kopia lustrzana https://github.com/OpenDroneMap/WebODM
352 wiersze
11 KiB
JavaScript
352 wiersze
11 KiB
JavaScript
'use strict';
|
|
var Notify = require( 'osg/notify' );
|
|
var MACROUTILS = require( 'osg/Utils' );
|
|
var GLObject = require( 'osg/GLObject' );
|
|
var StateAttribute = require( 'osg/StateAttribute' );
|
|
var Timer = require( 'osg/Timer' );
|
|
var WebglCaps = require( 'osg/WebGLCaps' );
|
|
|
|
/**
|
|
* FrameBufferObject manage fbo / rtt
|
|
* @class FrameBufferObject
|
|
*/
|
|
var FrameBufferObject = function () {
|
|
|
|
GLObject.call( this );
|
|
StateAttribute.call( this );
|
|
this._fbo = undefined;
|
|
this._rbo = undefined;
|
|
this._attachments = [];
|
|
this._dirty = true;
|
|
|
|
};
|
|
|
|
FrameBufferObject.COLOR_ATTACHMENT0 = 0x8CE0;
|
|
FrameBufferObject.DEPTH_ATTACHMENT = 0x8D00;
|
|
FrameBufferObject.DEPTH_COMPONENT16 = 0x81A5;
|
|
// static cache of glFrameBuffer flagged for deletion, which will actually
|
|
// be deleted in the correct GL context.
|
|
FrameBufferObject._sDeletedGLFrameBufferCache = new window.Map();
|
|
|
|
// static method to delete FrameBuffers
|
|
FrameBufferObject.deleteGLFrameBuffer = function ( gl, fb ) {
|
|
|
|
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) )
|
|
FrameBufferObject._sDeletedGLFrameBufferCache.set( gl, [] );
|
|
|
|
FrameBufferObject._sDeletedGLFrameBufferCache.get( gl ).push( fb );
|
|
};
|
|
|
|
// static method to flush all the cached glFrameBuffers which need to be deleted in the GL context specified
|
|
FrameBufferObject.flushDeletedGLFrameBuffers = function ( gl, availableTime ) {
|
|
|
|
// if no time available don't try to flush objects.
|
|
if ( availableTime <= 0.0 ) return availableTime;
|
|
|
|
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) ) return availableTime;
|
|
|
|
var elapsedTime = 0.0;
|
|
var beginTime = Timer.instance().tick();
|
|
var deleteList = FrameBufferObject._sDeletedGLFrameBufferCache.get( gl );
|
|
var numBuffers = deleteList.length;
|
|
|
|
for ( var i = numBuffers - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
|
gl.deleteFramebuffer( deleteList[ i ] );
|
|
deleteList.splice( i, 1 );
|
|
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
|
}
|
|
|
|
return availableTime - elapsedTime;
|
|
};
|
|
|
|
FrameBufferObject.flushAllDeletedGLFrameBuffers = function ( gl ) {
|
|
|
|
if ( !FrameBufferObject._sDeletedGLFrameBufferCache.has( gl ) ) return;
|
|
|
|
var deleteList = FrameBufferObject._sDeletedGLFrameBufferCache.get( gl );
|
|
var numBuffers = deleteList.length;
|
|
|
|
for ( var i = numBuffers - 1; i >= 0; i-- ) {
|
|
gl.deleteFramebuffer( deleteList[ i ] );
|
|
deleteList.splice( i, 1 );
|
|
}
|
|
};
|
|
|
|
|
|
// static cache of glRenderBuffer flagged for deletion, which will actually
|
|
// be deleted in the correct GL context.
|
|
FrameBufferObject._sDeletedGLRenderBufferCache = new window.Map();
|
|
|
|
// static method to delete RenderBuffers
|
|
FrameBufferObject.deleteGLRenderBuffer = function ( gl, fb ) {
|
|
|
|
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) )
|
|
FrameBufferObject._sDeletedGLRenderBufferCache.set( gl, [] );
|
|
|
|
FrameBufferObject._sDeletedGLRenderBufferCache.get( gl ).push( fb );
|
|
};
|
|
|
|
|
|
// static method to flush all the cached glRenderBuffers which need to be deleted in the GL context specified
|
|
FrameBufferObject.flushDeletedGLRenderBuffers = function ( gl, availableTime ) {
|
|
|
|
// if no time available don't try to flush objects.
|
|
if ( availableTime <= 0.0 ) return availableTime;
|
|
|
|
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) ) return availableTime;
|
|
|
|
var elapsedTime = 0.0;
|
|
var beginTime = Timer.instance().tick();
|
|
var deleteList = FrameBufferObject._sDeletedGLRenderBufferCache.get( gl );
|
|
var numBuffers = deleteList.length;
|
|
|
|
for ( var i = numBuffers - 1; i >= 0 && elapsedTime < availableTime; i-- ) {
|
|
gl.deleteRenderbuffer( deleteList[ i ] );
|
|
deleteList.splice( i, 1 );
|
|
elapsedTime = Timer.instance().deltaS( beginTime, Timer.instance().tick() );
|
|
}
|
|
|
|
return availableTime - elapsedTime;
|
|
};
|
|
|
|
FrameBufferObject.flushAllDeletedGLRenderBuffers = function ( gl ) {
|
|
|
|
if ( !FrameBufferObject._sDeletedGLRenderBufferCache.has( gl ) ) return;
|
|
|
|
var deleteList = FrameBufferObject._sDeletedGLRenderBufferCache.get( gl );
|
|
var numBuffers = deleteList.length;
|
|
|
|
for ( var i = numBuffers - 1; i >= 0; i-- ) {
|
|
gl.deleteRenderbuffer( deleteList[ i ] );
|
|
deleteList.splice( i, 1 );
|
|
}
|
|
};
|
|
|
|
/** @lends FrameBufferObject.prototype */
|
|
FrameBufferObject.prototype = MACROUTILS.objectInherit( GLObject.prototype, MACROUTILS.objectInherit( StateAttribute.prototype, {
|
|
|
|
attributeType: 'FrameBufferObject',
|
|
|
|
cloneType: function () {
|
|
return new FrameBufferObject();
|
|
},
|
|
|
|
dirty: function () {
|
|
this._dirty = true;
|
|
},
|
|
|
|
isDirty: function () {
|
|
return this._dirty;
|
|
},
|
|
|
|
setAttachment: function ( attachment ) {
|
|
this._attachments.push( attachment );
|
|
},
|
|
|
|
releaseGLObjects: function () {
|
|
|
|
if ( this._fbo !== undefined && this._gl !== undefined ) {
|
|
FrameBufferObject.deleteGLFrameBuffer( this._gl, this._fbo );
|
|
}
|
|
this._fbo = undefined;
|
|
|
|
if ( this._rbo !== undefined && this._gl !== undefined ) {
|
|
FrameBufferObject.deleteGLRenderBuffer( this._gl, this._rbo );
|
|
}
|
|
this._rbo = undefined;
|
|
|
|
},
|
|
|
|
_reportFrameBufferError: function ( code ) {
|
|
switch ( code ) {
|
|
case 0x8CD6:
|
|
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_ATTACHMENT' );
|
|
break;
|
|
case 0x8CD7:
|
|
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT' );
|
|
break;
|
|
case 0x8CD9:
|
|
Notify.debug( 'FRAMEBUFFER_INCOMPLETE_DIMENSIONS' );
|
|
break;
|
|
case 0x8CDD:
|
|
Notify.debug( 'FRAMEBUFFER_UNSUPPORTED' );
|
|
break;
|
|
default:
|
|
Notify.debug( 'FRAMEBUFFER unknown error ' + code.toString( 16 ) );
|
|
}
|
|
},
|
|
|
|
reset: function () {
|
|
this.releaseGLObjects();
|
|
this._attachments = [];
|
|
},
|
|
|
|
getFrameBufferObject: function () {
|
|
return this._fbo;
|
|
},
|
|
|
|
createFrameBufferObject: function ( state ) {
|
|
this.setGraphicContext( state.getGraphicContext() );
|
|
this._fbo = this._gl.createFramebuffer();
|
|
},
|
|
|
|
createRenderBuffer: function ( format, width, height ) {
|
|
var gl = this._gl;
|
|
var renderBuffer = gl.createRenderbuffer();
|
|
gl.bindRenderbuffer( gl.RENDERBUFFER, renderBuffer );
|
|
gl.renderbufferStorage( gl.RENDERBUFFER, format, width, height );
|
|
|
|
return renderBuffer;
|
|
},
|
|
|
|
framebufferRenderBuffer: function ( attachment, renderBuffer ) {
|
|
|
|
var gl = this._gl;
|
|
gl.bindRenderbuffer( gl.RENDERBUFFER, renderBuffer );
|
|
gl.framebufferRenderbuffer( gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderBuffer );
|
|
|
|
/* develblock:start */
|
|
// only visible with webgl-insector enabled
|
|
if ( gl.rawgl !== undefined ) {
|
|
Notify.log( 'FBO: renderBuffer: ' + this._fbo.trackedObject.defaultName );
|
|
}
|
|
/* develblock:end */
|
|
},
|
|
|
|
framebufferTexture2D: function ( state, attachment, textureTarget, texture ) {
|
|
|
|
var gl = this._gl;
|
|
|
|
// apply on unit 1 to init it
|
|
// make sure we do bind it whatever state stack
|
|
// texture is cached
|
|
state.applyTextureAttribute( 1, texture );
|
|
|
|
if ( texture.isDirty() || !texture.getTextureObject() ) {
|
|
// image wasn't ready, texture not allocated due to lack of gpu MEM
|
|
return false;
|
|
}
|
|
|
|
gl.framebufferTexture2D( gl.FRAMEBUFFER, attachment, textureTarget, texture.getTextureObject().id(), 0 );
|
|
|
|
/* develblock:start */
|
|
// only visible with webgl-insector enabled
|
|
// allow trace debug (fb<->texture link)
|
|
if ( gl.rawgl !== undefined ) {
|
|
Notify.log( 'FBO: texture: ' + texture.getName() + ' : ' + texture.getTextureObject().id().trackedObject.defaultName + ' fbo: ' + this._fbo.trackedObject.defaultName );
|
|
}
|
|
/* develblock:end */
|
|
|
|
return true;
|
|
},
|
|
|
|
bindFrameBufferObject: function () {
|
|
var gl = this._gl;
|
|
gl.bindFramebuffer( gl.FRAMEBUFFER, this._fbo );
|
|
},
|
|
|
|
checkStatus: function () {
|
|
|
|
var gl = this._gl;
|
|
var status = gl.checkFramebufferStatus( gl.FRAMEBUFFER );
|
|
if ( status !== 0x8CD5 ) {
|
|
this._reportFrameBufferError( status );
|
|
}
|
|
|
|
},
|
|
|
|
_checkAllowedSize: function ( w, h ) {
|
|
|
|
var maxSize = WebglCaps.instance().getWebGLParameter( 'MAX_RENDERBUFFER_SIZE' );
|
|
|
|
if ( w === 0 || h === 0 || h > maxSize || w > maxSize ) {
|
|
Notify.error( 'width (' + w + ') or height (' + w + ') makes frame buffer not bindable. Max RenderBuffer is "' + maxSize + '"' );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
apply: function ( state ) {
|
|
|
|
if ( !this._gl ) this.setGraphicContext( state.getGraphicContext() );
|
|
var gl = this._gl;
|
|
|
|
var attachments = this._attachments;
|
|
|
|
// if the fbo is created manually, we want to just bind it
|
|
if ( attachments.length > 0 || this._fbo ) {
|
|
|
|
if ( this.isDirty() ) {
|
|
|
|
if ( !this._fbo )
|
|
this.createFrameBufferObject( state );
|
|
|
|
this.bindFrameBufferObject();
|
|
|
|
var hasRenderBuffer = false;
|
|
|
|
for ( var i = 0, l = attachments.length; i < l; ++i ) {
|
|
|
|
var attachment = attachments[ i ];
|
|
|
|
// render buffer
|
|
if ( !attachment.texture ) {
|
|
|
|
if ( !this._checkAllowedSize( attachment.width, attachment.height ) ) {
|
|
this.releaseGLObjects();
|
|
return;
|
|
}
|
|
|
|
this._rbo = this.createRenderBuffer( attachment.format, attachment.width, attachment.height );
|
|
this.framebufferRenderBuffer( attachment.attachment, this._rbo );
|
|
hasRenderBuffer = true;
|
|
|
|
} else {
|
|
|
|
// use texture
|
|
var texture = attachment.texture;
|
|
|
|
if ( !this._checkAllowedSize( texture.getWidth(), texture.getHeight() ) ) {
|
|
this.releaseGLObjects();
|
|
return;
|
|
}
|
|
|
|
if ( !this.framebufferTexture2D( state, attachment.attachment, attachment.textureTarget, texture ) ) {
|
|
this.releaseGLObjects();
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.checkStatus();
|
|
|
|
// set it to null only if used renderbuffer
|
|
if ( hasRenderBuffer )
|
|
gl.bindRenderbuffer( gl.RENDERBUFFER, null );
|
|
|
|
this._dirty = false;
|
|
|
|
} else {
|
|
|
|
gl.bindFramebuffer( gl.FRAMEBUFFER, this._fbo );
|
|
|
|
if ( Notify.reportWebGLError === true )
|
|
this.checkStatus();
|
|
|
|
}
|
|
|
|
} else {
|
|
gl.bindFramebuffer( gl.FRAMEBUFFER, null );
|
|
}
|
|
}
|
|
} ) );
|
|
|
|
|
|
module.exports = FrameBufferObject;
|