module Webglimpse { export interface Buffer { bind ( gl , target ) ; unbind ( gl , target ) ; dispose ( ) ; } export interface DynamicBuffer extends Buffer { setData ( newData ) ; } export function newStaticBuffer ( data ) { return new StaticBufferImpl ( data ) ; } export function newDynamicBuffer ( data = new Float32Array ( 0 ) ) { return new DynamicBufferImpl ( data ) ; } class BufferEntry { gl : WebGLRenderingContext ; buffer : WebGLBuffer ; capacity : number = 0 ; marker : number = null ; constructor ( gl , buffer ) { this . gl = gl ; this . buffer = buffer ; } } class AbstractBuffer implements Buffer { private buffers : StringMap < BufferEntry > = { } ; private currentMarker : number = 0 ; init ( gl , target ) { throw new Error ( 'Method is abstract' ) ; } update ( gl , target , capacity ) { throw new Error ( 'Method is abstract' ) ; } setDirty ( ) { this . currentMarker ++ ; } bind ( gl , target ) { var glId = getObjectId ( gl ) ; if ( this . buffers [ glId ] === undefined ) { var buffer = gl . createBuffer ( ) ; if ( ! hasval ( buffer ) ) throw new Error ( 'Failed to create buffer' ) ; this . buffers [ glId ] = new BufferEntry ( gl , buffer ) ; gl . bindBuffer ( target , this . buffers [ glId ] . buffer ) ; this . buffers [ glId ] . capacity = this . init ( gl , target ) ; this . buffers [ glId ] . marker = this . currentMarker ; } else if ( this . buffers [ glId ] . marker !== this . currentMarker ) { gl . bindBuffer ( target , this . buffers [ glId ] . buffer ) ; this . buffers [ glId ] . capacity = this . update ( gl , target , this . buffers [ glId ] . capacity ) ; this . buffers [ glId ] . marker = this . currentMarker ; } else { gl . bindBuffer ( target , this . buffers [ glId ] . buffer ) ; } } unbind ( gl , target ) { gl . bindBuffer ( target , null ) ; } dispose ( ) { for ( var glid in this . buffers ) { if ( this . buffers . hasOwnProperty ( glid ) ) { var en = this . buffers [ glid ] ; en . gl . deleteBuffer ( en . buffer ) ; } } this . buffers = { } ; } } class StaticBufferImpl extends AbstractBuffer { private _data : ArrayBuffer ; constructor ( data ) { super ( ) ; this . _data = data ; } init ( gl , target ) { gl . bufferData ( target , this . _data , GL . STATIC_DRAW ) ; return this . _data . byteLength ; } update ( gl , target , capacity ) { throw new Error ( 'This buffer is static and should never need to be updated' ) ; } } class DynamicBufferImpl extends AbstractBuffer implements DynamicBuffer { private _data : ArrayBuffer ; constructor ( data ) { super ( ) ; this . _data = data ; } setData ( data ) { this . _data = data ; this . setDirty ( ) ; } init ( gl , target ) { gl . bufferData ( target , this . _data , GL . DYNAMIC_DRAW ) ; return this . _data . byteLength ; } update ( gl , target , capacity ) { if ( this . _data . byteLength <= capacity ) { gl . bufferSubData ( target , 0 , this . _data ) ; return capacity ; } else { gl . bufferData ( target , this . _data , GL . DYNAMIC_DRAW ) ; return this . _data . byteLength ; } } } }