threex
Version:
Game Extensions for three.js http://www.threejsgames.com/extensions/
1,571 lines (912 loc) • 37.7 kB
JavaScript
/*global THREE:false */
THREE.WebGLRenderer.LowLevelRenderer = function ( parameters ) {
parameters = parameters || {};
var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
_precision = parameters.precision !== undefined ? parameters.precision : 'highp',
_alpha = parameters.alpha !== undefined ? parameters.alpha : true,
_premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true,
_antialias = parameters.antialias !== undefined ? parameters.antialias : false,
_stencil = parameters.stencil !== undefined ? parameters.stencil : true,
_preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false,
_clearColor = parameters.clearColor !== undefined ? new THREE.Color( parameters.clearColor ) : new THREE.Color( 0x000000 ),
_clearAlpha = parameters.clearAlpha !== undefined ? parameters.clearAlpha : 0,
_autoScaleCubemaps = true;
this.devicePixelRatio = parameters.devicePixelRatio !== undefined ? parameters.devicePixelRatio : window.devicePixelRatio !== undefined ? window.devicePixelRatio : 1;
var _currentWidth = 0, _currentHeight = 0;
var _gl;
var _glExtensionTextureFloat;
var _glExtensionStandardDerivatives;
var _glExtensionTextureFilterAnisotropic;
var _glExtensionCompressedTextureS3TC;
initGL();
setDefaultGLState();
var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
var _supportsVertexTextures = ( _maxVertexTextures > 0 );
var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT );
var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT );
var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT );
var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT );
var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT );
var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT );
// clamp precision to maximum available
var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
if ( _precision === "highp" && ! highpAvailable ) {
if ( mediumpAvailable ) {
_precision = "mediump";
console.warn( "WebGLRenderer: highp not supported, using mediump" );
} else {
_precision = "lowp";
console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" );
}
}
if ( _precision === "mediump" && ! mediumpAvailable ) {
_precision = "lowp";
console.warn( "WebGLRenderer: mediump not supported, using lowp" );
}
var _enabledAttributes = {},
_oldBlending,
_oldBlendEquation,
_oldBlendSrc,
_oldBlendDst,
_oldDoubleSided = -1,
_oldFlipSided = -1,
_oldDepthTest = -1,
_oldDepthWrite = -1,
_oldLineWidth = -1,
_viewportX = 0,
_viewportY = 0,
_viewportWidth = 0,
_viewportHeight = 0,
// GL state cache
_oldPolygonOffset = null,
_oldPolygonOffsetFactor = null,
_oldPolygonOffsetUnits = null,
_currentFramebuffer = null;
function initGL () {
try {
if ( ! ( _gl = _canvas.getContext( 'experimental-webgl', { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer } ) ) ) {
throw 'Error creating WebGL context.';
}
} catch ( error ) {
console.error( error );
}
_glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
_glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
_glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) ||
_gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) ||
_gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
_glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
_gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
if ( ! _glExtensionTextureFloat ) {
console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
}
if ( ! _glExtensionStandardDerivatives ) {
console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
}
if ( ! _glExtensionTextureFilterAnisotropic ) {
console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
}
if ( ! _glExtensionCompressedTextureS3TC ) {
console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
}
if ( _gl.getShaderPrecisionFormat === undefined ) {
_gl.getShaderPrecisionFormat = function() {
return {
"rangeMin" : 1,
"rangeMax" : 1,
"precision" : 1
};
}
}
}
function setDefaultGLState () {
_gl.clearColor( 0, 0, 0, 1 );
_gl.clearDepth( 1 );
_gl.clearStencil( 0 );
_gl.enable( _gl.DEPTH_TEST );
_gl.depthFunc( _gl.LEQUAL );
_gl.frontFace( _gl.CCW );
_gl.cullFace( _gl.BACK );
_gl.enable( _gl.CULL_FACE );
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
}
// Fallback filters for non-power-of-2 textures
function filterFallback ( f ) {
if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) {
return _gl.NEAREST;
}
return _gl.LINEAR;
}
function getContext() {
return _gl;
}
function getDomElement(){
return _canvas;
}
function getPrecision() {
return _precision;
}
function getCurrentWidth(){
return _currentWidth;
}
function getCurrentHeight(){
return _currentHeight;
}
function supportsVertexTextures() {
return _supportsVertexTextures;
}
function supportsFloatTextures() {
return _glExtensionTextureFloat;
}
function supportsStandardDerivatives() {
return _glExtensionStandardDerivatives;
}
function supportsCompressedTextureS3TC() {
return _glExtensionCompressedTextureS3TC;
}
function getMaxAnisotropy() {
return _maxAnisotropy;
}
function setSize( width, height ) {
_canvas.width = width;
_canvas.height = height;
setViewport( 0, 0, _canvas.width, _canvas.height );
}
function setViewport( x, y, width, height ) {
_viewportX = x !== undefined ? x : 0;
_viewportY = y !== undefined ? y : 0;
_viewportWidth = width !== undefined ? width : _canvas.width;
_viewportHeight = height !== undefined ? height : _canvas.height;
_gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
}
function setScissor( x, y, width, height ) {
_gl.scissor( x, y, width, height );
}
function enableScissorTest( enable ) {
enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST );
}
// Clearing
function setClearColorHex( hex, alpha ) {
_clearColor.setHex( hex );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
}
function setClearColor( color, alpha ) {
_clearColor.copy( color );
_clearAlpha = alpha;
_gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
}
function getClearColor() {
return _clearColor;
}
function getClearAlpha() {
return _clearAlpha;
}
function clear( color, depth, stencil ) {
var bits = 0;
if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT;
if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT;
if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT;
_gl.clear( bits );
}
function clearTarget( renderTarget, color, depth, stencil ) {
setRenderTarget( renderTarget );
clear( color, depth, stencil );
}
function deleteBuffer(buffer){
_gl.deleteBuffer(buffer);
}
function deleteTexture(texture){
_gl.deleteTexture( texture );
}
function deleteFramebuffer(Framebuffer){
_gl.deleteFramebuffer(Framebuffer);
}
function deleteRenderbuffer(RenderBuffer){
_gl.deleteRenderbuffer(RenderBuffer);
}
function deleteProgram(RenderBuffer){
_gl.deleteProgram(RenderBuffer);
}
function createBuffer(){
return _gl.createBuffer();
}
function setStaticArrayBuffer(buffer,data){
bindArrayBuffer( buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, data, _gl.STATIC_DRAW );
}
function setStaticIndexBuffer(buffer,data){
bindElementArrayBuffer( buffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, data, _gl.STATIC_DRAW );
}
function setDynamicArrayBuffer(buffer,data){
bindArrayBuffer( buffer );
_gl.bufferData( _gl.ARRAY_BUFFER, data, _gl.DYNAMIC_DRAW );
}
function setDynamicIndexBuffer(buffer,data){
bindElementArrayBuffer( buffer );
_gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, data, _gl.DYNAMIC_DRAW );
}
function drawTriangles(count){
_gl.drawArrays( _gl.TRIANGLES, 0, count );
}
function drawTriangleStrip(count){
_gl.drawArrays( _gl.TRIANGLE_STRIP, 0, count );
}
function drawLines(count){
_gl.drawArrays( _gl.LINES, 0, count );
}
function drawLineStrip(count){
_gl.drawArrays( _gl.LINE_STRIP, 0, count );
}
function drawPoints(count){
_gl.drawArrays( _gl.POINTS, 0, count );
}
function drawTriangleElements(buffer,count,offset){
bindElementArrayBuffer( buffer );
_gl.drawElements( _gl.TRIANGLES, count, _gl.UNSIGNED_SHORT, offset ); // 2 bytes per Uint16
}
function drawLineElements(buffer,count,offset){
bindElementArrayBuffer( buffer );
_gl.drawElements( _gl.LINES, count, _gl.UNSIGNED_SHORT, offset ); // 2 bytes per Uint16
}
var _boundBuffer;
function bindArrayBuffer(buffer){
if (_boundBuffer != buffer){
_gl.bindBuffer( _gl.ARRAY_BUFFER, buffer );
_boundBuffer = buffer;
}
}
function bindElementArrayBuffer(buffer){
if (_boundBuffer != buffer){
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, buffer );
_boundBuffer = buffer;
}
}
function enableAttribute( attribute ) {
if ( ! _enabledAttributes[ attribute ] ) {
_gl.enableVertexAttribArray( attribute );
_enabledAttributes[ attribute ] = true;
}
}
function disableAttributes() {
for ( var attribute in _enabledAttributes ) {
if ( _enabledAttributes[ attribute ] ) {
_gl.disableVertexAttribArray( attribute );
_enabledAttributes[ attribute ] = false;
}
}
}
function getAttribLocation( program, id ){
return _gl.getAttribLocation( program, id );
}
function setFloatAttribute(index,buffer,size,offset){
bindArrayBuffer( buffer );
enableAttribute( index );
_gl.vertexAttribPointer( index, size, _gl.FLOAT, false, 0, offset );
}
function getUniformLocation( program, id ){
return _gl.getUniformLocation( program, id );
}
function uniform1i(uniform,value){
_gl.uniform1i( uniform, value );
}
function uniform1f(uniform,value){
_gl.uniform1f( uniform, value );
}
function uniform2f(uniform,value1, value2){
_gl.uniform2f( uniform, value1, value2 );
}
function uniform3f(uniform, value1, value2, value3){
_gl.uniform3f( uniform, value1, value2, value3 );
}
function uniform4f(uniform, value1, value2, value3, value4){
_gl.uniform4f( uniform, value1, value2, value3, value4);
}
function uniform1iv(uniform,value){
_gl.uniform1iv( uniform, value );
}
function uniform2iv(uniform,value){
_gl.uniform2iv( uniform, value );
}
function uniform3iv(uniform,value){
_gl.uniform3iv( uniform, value );
}
function uniform1fv(uniform,value){
_gl.uniform1fv( uniform, value );
}
function uniform2fv(uniform,value){
_gl.uniform2fv( uniform, value );
}
function uniform3fv(uniform,value){
_gl.uniform3fv( uniform, value );
}
function uniform4fv(uniform,value){
_gl.uniform3fv( uniform, value );
}
function uniformMatrix3fv(location,value){
_gl.uniformMatrix3fv( location, false, value );
}
function uniformMatrix4fv(location,value){
_gl.uniformMatrix4fv( location, false, value );
}
function useProgram(program){
_gl.useProgram( program );
}
function setFaceCulling( cullFace, frontFaceDirection ) {
if ( cullFace === THREE.CullFaceNone ) {
_gl.disable( _gl.CULL_FACE );
} else {
if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) {
_gl.frontFace( _gl.CW );
} else {
_gl.frontFace( _gl.CCW );
}
if ( cullFace === THREE.CullFaceBack ) {
_gl.cullFace( _gl.BACK );
} else if ( cullFace === THREE.CullFaceFront ) {
_gl.cullFace( _gl.FRONT );
} else {
_gl.cullFace( _gl.FRONT_AND_BACK );
}
_gl.enable( _gl.CULL_FACE );
}
}
function setMaterialFaces( material ) {
var doubleSided = material.side === THREE.DoubleSide;
var flipSided = material.side === THREE.BackSide;
if ( _oldDoubleSided !== doubleSided ) {
if ( doubleSided ) {
_gl.disable( _gl.CULL_FACE );
} else {
_gl.enable( _gl.CULL_FACE );
}
_oldDoubleSided = doubleSided;
}
if ( _oldFlipSided !== flipSided ) {
if ( flipSided ) {
_gl.frontFace( _gl.CW );
} else {
_gl.frontFace( _gl.CCW );
}
_oldFlipSided = flipSided;
}
}
function setPolygonOffset ( polygonoffset, factor, units ) {
if ( _oldPolygonOffset !== polygonoffset ) {
if ( polygonoffset ) {
_gl.enable( _gl.POLYGON_OFFSET_FILL );
} else {
_gl.disable( _gl.POLYGON_OFFSET_FILL );
}
_oldPolygonOffset = polygonoffset;
}
if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) {
_gl.polygonOffset( factor, units );
_oldPolygonOffsetFactor = factor;
_oldPolygonOffsetUnits = units;
}
}
function setBlending( blending, blendEquation, blendSrc, blendDst ) {
if ( blending !== _oldBlending ) {
if ( blending === THREE.NoBlending ) {
_gl.disable( _gl.BLEND );
} else if ( blending === THREE.AdditiveBlending ) {
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE );
} else if ( blending === THREE.SubtractiveBlending ) {
// TODO: Find blendFuncSeparate() combination
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR );
} else if ( blending === THREE.MultiplyBlending ) {
// TODO: Find blendFuncSeparate() combination
_gl.enable( _gl.BLEND );
_gl.blendEquation( _gl.FUNC_ADD );
_gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR );
} else if ( blending === THREE.CustomBlending ) {
_gl.enable( _gl.BLEND );
} else {
_gl.enable( _gl.BLEND );
_gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD );
_gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA );
}
_oldBlending = blending;
}
if ( blending === THREE.CustomBlending ) {
if ( blendEquation !== _oldBlendEquation ) {
_gl.blendEquation( paramThreeToGL( blendEquation ) );
_oldBlendEquation = blendEquation;
}
if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) {
_gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) );
_oldBlendSrc = blendSrc;
_oldBlendDst = blendDst;
}
} else {
_oldBlendEquation = null;
_oldBlendSrc = null;
_oldBlendDst = null;
}
}
function setDepthTest( depthTest ) {
if ( _oldDepthTest !== depthTest ) {
if ( depthTest ) {
_gl.enable( _gl.DEPTH_TEST );
} else {
_gl.disable( _gl.DEPTH_TEST );
}
_oldDepthTest = depthTest;
}
}
function setDepthWrite( depthWrite ) {
if ( _oldDepthWrite !== depthWrite ) {
_gl.depthMask( depthWrite );
_oldDepthWrite = depthWrite;
}
}
function setTexture( texture, slot ) {
if ( texture.needsUpdate ) {
if ( ! texture.__webglInit ) {
texture.__webglInit = true;
//texture.addEventListener( 'dispose', onTextureDispose );
texture.__webglTexture = _gl.createTexture();
//_this.info.memory.textures ++;
}
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
var image = texture.image,
isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
glFormat = paramThreeToGL( texture.format ),
glType = paramThreeToGL( texture.type );
setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
var mipmap, mipmaps = texture.mipmaps;
if ( texture instanceof THREE.DataTexture ) {
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
texture.generateMipmaps = false;
} else {
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
}
} else if ( texture instanceof THREE.CompressedTexture ) {
// compressed textures can only use manually created mipmaps
// WebGL can't generate mipmaps for DDS textures
for( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
}
} else { // regular Texture (image, video, canvas)
// use manually created mipmaps if available
// if there are no manual mipmaps
// set 0 level mipmap and then use GL to generate other mipmap levels
if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
mipmap = mipmaps[ i ];
_gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
}
texture.generateMipmaps = false;
} else {
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
}
}
if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
texture.needsUpdate = false;
if ( texture.onUpdate ) texture.onUpdate();
} else {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
}
}
function setCubeTexture ( texture, slot ) {
if ( texture.image.length === 6 ) {
if ( texture.needsUpdate ) {
if ( ! texture.image.__webglTextureCube ) {
texture.image.__webglTextureCube = _gl.createTexture();
}
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
var isCompressed = texture instanceof THREE.CompressedTexture;
var cubeImage = [];
for ( var i = 0; i < 6; i ++ ) {
if ( _autoScaleCubemaps && ! isCompressed ) {
cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
} else {
cubeImage[ i ] = texture.image[ i ];
}
}
var image = cubeImage[ 0 ],
isImagePowerOfTwo = isPowerOfTwo( image.width ) && isPowerOfTwo( image.height ),
glFormat = paramThreeToGL( texture.format ),
glType = paramThreeToGL( texture.type );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo );
for ( var i = 0; i < 6; i ++ ) {
if ( isCompressed ) {
var mipmap, mipmaps = cubeImage[ i ].mipmaps;
for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
mipmap = mipmaps[ j ];
_gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
}
} else {
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
}
}
if ( texture.generateMipmaps && isImagePowerOfTwo ) {
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
}
texture.needsUpdate = false;
if ( texture.onUpdate ) texture.onUpdate();
} else {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube );
}
}
}
// Textures
function isPowerOfTwo ( value ) {
return ( value & ( value - 1 ) ) === 0;
}
function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
if ( isImagePowerOfTwo ) {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) );
} else {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) );
_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) );
}
if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
_gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
texture.__oldAnisotropy = texture.anisotropy;
}
}
}
function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
}
function setupRenderBuffer ( renderbuffer, renderTarget ) {
_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
/* For some reason this is not working. Defaulting to RGBA4.
} else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
*/
} else if( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer );
} else {
_gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height );
}
}
function setRenderTarget( renderTarget ) {
var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
//renderTarget.addEventListener( 'dispose', onRenderTargetDispose );
renderTarget.__webglTexture = _gl.createTexture();
//_this.info.memory.textures ++;
// Setup texture, create render and frame buffers
var isTargetPowerOfTwo = isPowerOfTwo( renderTarget.width ) && isPowerOfTwo( renderTarget.height ),
glFormat = paramThreeToGL( renderTarget.format ),
glType = paramThreeToGL( renderTarget.type );
if ( isCube ) {
renderTarget.__webglFramebuffer = [];
renderTarget.__webglRenderbuffer = [];
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo );
for ( var i = 0; i < 6; i ++ ) {
renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer();
renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer();
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i );
setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget );
}
if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
} else {
renderTarget.__webglFramebuffer = _gl.createFramebuffer();
if ( renderTarget.shareDepthFrom ) {
renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer;
} else {
renderTarget.__webglRenderbuffer = _gl.createRenderbuffer();
}
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo );
_gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null );
setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D );
if ( renderTarget.shareDepthFrom ) {
if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) {
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
} else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) {
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer );
}
} else {
setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget );
}
if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
}
// Release everything
if ( isCube ) {
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
} else {
_gl.bindTexture( _gl.TEXTURE_2D, null );
}
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
_gl.bindFramebuffer( _gl.FRAMEBUFFER, null );
}
var framebuffer, width, height, vx, vy;
if ( renderTarget ) {
if ( isCube ) {
framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ];
} else {
framebuffer = renderTarget.__webglFramebuffer;
}
width = renderTarget.width;
height = renderTarget.height;
vx = 0;
vy = 0;
} else {
framebuffer = null;
width = _viewportWidth;
height = _viewportHeight;
vx = _viewportX;
vy = _viewportY;
}
if ( framebuffer !== _currentFramebuffer ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.viewport( vx, vy, width, height );
_currentFramebuffer = framebuffer;
}
_currentWidth = width;
_currentHeight = height;
}
function clampToMaxSize ( image, maxSize ) {
if ( image.width <= maxSize && image.height <= maxSize ) {
return image;
}
// Warning: Scaling through the canvas will only work with images that use
// premultiplied alpha.
var maxDimension = Math.max( image.width, image.height );
var newWidth = Math.floor( image.width * maxSize / maxDimension );
var newHeight = Math.floor( image.height * maxSize / maxDimension );
var canvas = document.createElement( 'canvas' );
canvas.width = newWidth;
canvas.height = newHeight;
var ctx = canvas.getContext( "2d" );
ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
return canvas;
}
function updateRenderTargetMipmap ( renderTarget ) {
if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) {
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture );
_gl.generateMipmap( _gl.TEXTURE_CUBE_MAP );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null );
} else {
_gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture );
_gl.generateMipmap( _gl.TEXTURE_2D );
_gl.bindTexture( _gl.TEXTURE_2D, null );
}
}
function setCubeTextureDynamic ( texture, slot ) {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
}
// Map three.js constants to WebGL constants
function paramThreeToGL ( p ) {
if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
if ( p === THREE.NearestFilter ) return _gl.NEAREST;
if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST;
if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR;
if ( p === THREE.LinearFilter ) return _gl.LINEAR;
if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST;
if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR;
if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE;
if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4;
if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1;
if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5;
if ( p === THREE.ByteType ) return _gl.BYTE;
if ( p === THREE.ShortType ) return _gl.SHORT;
if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT;
if ( p === THREE.IntType ) return _gl.INT;
if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT;
if ( p === THREE.FloatType ) return _gl.FLOAT;
if ( p === THREE.AlphaFormat ) return _gl.ALPHA;
if ( p === THREE.RGBFormat ) return _gl.RGB;
if ( p === THREE.RGBAFormat ) return _gl.RGBA;
if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE;
if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA;
if ( p === THREE.AddEquation ) return _gl.FUNC_ADD;
if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT;
if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT;
if ( p === THREE.ZeroFactor ) return _gl.ZERO;
if ( p === THREE.OneFactor ) return _gl.ONE;
if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR;
if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR;
if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA;
if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA;
if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA;
if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA;
if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR;
if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
if ( _glExtensionCompressedTextureS3TC !== undefined ) {
if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
}
return 0;
}
function compileShader(vertexShader, fragmentShader){
var program = _gl.createProgram();
var glFragmentShader = getShader( "fragment", fragmentShader );
var glVertexShader = getShader( "vertex", vertexShader );
_gl.attachShader( program, glVertexShader );
_gl.attachShader( program, glFragmentShader );
_gl.linkProgram( program );
if ( !_gl.getProgramParameter( program, _gl.LINK_STATUS ) ) {
console.error( "Could not initialise shader\n" + "VALIDATE_STATUS: " + _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) + ", gl error [" + _gl.getError() + "]" );
}
// clean up
_gl.deleteShader( glFragmentShader );
_gl.deleteShader( glVertexShader );
return program;
}
function resetState(){
_oldBlending = -1;
_oldDepthTest = -1;
_oldDepthWrite = -1;
_oldDoubleSided = -1;
_oldFlipSided = -1;
}
function getShader ( type, string ) {
var shader;
if ( type === "fragment" ) {
shader = _gl.createShader( _gl.FRAGMENT_SHADER );
} else if ( type === "vertex" ) {
shader = _gl.createShader( _gl.VERTEX_SHADER );
}
_gl.shaderSource( shader, string );
_gl.compileShader( shader );
if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) {
console.error( _gl.getShaderInfoLog( shader ) );
console.error( addLineNumbers( string ) );
return null;
}
return shader;
}
function addLineNumbers ( string ) {
var chunks = string.split( "\n" );
for ( var i = 0, il = chunks.length; i < il; i ++ ) {
// Chrome reports shader errors on lines
// starting counting from 1
chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ];
}
return chunks.join( "\n" );
}
function setLineWidth ( width ) {
if ( width !== _oldLineWidth ) {
_gl.lineWidth( width );
_oldLineWidth = width;
}
}
return {
context: _gl,
autoScaleCubemaps: _autoScaleCubemaps,
supportsBoneTextures: _supportsBoneTextures,
precision: _precision,
maxVertexUniformVectors: _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ),
// Methods
getContext: getContext,
getDomElement: getDomElement,
getPrecision: getPrecision,
getCurrentWidth: getCurrentWidth,
getCurrentHeight: getCurrentHeight,
supportsVertexTextures: supportsVertexTextures,
supportsFloatTextures: supportsFloatTextures,
supportsStandardDerivatives: supportsStandardDerivatives,
supportsCompressedTextureS3TC: supportsCompressedTextureS3TC,
getMaxAnisotropy: getMaxAnisotropy,
setRenderTarget: setRenderTarget,
setSize: setSize,
setViewport: setViewport,
setScissor: setScissor,
enableScissorTest: enableScissorTest,
setClearColorHex: setClearColorHex,
setClearColor: setClearColor,
getClearColor: getClearColor,
getClearAlpha: getClearAlpha,
clear: clear,
clearTarget: clearTarget,
deleteBuffer: deleteBuffer,
deleteTexture: deleteTexture,
deleteFramebuffer: deleteFramebuffer,
deleteRenderbuffer: deleteRenderbuffer,
deleteProgram: deleteProgram,
createBuffer: createBuffer,
setStaticArrayBuffer: setStaticArrayBuffer,
setStaticIndexBuffer: setStaticIndexBuffer,
setDynamicArrayBuffer: setDynamicArrayBuffer,
setDynamicIndexBuffer: setDynamicIndexBuffer,
drawTriangles: drawTriangles,
drawTriangleStrip: drawTriangleStrip,
drawLines: drawLines,
drawLineStrip: drawLineStrip,
drawPoints: drawPoints,
drawTriangleElements: drawTriangleElements,
drawLineElements: drawLineElements,
bindArrayBuffer: bindArrayBuffer,
bindElementArrayBuffer: bindElementArrayBuffer,
enableAttribute: enableAttribute,
disableAttributes: disableAttributes,
getAttribLocation: getAttribLocation,
setFloatAttribute: setFloatAttribute,
getUniformLocation: getUniformLocation,
uniform1i: uniform1i,
uniform1f: uniform1f,
uniform2f: uniform2f,
uniform3f: uniform3f,
uniform4f: uniform4f,
uniform1iv: uniform1iv,
uniform2iv: uniform2iv,
uniform3iv: uniform3iv,
uniform1fv: uniform1fv,
uniform2fv: uniform2fv,
uniform3fv: uniform3fv,
uniform4fv: uniform4fv,
uniformMatrix3fv: uniformMatrix3fv,
uniformMatrix4fv: uniformMatrix4fv,
useProgram: useProgram,
compileShader: compileShader,
setFaceCulling: setFaceCulling,
setMaterialFaces: setMaterialFaces,
setPolygonOffset: setPolygonOffset,
setBlending: setBlending,
setDepthTest: setDepthTest,
setDepthWrite: setDepthWrite,
setTexture: setTexture,
setCubeTexture: setCubeTexture,
updateRenderTargetMipmap: updateRenderTargetMipmap,
setCubeTextureDynamic: setCubeTextureDynamic,
paramThreeToGL: paramThreeToGL,
setLineWidth: setLineWidth,
resetState: resetState
}
};