Socket
Socket
Sign inDemoInstall

regl

Package Overview
Dependencies
0
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.8.0 to 0.9.0

compare/webgl_cube.html

62

CHANGES.md

@@ -5,6 +5,2 @@ # Release notes

* Optimize constructors/updates for renderbuffers and framebuffers
* Cubic frame buffer objects
* More test cases for framebuffers
* Implement a standard method for handling context creation errors

@@ -14,9 +10,17 @@ * Add a mechanism for managing webgl extensions

+ Allow users to disable extensions for testing/mocking
* Add a mechanism for users to specify minimum resource requirements (texture size, varying units, etc.)
* Performance monitoring hooks
* Cubic frame buffer objects
* Context loss handling
* Context loss
* Write comparison suite
* More performance monitoring hooks
+ Track currently used resource requirements
+ Output should be serializable -> works as input to constructor checks
* More validation
+ Should not be possible to write regl code that crashes on some systems
* Benchmark suite

@@ -26,21 +30,30 @@ + Dashboard for test cases and benchmarks

* A pretty printer for the generated code
* Documentation
+ All interface methods must be documented
+ Examples for all major features
+ Set up/quick start guides
+ Examples on codepen/requirebin/regl.party
+ Live coding videos on youtube
+ Talks? (what conferences can we present these results at?)
+ Core library modules need better comments
+ Work flow for development and testing needs documentation
* Testing
+ Instancing
+ Texture generation
+ Framebuffers
+ Element buffer rendering primitives
+ Float textures / framebuffers and their filtering modes
+ Constant attributes
+ Viewport change notifications
+ RAF/frame behavior
+ Complete coverage for all code generation pathways
+ Test weird invocation sequences
+ RAF/regl.frame behavior
+ Initialization pathways
+ General code coverage
* Build a website (preview at [regl.party](http://regl.party))
* Helper modules
+ A camera helper module to make getting started with 3D code easier
+ Debugging tools for inspecting the state of framebuffers, textures, buffers
* Recipe book/example set
+ Minecraft example
+ Globe
+ Tile based 2D rendering
+ Compound scene

@@ -50,5 +63,22 @@ + Shadow mapping

+ Turing patterns
+ Spring/cloth physics
+ Asset loading (obj, ply, etc.)
## Next
## 0.9.0
* Add performance monitoring hooks for commands. Now tracks draw call count, cpu time and gpu time (if disjoint timer extension supported).
* Performance monitoring hooks for commands can be enabled/disabled using the `profile` property.
* Finish API documentation for framebuffers
* Optimize constructors/updates for framebuffers
* More test cases for framebuffers
* Clean up renderbuffer constructor and improve test coverage
* Added `resize` method to textures, renderbuffers and framebuffers
* Added global performance monitoring hooks via `regl.stats`
* Rename `count` context variable to `tick`
* Remove `deltaTime` context variable
* Uniform validation fixes
* Texture construction fixes
* Improved test coverage for uniform variables
## 0.8.0

@@ -55,0 +85,0 @@

@@ -47,3 +47,3 @@ var check = require('./util/check')

module.exports = function wrapBufferState (gl) {
module.exports = function wrapBufferState (gl, stats) {
var bufferCount = 0

@@ -66,2 +66,6 @@ var bufferSet = {}

REGLBuffer.prototype.destroy = function () {
destroy(this)
}
var streamPool = []

@@ -166,7 +170,7 @@

function destroy (buffer) {
stats.bufferCount--
var handle = buffer.buffer
check(handle, 'buffer must not be deleted already')
if (gl.isBuffer(handle)) {
gl.deleteBuffer(handle)
}
gl.deleteBuffer(handle)
buffer.buffer = null

@@ -177,2 +181,4 @@ delete bufferSet[buffer.id]

function createBuffer (options, type, deferInit) {
stats.bufferCount++
var buffer = new REGLBuffer(type)

@@ -179,0 +185,0 @@ bufferSet[buffer.id] = buffer

var check = require('./util/check')
var isTypedArray = require('./util/is-typed-array')
var isNDArrayLike = require('./util/is-ndarray')
var values = require('./util/values')

@@ -24,3 +25,6 @@ var primTypes = require('./constants/primitives.json')

module.exports = function wrapElementsState (gl, extensions, bufferState) {
module.exports = function wrapElementsState (gl, extensions, bufferState, stats) {
var elementSet = {}
var elementCount = 0
var elementTypes = {

@@ -36,2 +40,4 @@ 'uint8': GL_UNSIGNED_BYTE,

function REGLElementBuffer (buffer) {
this.id = elementCount++
elementSet[this.id] = this
this.buffer = buffer

@@ -144,5 +150,15 @@ this.primType = GL_TRIANGLES

function destroyElements (elements) {
stats.elementsCount--
check(elements.buffer !== null, 'must not double destroy elements')
delete elementSet[elements.id]
elements.buffer.destroy()
elements.buffer = null
}
function createElements (options) {
var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true)
var elements = new REGLElementBuffer(buffer._buffer)
stats.elementsCount++

@@ -247,5 +263,3 @@ function reglElements (options) {

reglElements.destroy = function () {
check(elements.buffer !== null, 'must not double destroy elements')
buffer.destroy()
elements.buffer = null
destroyElements(elements)
}

@@ -266,4 +280,7 @@

return null
},
clear: function () {
values(elementSet).forEach(destroyElements)
}
}
}

@@ -24,2 +24,3 @@ module.exports = function createExtensionCache (gl) {

'ext_srgb',
'ext_disjoint_timer_query',

@@ -26,0 +27,0 @@ 'angle_instanced_arrays',

@@ -10,3 +10,2 @@ var check = require('./util/check')

var GL_TEXTURE_2D = 0x0DE1
var GL_TEXTURE_CUBE_MAP = 0x8513
var GL_TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515

@@ -19,9 +18,24 @@

var GL_UNSIGNED_BYTE = 0x1401
var GL_FLOAT = 0x1406
var GL_FRAMEBUFFER_COMPLETE = 0x8CD5
var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6
var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7
var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9
var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD
var GL_HALF_FLOAT_OES = 0x8D61
var GL_RGBA = 0x1908
var GL_ALPHA = 0x1906
var GL_RGB = 0x1907
var GL_LUMINANCE = 0x1909
var GL_LUMINANCE_ALPHA = 0x190A
var GL_DEPTH_COMPONENT = 0x1902
var colorTextureFormatEnums = [
GL_ALPHA,
GL_LUMINANCE,
GL_LUMINANCE_ALPHA,
GL_RGB,
GL_RGBA
]
var GL_RGBA4 = 0x8056

@@ -32,4 +46,2 @@ var GL_RGB5_A1 = 0x8057

var GL_STENCIL_INDEX8 = 0x8D48
var GL_DEPTH_COMPONENT = 0x1902
var GL_DEPTH_STENCIL = 0x84F9

@@ -44,8 +56,19 @@

var GL_FRAMEBUFFER_COMPLETE = 0x8CD5
var GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6
var GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7
var GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9
var GL_FRAMEBUFFER_UNSUPPORTED = 0x8CDD
var colorRenderbufferFormatEnums = [
GL_RGBA4,
GL_RGB5_A1,
GL_RGB565,
GL_SRGB8_ALPHA8_EXT,
GL_RGBA16F_EXT,
GL_RGB16F_EXT,
GL_RGBA32F_EXT
]
var statusCode = {}
statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment'
statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported'
module.exports = function wrapFBOState (

@@ -56,3 +79,4 @@ gl,

textureState,
renderbufferState) {
renderbufferState,
stats) {
var framebufferState = {

@@ -64,80 +88,41 @@ current: null,

var statusCode = {}
statusCode[GL_FRAMEBUFFER_COMPLETE] = 'complete'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = 'incomplete attachment'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = 'incomplete dimensions'
statusCode[GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = 'incomplete, missing attachment'
statusCode[GL_FRAMEBUFFER_UNSUPPORTED] = 'unsupported'
var colorTextureFormats = ['rgba']
var colorRenderbufferFormats = ['rgba4', 'rgb565', 'rgb5 a1']
var colorTextureFormats = {
'rgba': GL_RGBA
}
var colorRenderbufferFormats = {
'rgba4': GL_RGBA4,
'rgb565': GL_RGB565,
'rgb5 a1': GL_RGB5_A1
}
if (extensions.ext_srgb) {
colorRenderbufferFormats['srgba'] = GL_SRGB8_ALPHA8_EXT
colorRenderbufferFormats.push('srgba')
}
if (extensions.ext_color_buffer_half_float) {
colorRenderbufferFormats['rgba16f'] = GL_RGBA16F_EXT
colorRenderbufferFormats['rgb16f'] = GL_RGB16F_EXT
colorRenderbufferFormats.push('rgba16f', 'rgb16f')
}
if (extensions.webgl_color_buffer_float) {
colorRenderbufferFormats['rgba32f'] = GL_RGBA32F_EXT
colorRenderbufferFormats.push('rgba32f')
}
var depthRenderbufferFormatEnums = [GL_DEPTH_COMPONENT16]
var stencilRenderbufferFormatEnums = [GL_STENCIL_INDEX8]
var depthStencilRenderbufferFormatEnums = [GL_DEPTH_STENCIL]
var depthTextureFormatEnums = []
var stencilTextureFormatEnums = []
var depthStencilTextureFormatEnums = []
if (extensions.webgl_depth_texture) {
depthTextureFormatEnums.push(GL_DEPTH_COMPONENT)
depthStencilTextureFormatEnums.push(GL_DEPTH_STENCIL)
}
var colorFormats = extend(extend({},
colorTextureFormats),
colorRenderbufferFormats)
var colorTextureFormatEnums = values(colorTextureFormats)
var colorRenderbufferFormatEnums = values(colorRenderbufferFormats)
var highestPrecision = GL_UNSIGNED_BYTE
var colorTypes = {
'uint8': GL_UNSIGNED_BYTE
}
var colorTypes = ['uint8']
if (extensions.oes_texture_half_float) {
highestPrecision = colorTypes['half float'] = GL_HALF_FLOAT_OES
colorTypes.push('half float')
}
if (extensions.oes_texture_float) {
highestPrecision = colorTypes.float = GL_FLOAT
colorTypes.push('float')
}
colorTypes.best = highestPrecision
var DRAW_BUFFERS = (function () {
var result = new Array(limits.maxDrawbuffers)
for (var i = 0; i <= limits.maxDrawbuffers; ++i) {
var row = result[i] = new Array(i)
for (var j = 0; j < i; ++j) {
row[j] = GL_COLOR_ATTACHMENT0 + j
}
}
return result
})()
function FramebufferAttachment (target, level, texture, renderbuffer) {
function FramebufferAttachment (target, texture, renderbuffer) {
this.target = target
this.level = level
this.texture = texture
this.renderbuffer = renderbuffer
var w = 0
var h = 0
if (texture) {
w = texture.width
h = texture.height
} else if (renderbuffer) {
w = renderbuffer.width
h = renderbuffer.height
}
this.width = w
this.height = h
}

@@ -156,30 +141,20 @@

function incRefAndCheckShape (attachment, framebuffer) {
var width = framebuffer.width
var height = framebuffer.height
function incRefAndCheckShape (attachment, width, height) {
if (!attachment) {
return
}
if (attachment.texture) {
var texture = attachment.texture._texture
var tw = Math.max(1, texture.params.width >> attachment.level)
var th = Math.max(1, texture.params.height >> attachment.level)
width = width || tw
height = height || th
var tw = Math.max(1, texture.width)
var th = Math.max(1, texture.height)
check(tw === width && th === height,
'inconsistent width/height for supplied texture')
check(texture.pollId < 0,
'polling fbo textures not supported')
texture.refCount += 1
} else {
var renderbuffer = attachment.renderbuffer._renderbuffer
width = width || renderbuffer.width
height = height || renderbuffer.height
check(
renderbuffer.width === width && renderbuffer.height === height,
'inconsistent width/height for renderbuffer')
check(
colorRenderbufferFormatEnums.indexOf(renderbuffer.format) >= 0,
'renderbuffer format not compatible with color channels')
renderbuffer.refCount += 1
}
framebuffer.width = width
framebuffer.height = height
}

@@ -195,3 +170,3 @@

attachment.texture._texture.texture,
attachment.level)
0)
} else {

@@ -214,40 +189,4 @@ gl.framebufferRenderbuffer(

function tryUpdateAttachment (
attachment,
isTexture,
format,
type,
width,
height) {
if (attachment.texture) {
var texture = attachment.texture
if (isTexture) {
texture({
format: format,
type: type,
width: width,
height: height
})
texture._texture.refCount += 1
return true
}
} else {
var renderbuffer = attachment.renderbuffer
if (!isTexture) {
renderbuffer({
format: format,
width: width,
height: height
})
renderbuffer._renderbuffer.refCount += 1
return true
}
}
decRef(attachment)
return false
}
function parseAttachment (attachment) {
var target = GL_TEXTURE_2D
var level = 0
var texture = null

@@ -259,7 +198,4 @@ var renderbuffer = null

data = attachment.data
if ('level' in attachment) {
level = attachment.level | 0
}
if ('target' in attachment) {
target = attachment.target | 0
// target = attachment.target | 0
}

@@ -270,18 +206,15 @@ }

var type = attachment._reglType
if (type === 'texture') {
texture = attachment
if (texture._texture.target === GL_TEXTURE_CUBE_MAP) {
check(
target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
target < GL_TEXTURE_CUBE_MAP_POSITIVE_X + 6,
'invalid cube map target')
} else {
check(target === GL_TEXTURE_2D)
}
// TODO check miplevel is consistent
var type = data._reglType
if (type === 'texture2d') {
texture = data
check(target === GL_TEXTURE_2D)
} else if (type === 'textureCube') {
texture = data
check(
target >= GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
target < GL_TEXTURE_CUBE_MAP_POSITIVE_X + 6,
'invalid cube map target')
} else if (type === 'renderbuffer') {
renderbuffer = attachment
renderbuffer = data
target = GL_RENDERBUFFER
level = 0
} else {

@@ -291,5 +224,31 @@ check.raise('invalid regl object for attachment')

return new FramebufferAttachment(target, level, texture, renderbuffer)
return new FramebufferAttachment(target, texture, renderbuffer)
}
function allocAttachment (
width,
height,
isTexture,
format,
type) {
if (isTexture) {
var texture = textureState.create2D({
width: width,
height: height,
format: format,
type: type
})
texture._texture.refCount = 0
return new FramebufferAttachment(GL_TEXTURE_2D, texture, null)
} else {
var rb = renderbufferState.create({
width: width,
height: height,
format: format
})
rb._renderbuffer.refCount = 0
return new FramebufferAttachment(GL_RENDERBUFFER, null, rb)
}
}
function unwrapAttachment (attachment) {

@@ -299,2 +258,12 @@ return attachment && (attachment.texture || attachment.renderbuffer)

function resizeAttachment (attachment, w, h) {
if (attachment) {
if (attachment.texture) {
attachment.texture.resize(w, h)
} else if (attachment.renderbuffer) {
attachment.renderbuffer.resize(w, h)
}
}
}
var framebufferCount = 0

@@ -307,3 +276,3 @@ var framebufferSet = {}

this.framebuffer = null
this.framebuffer = gl.createFramebuffer()
this.width = 0

@@ -316,16 +285,25 @@ this.height = 0

this.depthStencilAttachment = null
}
this.ownsColor = false
this.ownsDepthStencil = false
function decFBORefs (framebuffer) {
framebuffer.colorAttachments.forEach(decRef)
decRef(framebuffer.depthAttachment)
decRef(framebuffer.stencilAttachment)
decRef(framebuffer.depthStencilAttachment)
}
function refresh (framebuffer) {
if (!gl.isFramebuffer(framebuffer.framebuffer)) {
framebuffer.framebuffer = gl.createFramebuffer()
}
framebufferState.dirty = true
function destroy (framebuffer) {
var handle = framebuffer.framebuffer
check(handle, 'must not double destroy framebuffer')
gl.deleteFramebuffer(handle)
framebuffer.framebuffer = null
stats.framebufferCount--
delete framebufferSet[framebuffer.id]
}
function updateFramebuffer (framebuffer) {
var i
gl.bindFramebuffer(GL_FRAMEBUFFER, framebuffer.framebuffer)
var colorAttachments = framebuffer.colorAttachments
for (var i = 0; i < colorAttachments.length; ++i) {
for (i = 0; i < colorAttachments.length; ++i) {
attach(GL_COLOR_ATTACHMENT0 + i, colorAttachments[i])

@@ -340,7 +318,2 @@ }

if (extensions.webgl_draw_buffers) {
extensions.webgl_draw_buffers.drawBuffersWEBGL(
DRAW_BUFFERS[colorAttachments.length])
}
// Check status code

@@ -352,26 +325,17 @@ var status = gl.checkFramebufferStatus(GL_FRAMEBUFFER)

}
}
function decFBORefs (framebuffer) {
framebuffer.colorAttachments.forEach(decRef)
decRef(framebuffer.depthAttachment)
decRef(framebuffer.stencilAttachment)
decRef(framebuffer.depthStencilAttachment)
gl.bindFramebuffer(GL_FRAMEBUFFER, framebufferState.next)
framebufferState.current = framebufferState.next
}
function destroy (framebuffer) {
var handle = framebuffer.framebuffer
check(handle, 'must not double destroy framebuffer')
if (gl.isFramebuffer(handle)) {
gl.deleteFramebuffer(handle)
}
}
function createFBO (options) {
function createFBO (a0, a1) {
var framebuffer = new REGLFramebuffer()
stats.framebufferCount++
function reglFramebuffer (input) {
function reglFramebuffer (a, b) {
var i
var options = input || {}
check(framebufferState.next !== framebuffer,
'can not update framebuffer which is currently in use')
var extDrawBuffers = extensions.webgl_draw_buffers

@@ -381,130 +345,137 @@

var height = 0
if ('shape' in options) {
var shape = options.shape
check(Array.isArray(shape) && shape.length >= 2,
'invalid shape for framebuffer')
width = shape[0]
height = shape[1]
} else {
if ('radius' in options) {
width = height = options.radius
}
if ('width' in options) {
width = options.width
}
if ('height' in options) {
height = options.height
}
}
// colorType, numColors
var colorBuffers = null
var ownsColor = false
if ('colorBuffers' in options || 'colorBuffer' in options) {
var colorInputs = options.colorBuffers || options.colorBuffer
if (!Array.isArray(colorInputs)) {
colorInputs = [colorInputs]
}
var needsDepth = true
var needsStencil = true
framebuffer.width = width
framebuffer.height = height
var colorBuffer = null
var colorTexture = true
var colorFormat = 'rgba'
var colorType = 'uint8'
var colorCount = 1
if (colorInputs.length > 1) {
check(extDrawBuffers, 'multiple render targets not supported')
}
check(colorInputs.length >= 0,
'must specify at least one color attachment')
var depthBuffer = null
var stencilBuffer = null
var depthStencilBuffer = null
var depthStencilTexture = false
// Wrap color attachments
colorBuffers = colorInputs.map(parseAttachment)
if (typeof a === 'number') {
width = a | 0
height = (b | 0) || width
} else if (!a) {
width = height = 1
} else {
check.type(a, 'object', 'invalid arguments for framebuffer')
var options = a
// Check head node
for (i = 0; i < colorBuffers.length; ++i) {
var colorAttachment = colorBuffers[i]
check.framebufferFormat(
colorAttachment,
colorTextureFormatEnums,
colorRenderbufferFormatEnums)
incRefAndCheckShape(
colorAttachment,
framebuffer)
if ('shape' in options) {
var shape = options.shape
check(Array.isArray(shape) && shape.length >= 2,
'invalid shape for framebuffer')
width = shape[0]
height = shape[1]
} else {
if ('radius' in options) {
width = height = options.radius
}
if ('width' in options) {
width = options.width
}
if ('height' in options) {
height = options.height
}
}
width = framebuffer.width
height = framebuffer.height
} else {
var colorTexture = true
var colorFormat = 'rgba'
var colorType = 'uint8'
var colorCount = 1
ownsColor = true
if ('color' in options ||
'colors' in options) {
colorBuffer =
options.color ||
options.colors
if (Array.isArray(colorBuffer)) {
check(
colorBuffer.length === 1 || extDrawBuffers,
'multiple render targets not supported')
}
}
framebuffer.width = width = width || gl.drawingBufferWidth
framebuffer.height = height = height || gl.drawingBufferHeight
if (!colorBuffer) {
if ('colorCount' in options) {
colorCount = options.colorCount | 0
check(colorCount > 0, 'invalid color buffer count')
}
if ('format' in options) {
colorFormat = options.format
check.parameter(colorFormat, colorFormats, 'invalid color format')
colorTexture = colorFormat in colorTextureFormats
}
if ('colorTexture' in options) {
colorTexture = !!options.colorTexture
colorFormat = 'rgba4'
}
if ('type' in options) {
check(colorTexture,
'colorType can not be set for renderbuffer targets')
colorType = options.type
check.parameter(colorType, colorTypes, 'invalid color type')
if ('colorType' in options) {
check.oneOf(
options.colorType, colorTypes,
'invalid color type')
colorType = options.colorType
if (!colorTexture) {
if (colorType === 'half float') {
if (extensions.ext_color_buffer_half_float) {
colorFormat = 'rgba16f'
}
} else if (colorType === 'float') {
if (extensions.webgl_color_buffer_float) {
colorFormat = 'rgba32f'
}
}
}
}
if ('colorFormat' in options) {
colorFormat = options.colorFormat
if (colorTextureFormats.indexOf(colorFormat) >= 0) {
colorTexture = true
} else if (colorRenderbufferFormats.indexOf(colorFormat) >= 0) {
colorTexture = false
} else {
if (colorTexture) {
check.oneOf(
options.colorFormat, colorTextureFormats,
'invalid color format for texture')
} else {
check.oneOf(
options.colorFormat, colorRenderbufferFormats,
'invalid color format for renderbuffer')
}
}
}
}
if ('colorCount' in options) {
colorCount = options.colorCount | 0
check(colorCount >= 0, 'color count must be positive')
if ('depthTexture' in options || 'depthStencilTexture' in options) {
depthStencilTexture = !!(options.depthTexture ||
options.depthStencilTexture)
check(!depthStencilTexture || extensions.webgl_depth_texture,
'webgl_depth_texture extension not supported')
}
// Reuse color buffer array if we own it
if (framebuffer.ownsColor) {
colorBuffers = framebuffer.colorAttachments
while (colorBuffers.length > colorCount) {
decRef(colorBuffers.pop())
if ('depth' in options) {
if (typeof options.depth === 'boolean') {
needsDepth = options.depth
} else {
depthBuffer = options.depth
needsStencil = false
}
} else {
colorBuffers = []
}
// update buffers in place, remove incompatible buffers
for (i = 0; i < colorBuffers.length; ++i) {
if (!tryUpdateAttachment(
colorBuffers[i],
colorTexture,
colorFormat,
colorType,
width,
height)) {
colorBuffers[i--] = colorBuffers[colorBuffers.length - 1]
colorBuffers.pop()
if ('stencil' in options) {
if (typeof options.stencil === 'boolean') {
needsStencil = options.stencil
} else {
stencilBuffer = options.stencil
needsDepth = false
}
}
// Then append new buffers
while (colorBuffers.length < colorCount) {
if (colorTexture) {
colorBuffers.push(new FramebufferAttachment(
GL_TEXTURE_2D,
0,
textureState.create2D({
format: colorFormat,
type: colorType,
width: width,
height: height
}, GL_TEXTURE_2D),
null))
if ('depthStencil' in options) {
if (typeof options.depthStencil === 'boolean') {
needsDepth = needsStencil = options.depthStencil
} else {
colorBuffers.push(new FramebufferAttachment(
GL_RENDERBUFFER,
0,
null,
renderbufferState.create({
format: colorFormat,
width: width,
height: height
})))
depthStencilBuffer = options.depthStencil
needsDepth = false
needsStencil = false
}

@@ -514,159 +485,112 @@ }

check(colorBuffers.length > 0, 'must specify at least one color buffer')
// parse attachments
var colorAttachments = null
var depthAttachment = null
var stencilAttachment = null
var depthStencilAttachment = null
framebuffer.width = width
framebuffer.height = height
var depthBuffer = null
var stencilBuffer = null
var depthStencilBuffer = null
var ownsDepthStencil = false
var depthStencilCount = 0
if ('depthBuffer' in options) {
depthBuffer = parseAttachment(options.depthBuffer)
check.framebufferFormat(
depthBuffer,
depthTextureFormatEnums,
depthRenderbufferFormatEnums)
depthStencilCount += 1
// Set up color attachments
if (Array.isArray(colorBuffer)) {
colorAttachments = colorBuffer.map(parseAttachment)
} else if (colorBuffer) {
colorAttachments = [parseAttachment(colorBuffer)]
} else {
colorAttachments = new Array(colorCount)
for (i = 0; i < colorCount; ++i) {
colorAttachments[i] = allocAttachment(
width,
height,
colorTexture,
colorFormat,
colorType)
}
}
if ('stencilBuffer' in options) {
stencilBuffer = parseAttachment(options.stencilBuffer)
check.framebufferFormat(
stencilBuffer,
stencilTextureFormatEnums,
stencilRenderbufferFormatEnums)
depthStencilCount += 1
}
if ('depthStencilBuffer' in options) {
depthStencilBuffer = parseAttachment(options.depthStencilBuffer)
check.framebufferFormat(
depthStencilBuffer,
depthStencilTextureFormatEnums,
depthStencilRenderbufferFormatEnums)
depthStencilCount += 1
}
if (!(depthBuffer || stencilBuffer || depthStencilBuffer)) {
var depth = true
var stencil = false
var useTexture = false
check(colorAttachments.length <= limits.maxColorAttachments,
'too many color attachments, not supported')
if ('depth' in options) {
depth = !!options.depth
}
if ('stencil' in options) {
stencil = !!options.stencil
}
if ('depthTexture' in options) {
useTexture = !!options.depthTexture
}
width = width || colorAttachments[0].width
height = height || colorAttachments[0].height
var curDepthStencil =
framebuffer.depthAttachment ||
framebuffer.stencilAttachment ||
framebuffer.depthStencilAttachment
var nextDepthStencil = null
if (depthBuffer) {
depthAttachment = parseAttachment(depthBuffer)
} else if (needsDepth && !needsStencil) {
depthAttachment = allocAttachment(
width,
height,
depthStencilTexture,
'depth',
'uint32')
}
if (depth || stencil) {
ownsDepthStencil = true
if (stencilBuffer) {
stencilAttachment = parseAttachment(stencilBuffer)
} else if (needsStencil && !needsDepth) {
stencilAttachment = allocAttachment(
width,
height,
false,
'stencil',
'uint8')
}
if (useTexture) {
check(extensions.webgl_depth_texture,
'depth texture extension not supported')
var depthTextureFormat
check(depth, 'stencil only textures not supported')
if (stencil) {
depthTextureFormat = 'depth stencil'
} else {
depthTextureFormat = 'depth'
}
if (framebuffer.ownsDepthStencil && curDepthStencil.texture) {
curDepthStencil.texture({
format: depthTextureFormat,
width: width,
height: height
})
curDepthStencil.texture._texture.refCount += 1
nextDepthStencil = curDepthStencil
} else {
nextDepthStencil = new FramebufferAttachment(
GL_TEXTURE_2D,
0,
textureState.create({
format: depthTextureFormat,
width: width,
height: height
}, GL_TEXTURE_2D),
null)
}
} else {
var depthRenderbufferFormat
if (depth) {
if (stencil) {
depthRenderbufferFormat = 'depth stencil'
} else {
depthRenderbufferFormat = 'depth'
}
} else {
depthRenderbufferFormat = 'stencil'
}
if (framebuffer.ownsDepthStencil && curDepthStencil.renderbuffer) {
curDepthStencil.renderbuffer({
format: depthRenderbufferFormat,
width: width,
height: height
})
curDepthStencil.renderbuffer._renderbuffer.refCount += 1
nextDepthStencil = curDepthStencil
} else {
nextDepthStencil = new FramebufferAttachment(
GL_RENDERBUFFER,
0,
null,
renderbufferState.create({
format: depthRenderbufferFormat,
width: width,
height: height
}))
}
}
if (depthStencilBuffer) {
depthStencilAttachment = parseAttachment(depthStencilBuffer)
} else if (!depthBuffer && !stencilBuffer && needsStencil && needsDepth) {
depthStencilAttachment = allocAttachment(
width,
height,
depthStencilTexture,
'depth stencil',
'depth stencil')
}
if (depth) {
if (stencil) {
depthStencilBuffer = nextDepthStencil
} else {
depthBuffer = nextDepthStencil
}
} else {
stencilBuffer = nextDepthStencil
}
}
} else {
check(depthStencilCount === 1,
'can specify only one of depth, stencil or depthStencil attachment')
check(
(!!depthBuffer) + (!!stencilBuffer) + (!!depthStencilBuffer) <= 1,
'invalid framebuffer configuration, can specify exactly one depth/stencil attachment')
incRefAndCheckShape(
depthBuffer ||
stencilBuffer ||
depthStencilBuffer,
framebuffer)
for (i = 0; i < colorAttachments.length; ++i) {
incRefAndCheckShape(colorAttachments[i], width, height)
check(!colorAttachments[i] ||
(colorAttachments[i].texture &&
colorTextureFormatEnums.indexOf(colorAttachments[i].texture._texture.format) >= 0) ||
(colorAttachments[i].renderbuffer &&
colorRenderbufferFormatEnums.indexOf(colorAttachments[i].renderbuffer._renderbuffer.format) >= 0),
'framebuffer color attachment ' + i + ' is invalid')
}
incRefAndCheckShape(depthAttachment, width, height)
check(!depthAttachment ||
(depthAttachment.texture &&
depthAttachment.texture._texture.format === GL_DEPTH_COMPONENT) ||
(depthAttachment.renderbuffer &&
depthAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_COMPONENT16),
'invalid depth attachment for framebuffer object')
incRefAndCheckShape(stencilAttachment, width, height)
check(!stencilAttachment ||
(stencilAttachment.renderbuffer &&
stencilAttachment.renderbuffer._renderbuffer.format === GL_STENCIL_INDEX8),
'invalid stencil attachment for framebuffer object')
incRefAndCheckShape(depthStencilAttachment, width, height)
check(!depthStencilAttachment ||
(depthStencilAttachment.texture &&
depthStencilAttachment.texture._texture.format === GL_DEPTH_STENCIL) ||
(depthStencilAttachment.renderbuffer &&
depthStencilAttachment.renderbuffer._renderbuffer.format === GL_DEPTH_STENCIL),
'invalid depth-stencil attachment for framebuffer object')
// decrement references
decFBORefs(framebuffer)
framebuffer.colorAttachments = colorBuffers
framebuffer.depthAttachment = depthBuffer
framebuffer.stencilAttachment = stencilBuffer
framebuffer.depthStencilAttachment = depthStencilBuffer
framebuffer.ownsColor = ownsColor
framebuffer.ownsDepthStencil = ownsDepthStencil
framebuffer.width = width
framebuffer.height = height
reglFramebuffer.color = colorBuffers.map(unwrapAttachment)
reglFramebuffer.depth = unwrapAttachment(depthBuffer)
reglFramebuffer.stencil = unwrapAttachment(stencilBuffer)
reglFramebuffer.depthStencil = unwrapAttachment(depthStencilBuffer)
framebuffer.colorAttachments = colorAttachments
framebuffer.depthAttachment = depthAttachment
framebuffer.stencilAttachment = stencilAttachment
framebuffer.depthStencilAttachment = depthStencilAttachment
refresh(framebuffer)
reglFramebuffer.color = colorAttachments.map(unwrapAttachment)
reglFramebuffer.depth = unwrapAttachment(depthAttachment)
reglFramebuffer.stencil = unwrapAttachment(stencilAttachment)
reglFramebuffer.depthStencil = unwrapAttachment(depthStencilAttachment)

@@ -676,11 +600,42 @@ reglFramebuffer.width = framebuffer.width

updateFramebuffer(framebuffer)
return reglFramebuffer
}
reglFramebuffer(options)
function resize (w_, h_) {
check(framebufferState.next !== framebuffer,
'can not resize a framebuffer which is currently in use')
var w = w_ | 0
var h = (h_ | 0) || w
if (w === framebuffer.width && h === framebuffer.height) {
return reglFramebuffer
}
// resize all buffers
var colorAttachments = framebuffer.colorAttachments
for (var i = 0; i < colorAttachments.length; ++i) {
resizeAttachment(colorAttachments[i], w, h)
}
resizeAttachment(framebuffer.depthAttachment, w, h)
resizeAttachment(framebuffer.stencilAttachment, w, h)
resizeAttachment(framebuffer.depthStencilAttachment, w, h)
framebuffer.width = reglFramebuffer.width = w
framebuffer.height = reglFramebuffer.height = h
updateFramebuffer(framebuffer)
return reglFramebuffer
}
reglFramebuffer(a0, a1)
reglFramebuffer.resize = resize
reglFramebuffer._reglType = 'framebuffer'
reglFramebuffer._framebuffer = framebuffer
reglFramebuffer._destroy = function () {
reglFramebuffer.destroy = function () {
destroy(framebuffer)
decFBORefs(framebuffer)
}

@@ -691,10 +646,2 @@

function refreshCache () {
values(framebufferSet).forEach(refresh)
}
function clearCache () {
values(framebufferSet).forEach(destroy)
}
return extend(framebufferState, {

@@ -711,5 +658,6 @@ getFramebuffer: function (object) {

create: createFBO,
clear: clearCache,
refresh: refreshCache
clear: function () {
values(framebufferSet).forEach(destroy)
}
})
}

@@ -10,14 +10,21 @@ var check = require('./util/check')

function readPixels (input) {
var options = input || {}
// TODO check framebuffer state supports read
var x = 0
var y = 0
var width = context.framebufferWidth
var height = context.framebufferHeight
var data = null
if (isTypedArray(input)) {
options = {
data: options
}
data = input
} else if (arguments.length === 2) {
options = {
width: arguments[0] | 0,
height: arguments[1] | 0
}
} else if (typeof input !== 'object') {
options = {}
width = arguments[0] | 0
height = arguments[1] | 0
} else if (input) {
check.type(input, 'object', 'invalid arguments to regl.read()')
x = input.x | 0
y = input.y | 0
width = input.width || context.framebufferWidth
height = input.height || context.framebufferHeight
data = input.data || null
}

@@ -28,10 +35,6 @@

// Read viewport state
var x = options.x || 0
var y = options.y || 0
var width = options.width || context.viewportWidth
var height = options.height || context.viewportHeight
// TODO:
// float color buffers
// implementation specific formats
// TODO handle color buffer float
// Compute size

@@ -41,3 +44,3 @@ var size = width * height * 4

// Allocate data
var data = options.data || new Uint8Array(size)
data = data || new Uint8Array(size)

@@ -44,0 +47,0 @@ // Type check

@@ -20,3 +20,3 @@ var check = require('./util/check')

module.exports = function (gl, extensions, limits) {
module.exports = function (gl, extensions, limits, stats) {
var formatTypes = {

@@ -47,7 +47,7 @@ 'rgba4': GL_RGBA4,

function REGLRenderbuffer () {
function REGLRenderbuffer (renderbuffer) {
this.id = renderbufferCount++
this.refCount = 1
this.renderbuffer = null
this.renderbuffer = renderbuffer

@@ -60,3 +60,3 @@ this.format = GL_RGBA4

REGLRenderbuffer.prototype.decRef = function () {
if (--this.refCount === 0) {
if (--this.refCount <= 0) {
destroy(this)

@@ -66,14 +66,2 @@ }

function refresh (rb) {
if (!gl.isRenderbuffer(rb.renderbuffer)) {
rb.renderbuffer = gl.createRenderbuffer()
}
gl.bindRenderbuffer(GL_RENDERBUFFER, rb.renderbuffer)
gl.renderbufferStorage(
GL_RENDERBUFFER,
rb.format,
rb.width,
rb.height)
}
function destroy (rb) {

@@ -83,56 +71,104 @@ var handle = rb.renderbuffer

gl.bindRenderbuffer(GL_RENDERBUFFER, null)
if (gl.isRenderbuffer(handle)) {
gl.deleteRenderbuffer(handle)
}
gl.deleteRenderbuffer(handle)
rb.renderbuffer = null
rb.refCount = 0
delete renderbufferSet[rb.id]
stats.renderbufferCount--
}
function createRenderbuffer (input) {
var renderbuffer = new REGLRenderbuffer()
function createRenderbuffer (a, b) {
var renderbuffer = new REGLRenderbuffer(gl.createRenderbuffer())
renderbufferSet[renderbuffer.id] = renderbuffer
stats.renderbufferCount++
function reglRenderbuffer (input) {
var options = input || {}
function reglRenderbuffer (a, b) {
var w = 0
var h = 0
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
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 ('width' in options) {
w = options.width | 0
if ('format' in options) {
check.parameter(options.format, formatTypes,
'invalid renderbuffer format')
format = formatTypes[options.format]
}
if ('height' in options) {
h = options.height | 0
} 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')
}
var s = limits.maxRenderbufferSize
check(w >= 0 && h >= 0 && w <= s && h <= s,
// check shape
check(
w > 0 && h > 0 &&
w <= limits.maxRenderbufferSize && h <= limits.maxRenderbufferSize,
'invalid renderbuffer size')
reglRenderbuffer.width = renderbuffer.width = Math.max(w, 1)
reglRenderbuffer.height = renderbuffer.height = Math.max(h, 1)
renderbuffer.format = GL_RGBA4
if ('format' in options) {
var format = options.format
check.parameter(format, formatTypes, 'invalid render buffer format')
renderbuffer.format = formatTypes[format]
if (w === renderbuffer.width &&
h === renderbuffer.height &&
format === renderbuffer.format) {
return
}
refresh(renderbuffer)
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)
return reglRenderbuffer
}
reglRenderbuffer(input)
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)
return reglRenderbuffer
}
reglRenderbuffer(a, b)
reglRenderbuffer.resize = resize
reglRenderbuffer._reglType = 'renderbuffer'

@@ -147,15 +183,8 @@ reglRenderbuffer._renderbuffer = renderbuffer

function refreshRenderbuffers () {
values(renderbufferSet).forEach(refresh)
}
function destroyRenderbuffers () {
values(renderbufferSet).forEach(destroy)
}
return {
create: createRenderbuffer,
refresh: refreshRenderbuffers,
clear: destroyRenderbuffers
clear: function () {
values(renderbufferSet).forEach(destroy)
}
}
}

@@ -10,3 +10,3 @@ var check = require('./util/check')

module.exports = function wrapShaderState (gl, stringStore) {
module.exports = function wrapShaderState (gl, stringStore, stats) {
// ===================================================

@@ -145,8 +145,4 @@ // glsl compilation and linking

programCache = {}
},
refresh: function () {
fragShaders = {}
vertShaders = {}
programList.forEach(linkProgram)
stats.shaderCount = 0
},

@@ -158,2 +154,4 @@

stats.shaderCount++
var cache = programCache[fragId]

@@ -160,0 +158,0 @@ if (!cache) {

@@ -8,2 +8,3 @@ var check = require('./util/check')

var convertToHalfFloat = require('./util/to-half-float')
var isArrayLike = require('./util/is-array-like')

@@ -154,14 +155,6 @@ var dtypes = require('./constants/arraytypes.json')

}
var width = arr.length
if (width === 0 || !Array.isArray(arr[0])) {
if (width === 0 || !isArrayLike(arr[0])) {
return false
}
var height = arr[0].length
for (var i = 1; i < width; ++i) {
if (!Array.isArray(arr[i]) || arr[i].length !== height) {
return false
}
}
return true

@@ -300,3 +293,3 @@ }

module.exports = function createTextureSet (
gl, extensions, limits, reglPoll, contextState) {
gl, extensions, limits, reglPoll, contextState, stats) {
// -------------------------------------------------------

@@ -708,3 +701,3 @@ // Initialize constants and parameter tables here

var c = 1
if (Array.isArray(data[0][0])) {
if (isArrayLike(data[0][0])) {
c = data[0][0].length

@@ -724,3 +717,3 @@ flatten3DData(image, data, w, h, c)

if (image.type === GL_FLOAT) {
check(limits.extenstions.indexOf('oes_texture_float') >= 0,
check(limits.extensions.indexOf('oes_texture_float') >= 0,
'oes_texture_float extension not enabled')

@@ -823,2 +816,3 @@ } else if (image.type === GL_HALF_FLOAT_OES) {

imgData = mipmap.images[0] = allocImage()
copyFlags(imgData, mipmap)
parseImage(imgData, options)

@@ -1018,2 +1012,3 @@ mipmap.mipmask = 1

this.mipmask = 0
this.internalformat = GL_RGBA

@@ -1061,2 +1056,3 @@ this.id = textureCount++

delete textureSet[texture.id]
stats.textureCount--
}

@@ -1097,3 +1093,3 @@

decRef: function () {
if (--this.refCount === 0) {
if (--this.refCount <= 0) {
destroy(this)

@@ -1107,2 +1103,3 @@ }

textureSet[texture.id] = texture
stats.textureCount++

@@ -1136,2 +1133,3 @@ function reglTexture2D (a, b) {

check.texture2D(texInfo, mipData, limits)
texture.internalformat = mipData.internalformat

@@ -1193,5 +1191,32 @@ reglTexture2D.width = mipData.width

function resize (w_, h_) {
var w = w_ | 0
var h = (h_ | 0) || w
if (w === texture.width && h === texture.height) {
return reglTexture2D
}
reglTexture2D.width = texture.width = w
reglTexture2D.height = texture.height = h
tempBind(texture)
gl.texImage2D(
GL_TEXTURE_2D,
0,
texture.format,
w,
h,
0,
texture.format,
texture.type,
null)
tempRestore()
return reglTexture2D
}
reglTexture2D(a, b)
reglTexture2D.subimage = subimage
reglTexture2D.resize = resize
reglTexture2D._reglType = 'texture2d'

@@ -1209,2 +1234,3 @@ reglTexture2D._texture = texture

textureSet[texture.id] = texture
stats.cubeCount++

@@ -1264,2 +1290,3 @@ var faces = new Array(6)

check.textureCube(texture, texInfo, faces, limits)
texture.internalformat = faces[0].internalformat

@@ -1328,5 +1355,34 @@ reglTextureCube.width = faces[0].width

function resize (w_, h_) {
var w = w_ | 0
var h = (h_ | 0) || w
if (w === texture.width && h === texture.height) {
return reglTextureCube
}
reglTextureCube.width = texture.width = w
reglTextureCube.height = texture.height = h
tempBind(texture)
for (var i = 0; i < 6; ++i) {
gl.texImage2D(
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0,
texture.format,
w,
h,
0,
texture.format,
texture.type,
null)
}
tempRestore()
return reglTextureCube
}
reglTextureCube(a0, a1, a2, a3, a4, a5)
reglTextureCube.subimage = subimage
reglTextureCube.resize = resize
reglTextureCube._reglType = 'textureCube'

@@ -1349,2 +1405,5 @@ reglTextureCube._texture = texture

values(textureSet).forEach(destroy)
stats.cubeCount = 0
stats.textureCount = 0
}

@@ -1351,0 +1410,0 @@

@@ -104,3 +104,3 @@ // Error checking and parameter validation.

var error = new Error()
var stack = error.stack.toString()
var stack = (error.stack || error).toString()
var pat = /compileProcedure.*\n\s*at.*\((.*)\)/.exec(stack)

@@ -119,3 +119,3 @@ if (pat) {

var error = new Error()
var stack = error.stack
var stack = (error.stack || error).toString()
var pat = /at REGLCommand.*\n\s+at.*\((.*)\)/.exec(stack)

@@ -377,3 +377,3 @@ if (pat) {

checkOneOf(
attachment.texture._texture.params.internalformat,
attachment.texture._texture.internalformat,
texFormats,

@@ -380,0 +380,0 @@ 'unsupported texture format for attachment')

@@ -167,2 +167,3 @@ var extend = require('./extend')

var proc = Function.apply(null, linkedNames.concat(src))
// console.log('src: ', src)
return proc.apply(null, linkedValues)

@@ -169,0 +170,0 @@ }

{
"name": "regl",
"version": "0.8.0",
"description": "WebGL",
"version": "0.9.0",
"description": "Regl is a fast functional reactive abstraction for WebGL.",
"main": "regl.js",

@@ -19,2 +19,3 @@ "directories": {

"canvas-orbit-camera": "^1.0.2",
"control-panel": "^1.2.0",
"falafel": "^1.2.0",

@@ -30,2 +31,3 @@ "faucet": "0.0.1",

"indexhtmlify": "^1.2.1",
"install": "^0.8.1",
"istanbul": "^0.4.3",

@@ -36,2 +38,4 @@ "mkdirp": "^0.5.1",

"parse-dds": "^1.2.1",
"primitive-sphere": "^2.0.0",
"regl-stats-widget": "0.0.1",
"resl": "^1.0.0",

@@ -47,2 +51,3 @@ "runscript": "^1.1.0",

"scripts": {
"mytest": "standard | snazzy && tape test/stats.js",
"test": "standard | snazzy && tape test/util/index.js | faucet",

@@ -49,0 +54,0 @@ "test-browser": "budo test/util/browser.js --open",

@@ -61,3 +61,3 @@ # regl

// regl.frame() wraps requestAnimationFrame and also handles viewport changes
regl.frame(() => {
regl.frame(({time}) => {
// clear contents of the drawing buffer

@@ -72,5 +72,5 @@ regl.clear({

color: [
Math.cos(Date.now() * 0.001),
Math.sin(Date.now() * 0.0008),
Math.cos(Date.now() * 0.003),
Math.cos(time * 0.001),
Math.sin(time * 0.0008),
Math.cos(time * 0.003),
1

@@ -116,10 +116,435 @@ ]

**TODO** implement spinning textured cube in each of the following frameworks
In this section, we show how you can implement a spinning textured cube in `regl`, and compare it with other WebGL frameworks.
* vs WebGL
* vs gl-* modules from stack.gl
* gl-react
* vs TWGL
* vs THREE.js
![](images/cube_example.png)
#### [`regl`](https://mikolalysenko.github.io/regl/www/gallery/cube.js.html)
```javascript
const regl = require('../regl')()
const mat4 = require('gl-mat4')
var cubePosition = [
[-0.5, +0.5, +0.5], [+0.5, +0.5, +0.5], [+0.5, -0.5, +0.5], [-0.5, -0.5, +0.5], // positive z face.
[+0.5, +0.5, +0.5], [+0.5, +0.5, -0.5], [+0.5, -0.5, -0.5], [+0.5, -0.5, +0.5], // positive x face
[+0.5, +0.5, -0.5], [-0.5, +0.5, -0.5], [-0.5, -0.5, -0.5], [+0.5, -0.5, -0.5], // negative z face
[-0.5, +0.5, -0.5], [-0.5, +0.5, +0.5], [-0.5, -0.5, +0.5], [-0.5, -0.5, -0.5], // negative x face.
[-0.5, +0.5, -0.5], [+0.5, +0.5, -0.5], [+0.5, +0.5, +0.5], [-0.5, +0.5, +0.5], // top face
[-0.5, -0.5, -0.5], [+0.5, -0.5, -0.5], [+0.5, -0.5, +0.5], [-0.5, -0.5, +0.5] // bottom face
]
var cubeUv = [
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], // positive z face.
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], // positive x face.
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], // negative z face.
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], // negative x face.
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], // top face
[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0] // bottom face
]
const cubeElements = [
[2, 1, 0], [2, 0, 3], // positive z face.
[6, 5, 4], [6, 4, 7], // positive x face.
[10, 9, 8], [10, 8, 11], // negative z face.
[14, 13, 12], [14, 12, 15], // negative x face.
[18, 17, 16], [18, 16, 19], // top face.
[20, 21, 22], [23, 20, 22] // bottom face
]
const drawCube = regl({
frag: `
precision mediump float;
varying vec2 vUv;
uniform sampler2D tex;
void main () {
gl_FragColor = texture2D(tex,vUv);
}`,
vert: `
precision mediump float;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
uniform mat4 projection, view;
void main() {
vUv = uv;
gl_Position = projection * view * vec4(position, 1);
}`,
attributes: {
position: cubePosition,
uv: cubeUv
},
elements: cubeElements,
uniforms: {
view: ({tick}) => {
const t = 0.01 * tick
return mat4.lookAt([],
[5 * Math.cos(t), 2.5 * Math.sin(t), 5 * Math.sin(t)],
[0, 0.0, 0],
[0, 1, 0])
},
projection: ({viewportWidth, viewportHeight}) =>
mat4.perspective([],
Math.PI / 4,
viewportWidth / viewportHeight,
0.01,
10),
tex: regl.prop('texture')
}
})
require('resl')({
manifest: {
texture: {
type: 'image',
src: 'assets/lena.png',
parser: (data) => regl.texture({
data: data,
mag: 'linear',
min: 'linear'
})
}
},
onDone: ({texture}) => {
regl.frame(() => {
regl.clear({
color: [0, 0, 0, 255],
depth: 1
})
drawCube({texture})
})
}
})
```
#### [Raw WebGL](https://mikolalysenko.github.io/regl/compare/webgl_cube.html)
```html
<!doctype html>
<html>
<head>
<title>WebGL Textured Cube Demo</title>
<script type="text/javascript">
/* global Image, alert, requestAnimationFrame */
var canvas
var gl
var cubePositionBuffer
var cubeUvBuffer
var cubeElementsBuffers
var cubeTexture
var shaderProgram
var cubePositionAttribute
var cubeUvAttribute
var projectionUniformLocation
var viewUniformLocation
var tick
function start () {
canvas = document.getElementById('glcanvas')
tick = 0
initWebGL(canvas)
if (gl) {
gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.enable(gl.DEPTH_TEST)
gl.enable(gl.CULL_FACE)
initShaders()
initBuffers()
initTextures()
// start RAF
requestAnimationFrame(drawScene)
}
}
function initWebGL () {
try {
gl = canvas.getContext('experimental-webgl')
} catch (e) {
}
if (!gl) {
alert('Unable to initialize WebGL. Your browser may not support it.')
}
}
function initBuffers () {
cubePositionBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, cubePositionBuffer)
var cubePosition = [
// positive z face.
-0.5, +0.5, +0.5,
+0.5, +0.5, +0.5,
+0.5, -0.5, +0.5,
-0.5, -0.5, +0.5,
// positive x face
+0.5, +0.5, +0.5,
+0.5, +0.5, -0.5,
+0.5, -0.5, -0.5,
+0.5, -0.5, +0.5,
// negative z face
+0.5, +0.5, -0.5,
-0.5, +0.5, -0.5,
-0.5, -0.5, -0.5,
+0.5, -0.5, -0.5,
// negative x face.
-0.5, +0.5, -0.5,
-0.5, +0.5, +0.5,
-0.5, -0.5, +0.5,
-0.5, -0.5, -0.5,
// top face
-0.5, +0.5, -0.5,
+0.5, +0.5, -0.5,
+0.5, +0.5, +0.5,
-0.5, +0.5, +0.5,
// bottom face
-0.5, -0.5, -0.5,
+0.5, -0.5, -0.5,
+0.5, -0.5, +0.5,
-0.5, -0.5, +0.5
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubePosition), gl.STATIC_DRAW)
cubeUvBuffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, cubeUvBuffer)
var cubeUv = [
// positive z face.
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// positive x face.
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// negative z face.
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// negative x face.
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// top face
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0,
// bottom face
0.0, 0.0,
1.0, 0.0,
1.0, 1.0,
0.0, 1.0
]
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeUv), gl.STATIC_DRAW)
cubeElementsBuffers = gl.createBuffer()
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeElementsBuffers)
var cubeElements = [
// positive z face.
2, 1, 0,
2, 0, 3,
// positive x face.
6, 5, 4,
6, 4, 7,
// negative z face.
10, 9, 8,
10, 8, 11,
// negative x face.
14, 13, 12,
14, 12, 15,
// top face.
18, 17, 16,
18, 16, 19,
// bottom face
20, 21, 22,
23, 20, 22
]
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeElements), gl.STATIC_DRAW)
}
function initTextures () {
cubeTexture = gl.createTexture()
var cubeImage = new Image()
cubeImage.onload = function () {
gl.bindTexture(gl.TEXTURE_2D, cubeTexture)
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, cubeImage)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
}
cubeImage.src = '../example/assets/lena.png'
}
function drawScene () {
tick++
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
// bind buffers.
gl.bindBuffer(gl.ARRAY_BUFFER, cubePositionBuffer)
gl.vertexAttribPointer(cubePositionAttribute, 3, gl.FLOAT, false, 0, 0)
gl.bindBuffer(gl.ARRAY_BUFFER, cubeUvBuffer)
gl.vertexAttribPointer(cubeUvAttribute, 2, gl.FLOAT, false, 0, 0)
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeElementsBuffers)
// set texture.
gl.activeTexture(gl.TEXTURE0)
gl.bindTexture(gl.TEXTURE_2D, cubeTexture)
// set uniforms
gl.uniform1i(gl.getUniformLocation(shaderProgram, 'tex'), 0)
const t = 0.01 * tick
var perspectiveMatrix = perspective(45, 640.0 / 480.0, 0.1, 100.0)
gl.uniformMatrix4fv(projectionUniformLocation, false, new Float32Array(perspectiveMatrix))
gl.uniformMatrix4fv(viewUniformLocation, false, new Float32Array(
lookAt(
[5 * Math.cos(t), 2.5 * Math.sin(t), 5 * Math.sin(t)],
[0, 0.0, 0],
[0, 1, 0])))
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0)
requestAnimationFrame(drawScene)
}
function initShaders () {
var fragmentShader = getShader(gl, 'shader-fs')
var vertexShader = getShader(gl, 'shader-vs')
shaderProgram = gl.createProgram()
gl.attachShader(shaderProgram, vertexShader)
gl.attachShader(shaderProgram, fragmentShader)
gl.linkProgram(shaderProgram)
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram))
}
gl.useProgram(shaderProgram)
cubePositionAttribute = gl.getAttribLocation(shaderProgram, 'position')
gl.enableVertexAttribArray(cubePositionAttribute)
cubeUvAttribute = gl.getAttribLocation(shaderProgram, 'uv')
gl.enableVertexAttribArray(cubeUvAttribute)
projectionUniformLocation = gl.getUniformLocation(shaderProgram, 'projection')
viewUniformLocation = gl.getUniformLocation(shaderProgram, 'view')
}
function getShader (gl, id) {
var e = document.getElementById(id)
if (!e) {
return null
}
var sourceCode = e.firstChild.textContent
var shader
if (e.type === 'x-shader/x-fragment') {
shader = gl.createShader(gl.FRAGMENT_SHADER)
} else if (e.type === 'x-shader/x-vertex') {
shader = gl.createShader(gl.VERTEX_SHADER)
} else {
return null
}
gl.shaderSource(shader, sourceCode)
gl.compileShader(shader)
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader))
return null
}
return shader
}
// Taken from gl-mat4
// https://github.com/stackgl/gl-mat4/blob/master/lookAt.js
function lookAt (eye, center, up) {
var x0, x1, x2, y0, y1, y2, z0, z1, z2, len
var eyex = eye[0]
var eyey = eye[1]
var eyez = eye[2]
var upx = up[0]
var upy = up[1]
var upz = up[2]
var centerx = center[0]
var centery = center[1]
var centerz = center[2]
z0 = eyex - centerx
z1 = eyey - centery
z2 = eyez - centerz
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2)
z0 *= len
z1 *= len
z2 *= len
x0 = upy * z2 - upz * z1
x1 = upz * z0 - upx * z2
x2 = upx * z1 - upy * z0
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2)
if (!len) {
x0 = 0
x1 = 0
x2 = 0
} else {
len = 1 / len
x0 *= len
x1 *= len
x2 *= len
}
y0 = z1 * x2 - z2 * x1
y1 = z2 * x0 - z0 * x2
y2 = z0 * x1 - z1 * x0
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2)
if (!len) {
y0 = 0
y1 = 0
y2 = 0
} else {
len = 1 / len
y0 *= len
y1 *= len
y2 *= len
}
return [
x0, y0, z0, 0,
x1, y1, z1, 0,
x2, y2, z2, 0,
-(x0 * eyex + x1 * eyey + x2 * eyez),
-(y0 * eyex + y1 * eyey + y2 * eyez),
-(z0 * eyex + z1 * eyey + z2 * eyez),
1
]
}
// Taken from gl-mat4
// https://github.com/stackgl/gl-mat4/blob/master/perspective.js
function perspective (fovy, aspect, near, far) {
var f = 1.0 / Math.tan(fovy / 2)
var nf = 1 / (near - far)
return [
f / aspect, 0.0, 0.0, 0.0,
0.0, f, 0.0, 0.0,
0.0, 0.0, (far + near) * nf, -1.0,
0.0, 0.0, (2 * far * near) * nf, 0.0
]
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec2 vUv;
uniform sampler2D tex;
void main () {
gl_FragColor = texture2D(tex,vUv);
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec3 position;
attribute vec2 uv;
varying vec2 vUv;
uniform mat4 projection, view;
void main() {
vUv = uv;
gl_Position = projection * view * vec4(position, 1);
}
</script>
</head>
<body onload="start()">
<canvas id="glcanvas" width="640" height="480">
Your browser doesn't appear to support the <code>&lt;canvas&gt;</code> element.
</canvas>
</body>
</html>
```
#### [stack.gl]()
TODO
#### [gl-react]()
TODO
#### [TWGL]()
TODO
#### [three.js]()
TODO
### Benchmarks

@@ -126,0 +551,0 @@ You can run benchmarks locally using `npm run bench` or check them out here:

@@ -19,2 +19,4 @@ var check = require('./lib/util/check')

var createCore = require('./lib/core')
var createStats = require('./lib/stats')
var createTimer = require('./lib/timer')

@@ -40,8 +42,9 @@ var GL_COLOR_BUFFER_BIT = 16384

var stringStore = createStringStore()
var stats = createStats()
var extensionState = wrapExtensions(gl)
var extensions = extensionState.extensions
var timer = createTimer(gl, extensions)
var START_TIME = clock()
var LAST_TIME = START_TIME
var WIDTH = gl.drawingBufferWidth

@@ -51,4 +54,3 @@ var HEIGHT = gl.drawingBufferHeight

var contextState = {
count: 0,
deltaTime: 0,
tick: 0,
time: 0,

@@ -73,4 +75,4 @@ viewportWidth: WIDTH,

var limits = wrapLimits(gl, extensions)
var bufferState = wrapBuffers(gl)
var elementState = wrapElements(gl, extensions, bufferState)
var bufferState = wrapBuffers(gl, stats)
var elementState = wrapElements(gl, extensions, bufferState, stats)
var attributeState = wrapAttributes(

@@ -82,3 +84,3 @@ gl,

stringStore)
var shaderState = wrapShaders(gl, stringStore)
var shaderState = wrapShaders(gl, stringStore, stats)
var textureState = wrapTextures(

@@ -89,4 +91,5 @@ gl,

poll,
contextState)
var renderbufferState = wrapRenderbuffers(gl, extensions, limits)
contextState,
stats)
var renderbufferState = wrapRenderbuffers(gl, extensions, limits, stats)
var framebufferState = wrapFramebuffers(

@@ -97,3 +100,4 @@ gl,

textureState,
renderbufferState)
renderbufferState,
stats)
var readPixels = wrapRead(gl, poll, contextState)

@@ -114,3 +118,4 @@

drawState,
contextState)
contextState,
timer)

@@ -127,11 +132,11 @@ var nextState = core.next

// increment frame count
contextState.count += 1
contextState.tick += 1
var now = clock()
contextState.deltaTime = (now - LAST_TIME) / 1000.0
contextState.time = (now - START_TIME) / 1000.0
LAST_TIME = now
// Update time
contextState.time = (clock() - START_TIME) / 1000.0
refresh()
// poll for changes
poll()
// fire a callback for all pending rafs
for (var i = 0; i < rafCallbacks.length; ++i) {

@@ -141,2 +146,8 @@ var cb = rafCallbacks[i]

}
// flush all pending webgl calls
gl.flush()
if (timer) {
timer.update()
}
}

@@ -182,4 +193,9 @@

textureState.clear()
elementState.clear()
bufferState.clear()
if (timer) {
timer.clear()
}
if (options.onDestroy) {

@@ -243,4 +259,10 @@ options.onDestroy()

var compiled = core.compile(opts, attributes, uniforms, context)
var stats = {
gpuTime: 0.0,
cpuTime: 0.0,
count: 0
}
var compiled = core.compile(opts, attributes, uniforms, context, stats)
var draw = compiled.draw

@@ -289,7 +311,7 @@ var batch = compiled.batch

return REGLCommand
}
return extend(REGLCommand, {
stats: stats
})
function poll () {
core.procs.poll()
// return REGLCommand
}

@@ -303,5 +325,4 @@

var clearFlags = 0
core.procs.poll()
poll()
var c = options.color

@@ -350,10 +371,9 @@ if (c) {

function refresh () {
// reset viewport
// poll viewport
function pollViewport () {
var viewport = nextState.viewport
var scissorBox = nextState.scissor_box
viewport[0] = viewport[1] = scissorBox[0] = scissorBox[1] = 0
contextState.viewportWidth =
contextState.frameBufferWidth =
contextState.framebufferWidth =
contextState.drawingBufferWidth =

@@ -363,8 +383,19 @@ viewport[2] =

contextState.viewportHeight =
contextState.frameBufferWidth =
contextState.framebufferHeight =
contextState.drawingBufferHeight =
viewport[3] =
scissorBox[3] = gl.drawingBufferHeight
}
function poll () {
pollViewport()
core.procs.poll()
}
function refresh () {
pollViewport()
core.procs.refresh()
if (timer) {
timer.update()
}
}

@@ -419,4 +450,14 @@

_gl: gl,
_refresh: refresh
_refresh: refresh,
poll: function () {
core.procs.poll()
if (timer) {
timer.update()
}
},
// regl Statistics Information
stats: stats
})
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc