256 lines
6.5 KiB
JavaScript
256 lines
6.5 KiB
JavaScript
|
var check = require('./util/check')
|
||
|
var values = require('./util/values')
|
||
|
|
||
|
var GL_RENDERBUFFER = 0x8D41
|
||
|
|
||
|
var GL_RGBA4 = 0x8056
|
||
|
var GL_RGB5_A1 = 0x8057
|
||
|
var GL_RGB565 = 0x8D62
|
||
|
var GL_DEPTH_COMPONENT16 = 0x81A5
|
||
|
var GL_STENCIL_INDEX8 = 0x8D48
|
||
|
var GL_DEPTH_STENCIL = 0x84F9
|
||
|
|
||
|
var GL_SRGB8_ALPHA8_EXT = 0x8C43
|
||
|
|
||
|
var GL_RGBA32F_EXT = 0x8814
|
||
|
|
||
|
var GL_RGBA16F_EXT = 0x881A
|
||
|
var GL_RGB16F_EXT = 0x881B
|
||
|
|
||
|
var FORMAT_SIZES = []
|
||
|
|
||
|
FORMAT_SIZES[GL_RGBA4] = 2
|
||
|
FORMAT_SIZES[GL_RGB5_A1] = 2
|
||
|
FORMAT_SIZES[GL_RGB565] = 2
|
||
|
|
||
|
FORMAT_SIZES[GL_DEPTH_COMPONENT16] = 2
|
||
|
FORMAT_SIZES[GL_STENCIL_INDEX8] = 1
|
||
|
FORMAT_SIZES[GL_DEPTH_STENCIL] = 4
|
||
|
|
||
|
FORMAT_SIZES[GL_SRGB8_ALPHA8_EXT] = 4
|
||
|
FORMAT_SIZES[GL_RGBA32F_EXT] = 16
|
||
|
FORMAT_SIZES[GL_RGBA16F_EXT] = 8
|
||
|
FORMAT_SIZES[GL_RGB16F_EXT] = 6
|
||
|
|
||
|
function getRenderbufferSize (format, width, height) {
|
||
|
return FORMAT_SIZES[format] * width * height
|
||
|
}
|
||
|
|
||
|
module.exports = function (gl, extensions, limits, stats, config) {
|
||
|
var formatTypes = {
|
||
|
'rgba4': GL_RGBA4,
|
||
|
'rgb565': GL_RGB565,
|
||
|
'rgb5 a1': GL_RGB5_A1,
|
||
|
'depth': GL_DEPTH_COMPONENT16,
|
||
|
'stencil': GL_STENCIL_INDEX8,
|
||
|
'depth stencil': GL_DEPTH_STENCIL
|
||
|
}
|
||
|
|
||
|
if (extensions.ext_srgb) {
|
||
|
formatTypes['srgba'] = GL_SRGB8_ALPHA8_EXT
|
||
|
}
|
||
|
|
||
|
if (extensions.ext_color_buffer_half_float) {
|
||
|
formatTypes['rgba16f'] = GL_RGBA16F_EXT
|
||
|
formatTypes['rgb16f'] = GL_RGB16F_EXT
|
||
|
}
|
||
|
|
||
|
if (extensions.webgl_color_buffer_float) {
|
||
|
formatTypes['rgba32f'] = GL_RGBA32F_EXT
|
||
|
}
|
||
|
|
||
|
var formatTypesInvert = []
|
||
|
Object.keys(formatTypes).forEach(function (key) {
|
||
|
var val = formatTypes[key]
|
||
|
formatTypesInvert[val] = key
|
||
|
})
|
||
|
|
||
|
var renderbufferCount = 0
|
||
|
var renderbufferSet = {}
|
||
|
|
||
|
function REGLRenderbuffer (renderbuffer) {
|
||
|
this.id = renderbufferCount++
|
||
|
this.refCount = 1
|
||
|
|
||
|
this.renderbuffer = renderbuffer
|
||
|
|
||
|
this.format = GL_RGBA4
|
||
|
this.width = 0
|
||
|
this.height = 0
|
||
|
|
||
|
if (config.profile) {
|
||
|
this.stats = { size: 0 }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
REGLRenderbuffer.prototype.decRef = function () {
|
||
|
if (--this.refCount <= 0) {
|
||
|
destroy(this)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function destroy (rb) {
|
||
|
var handle = rb.renderbuffer
|
||
|
check(handle, 'must not double destroy renderbuffer')
|
||
|
gl.bindRenderbuffer(GL_RENDERBUFFER, null)
|
||
|
gl.deleteRenderbuffer(handle)
|
||
|
rb.renderbuffer = null
|
||
|
rb.refCount = 0
|
||
|
delete renderbufferSet[rb.id]
|
||
|
stats.renderbufferCount--
|
||
|
}
|
||
|
|
||
|
function createRenderbuffer (a, b) {
|
||
|
var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer())
|
||
|
renderbufferSet[renderbuffer.id] = renderbuffer
|
||
|
stats.renderbufferCount++
|
||
|
|
||
|
function reglRenderbuffer (a, b) {
|
||
|
var w = 0
|
||
|
var h = 0
|
||
|
var format = GL_RGBA4
|
||
|
|
||
|
if (typeof a === 'object' && a) {
|
||
|
var options = a
|
||
|
if ('shape' in options) {
|
||
|
var shape = options.shape
|
||
|
check(Array.isArray(shape) && shape.length >= 2,
|
||
|
'invalid renderbuffer shape')
|
||
|
w = shape[0] | 0
|
||
|
h = shape[1] | 0
|
||
|
} else {
|
||
|
if ('radius' in options) {
|
||
|
w = h = options.radius | 0
|
||
|
}
|
||
|
if ('width' in options) {
|
||
|
w = options.width | 0
|
||
|
}
|
||
|
if ('height' in options) {
|
||
|
h = options.height | 0
|
||
|
}
|
||
|
}
|
||
|
if ('format' in options) {
|
||
|
check.parameter(options.format, formatTypes,
|
||
|
'invalid renderbuffer format')
|
||
|
format = formatTypes[options.format]
|
||
|
}
|
||
|
} else if (typeof a === 'number') {
|
||
|
w = a | 0
|
||
|
if (typeof b === 'number') {
|
||
|
h = b | 0
|
||
|
} else {
|
||
|
h = w
|
||
|
}
|
||
|
} else if (!a) {
|
||
|
w = h = 1
|
||
|
} else {
|
||
|
check.raise('invalid arguments to renderbuffer constructor')
|
||
|
}
|
||
|
|
||
|
// check shape
|
||
|
check(
|
||
|
w > 0 && h > 0 &&
|
||
|
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize,
|
||
|
'invalid renderbuffer size')
|
||
|
|
||
|
if (w === renderbuffer.width &&
|
||
|
h === renderbuffer.height &&
|
||
|
format === renderbuffer.format) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
reglRenderbuffer.width = renderbuffer.width = w
|
||
|
reglRenderbuffer.height = renderbuffer.height = h
|
||
|
renderbuffer.format = format
|
||
|
|
||
|
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer)
|
||
|
gl.renderbufferStorage(GL_RENDERBUFFER, format, w, h)
|
||
|
|
||
|
check(
|
||
|
gl.getError() === 0,
|
||
|
'invalid render buffer format')
|
||
|
|
||
|
if (config.profile) {
|
||
|
renderbuffer.stats.size = getRenderbufferSize(renderbuffer.format, renderbuffer.width, renderbuffer.height)
|
||
|
}
|
||
|
reglRenderbuffer.format = formatTypesInvert[renderbuffer.format]
|
||
|
|
||
|
return reglRenderbuffer
|
||
|
}
|
||
|
|
||
|
function resize (w_, h_) {
|
||
|
var w = w_ | 0
|
||
|
var h = (h_ | 0) || w
|
||
|
|
||
|
if (w === renderbuffer.width && h === renderbuffer.height) {
|
||
|
return reglRenderbuffer
|
||
|
}
|
||
|
|
||
|
// check shape
|
||
|
check(
|
||
|
w > 0 && h > 0 &&
|
||
|
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize,
|
||
|
'invalid renderbuffer size')
|
||
|
|
||
|
reglRenderbuffer.width = renderbuffer.width = w
|
||
|
reglRenderbuffer.height = renderbuffer.height = h
|
||
|
|
||
|
gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer.renderbuffer)
|
||
|
gl.renderbufferStorage(GL_RENDERBUFFER, renderbuffer.format, w, h)
|
||
|
|
||
|
check(
|
||
|
gl.getError() === 0,
|
||
|
'invalid render buffer format')
|
||
|
|
||
|
// also, recompute size.
|
||
|
if (config.profile) {
|
||
|
renderbuffer.stats.size = getRenderbufferSize(
|
||
|
renderbuffer.format, renderbuffer.width, renderbuffer.height)
|
||
|
}
|
||
|
|
||
|
return reglRenderbuffer
|
||
|
}
|
||
|
|
||
|
reglRenderbuffer(a, b)
|
||
|
|
||
|
reglRenderbuffer.resize = resize
|
||
|
reglRenderbuffer._reglType = 'renderbuffer'
|
||
|
reglRenderbuffer._renderbuffer = renderbuffer
|
||
|
if (config.profile) {
|
||
|
reglRenderbuffer.stats = renderbuffer.stats
|
||
|
}
|
||
|
reglRenderbuffer.destroy = function () {
|
||
|
renderbuffer.decRef()
|
||
|
}
|
||
|
|
||
|
return reglRenderbuffer
|
||
|
}
|
||
|
|
||
|
if (config.profile) {
|
||
|
stats.getTotalRenderbufferSize = function () {
|
||
|
var total = 0
|
||
|
Object.keys(renderbufferSet).forEach(function (key) {
|
||
|
total += renderbufferSet[key].stats.size
|
||
|
})
|
||
|
return total
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function restoreRenderbuffers () {
|
||
|
values(renderbufferSet).forEach(function (rb) {
|
||
|
rb.renderbuffer = gl.createRenderbuffer()
|
||
|
gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer)
|
||
|
gl.renderbufferStorage(GL_RENDERBUFFER, rb.format, rb.width, rb.height)
|
||
|
})
|
||
|
gl.bindRenderbuffer(GL_RENDERBUFFER, null)
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
create: createRenderbuffer,
|
||
|
clear: function () {
|
||
|
values(renderbufferSet).forEach(destroy)
|
||
|
},
|
||
|
restore: restoreRenderbuffers
|
||
|
}
|
||
|
}
|