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.0.0 to 0.1.0

API.md

55

lib/buffer.js
// Array and element buffer creation
var check = require('./check')
var isTypedArray = require('./is-typed-array')
var bufferTypes = require('./constants/buffer.json')
var usageTypes = require('./constants/usage.json')

@@ -9,7 +8,18 @@ var arrayTypes = require('./constants/arraytypes.json')

var GL_UNSIGNED_BYTE = 5121
var GL_ARRAY_BUFFER = 34962
var GL_ELEMENT_ARRAY_BUFFER = 34963
var GL_STATIC_DRAW = 35044
var GL_FLOAT = 5126
module.exports = function wrapBufferState (gl, extensions) {
function flatten (data, dimension) {
var result = new Float32Array(data.length * dimension)
var ptr = 0
for (var i = 0; i < data.length; ++i) {
var v = data[i]
for (var j = 0; j < dimension; ++j) {
result[ptr++] = v[j]
}
}
return result
}
module.exports = function wrapBufferState (gl) {
var bufferCount = 0

@@ -24,2 +34,3 @@ var bufferSet = {}

this.byteLength = 0
this.dimension = 1
this.data = null

@@ -31,5 +42,3 @@ this.dtype = GL_UNSIGNED_BYTE

bind: function () {
var buffer = this.buffer
check(!!buffer, 'cannot bind deleted buffer')
gl.bindBuffer(this.type, buffer)
gl.bindBuffer(this.type, this.buffer)
},

@@ -60,2 +69,3 @@

var dimension = (options.dimension | 0) || 1
if ('data' in options) {

@@ -68,16 +78,16 @@ var data = options.data

if (Array.isArray(data)) {
if (this.type === GL_ELEMENT_ARRAY_BUFFER) {
if (extensions['oes_element_index_uint']) {
data = new Uint32Array(data)
} else {
data = new Uint16Array(data)
}
if (data.length > 0 && Array.isArray(data[0])) {
dimension = data[0].length
data = flatten(data, dimension)
this.dtype = GL_FLOAT
} else {
data = new Float32Array(data)
this.dtype = GL_FLOAT
}
} else {
check.isTypedArray(data, 'invalid data type buffer data')
this.dtype = arrayTypes[Object.prototype.toString.call(data)]
}
this.dimension = dimension
this.byteLength = data.byteLength
this.dtype = arrayTypes[Object.prototype.toString.call(data)]
}

@@ -106,3 +116,3 @@ this.data = data

check(this.buffer, 'buffer must not be deleted already')
gl.destroyBuffer(this.buffer)
gl.deleteBuffer(this.buffer)
this.buffer = null

@@ -113,21 +123,16 @@ delete bufferSet[this.id]

function createBuffer (options) {
function createBuffer (options, type) {
options = options || {}
var handle = gl.createBuffer()
var type = GL_ARRAY_BUFFER
if ('type' in options) {
check.parameter(type, bufferTypes, 'buffer type')
type = bufferTypes[options.type]
}
var buffer = new REGLBuffer(handle, type)
buffer.update(options)
bufferSet[buffer.id] = buffer
buffer.update(options)
function updateBuffer (options) {
buffer.update(options || {})
return buffer
return updateBuffer
}
updateBuffer._reglType = 'buffer'
updateBuffer._buffer = buffer

@@ -155,3 +160,3 @@ updateBuffer.destroy = function () { buffer.destroy() }

getBuffer: function (wrapper) {
if (wrapper._buffer instanceof REGLBuffer) {
if (wrapper && wrapper._buffer instanceof REGLBuffer) {
return wrapper._buffer

@@ -158,0 +163,0 @@ }

// Error checking and parameter validation
var isTypedArray = require('./is-typed-array')
function extend (Parent, Child, name) {
var proto = Child.prototype = new Parent()
proto.name = name
proto.constructor = Child
}
function REGLError (message) {
this.message = 'REGL Error:\n' + message
this.stack = (new Error()).stack
}
extend(REGLError, Error, 'REGLError')
function raise (message) {
console.error(message)
throw new REGLError(message)
throw new Error(message)
}

@@ -68,3 +56,2 @@

module.exports = Object.assign(check, {
error: REGLError,
raise: raise,

@@ -71,0 +58,0 @@ parameter: checkParameter,

@@ -15,3 +15,3 @@ function slice (x) {

function link (value) {
var name = '_g' + (varCounter++)
var name = 'g' + (varCounter++)
linkedNames.push(name)

@@ -29,4 +29,24 @@ linkedValues.push(value)

var vars = []
function def () {
var name = 'v' + (varCounter++)
vars.push(name)
if (arguments.length > 0) {
code.push(name, '=')
code.push.apply(code, slice(arguments))
code.push(';')
}
return name
}
return Object.assign(push, {
toString: code.join.bind(code, '')
def: def,
toString: function () {
return [
(vars.length > 0 ? 'var ' + vars + ';' : ''),
code.join('')
].join('')
}
})

@@ -40,3 +60,3 @@ }

function arg () {
var name = '_a' + (varCounter++)
var name = 'a' + (varCounter++)
args.push(name)

@@ -46,30 +66,11 @@ return name

var code = []
function push () {
code.push.apply(code, slice(arguments))
}
var body = block()
var bodyToString = body.toString
var vars = []
function def () {
var name = '_v' + (varCounter++)
vars.push(name)
if (arguments.length > 0) {
code.push(name, '=')
code.push.apply(code, slice(arguments))
code.push(';')
}
return name
}
var result = procedures[name] = Object.assign(push, {
var result = procedures[name] = Object.assign(body, {
arg: arg,
def: def,
toString: function () {
return [
'function(', args.join(), '){',
(vars.length > 0 ? 'var ' + vars.join() + ';' : ''),
code.join(''),
bodyToString(),
'}'

@@ -85,3 +86,3 @@ ].join('')

function compile () {
var code = ['return {']
var code = ['"use strict";return {']
Object.keys(procedures).forEach(function (name) {

@@ -88,0 +89,0 @@ code.push('"', name, '":', procedures[name].toString(), ',')

var VARIABLE_COUNTER = 0
function DynamicVariable (type, data) {
function DynamicVariable (isFunc, data) {
this.id = (VARIABLE_COUNTER++)
this.type = type
this.func = isFunc
this.data = data

@@ -11,8 +11,8 @@ }

switch (typeof data) {
case 'boolean':
case 'number':
return new DynamicVariable('arg', data)
case 'string':
return new DynamicVariable('prop', data)
return new DynamicVariable(false, data)
case 'function':
return new DynamicVariable('func', data)
return new DynamicVariable(true, data)
default:

@@ -24,3 +24,4 @@ return defineDynamic

function isDynamic (x) {
return x === defineDynamic || x instanceof DynamicVariable
return (typeof x === 'function' && !x._reglType) ||
x instanceof DynamicVariable
}

@@ -31,4 +32,7 @@

return x
} else if (typeof x === 'function' &&
x !== defineDynamic) {
return new DynamicVariable(true, x)
}
return new DynamicVariable('prop', path)
return new DynamicVariable(false, path)
}

@@ -35,0 +39,0 @@

@@ -1,52 +0,29 @@

// Shader state management
var check = require('./check')
var createEnvironment = require('./codegen')
var DEFAULT_FRAG_SHADER = 'void main(){gl_FragColor=vec4(0,0,0,0);}'
var DEFAULT_VERT_SHADER = 'void main(){gl_Position=vec4(0,0,0,0);}'
var GL_FRAGMENT_SHADER = 35632
var GL_VERTEX_SHADER = 35633
var GL_FLOAT = 5126
var GL_FLOAT_VEC2 = 35664
var GL_FLOAT_VEC3 = 35665
var GL_FLOAT_VEC4 = 35666
var GL_INT = 5124
var GL_INT_VEC2 = 35667
var GL_INT_VEC3 = 35668
var GL_INT_VEC4 = 35669
var GL_BOOL = 35670
var GL_BOOL_VEC2 = 35671
var GL_BOOL_VEC3 = 35672
var GL_BOOL_VEC4 = 35673
var GL_FLOAT_MAT2 = 35674
var GL_FLOAT_MAT3 = 35675
var GL_FLOAT_MAT4 = 35676
function typeLength (x) {
switch (x) {
case GL_FLOAT_VEC2:
case GL_INT_VEC2:
case GL_BOOL_VEC2:
return 2
case GL_FLOAT_VEC3:
case GL_INT_VEC3:
case GL_BOOL_VEC3:
return 3
case GL_FLOAT_VEC4:
case GL_INT_VEC4:
case GL_BOOL_VEC4:
return 4
default:
return 1
}
function ActiveInfo (name, location, info) {
this.name = name
this.location = location
this.info = info
}
module.exports = function wrapShaderState (gl, extensions) {
var NUM_ATTRIBUTES = gl.getParameter(gl.MAX_VERTEX_ATTRIBS)
var INSTANCING = extensions.extensions.angle_instanced_arrays
module.exports = function wrapShaderState (
gl,
extensions,
attributeState,
uniformState,
compileShaderDraw) {
// ===================================================
// shader compilation
// glsl compilation and linking
// ===================================================
var shaders = {}
var fragShaders = [DEFAULT_FRAG_SHADER]
var vertShaders = [DEFAULT_VERT_SHADER]
function getShader (type, source) {

@@ -79,3 +56,3 @@ var cache = shaders[type]

Object.keys(shaders[type]).forEach(function (shader) {
gl.destroyShader(shader)
gl.deleteShader(shaders[type][shader])
})

@@ -93,14 +70,2 @@ })

function UniformInfo (name, location, info) {
this.name = name
this.location = location
this.info = info
}
function AttributeInfo (name, location, info) {
this.name = name
this.location = location
this.info = info
}
function REGLProgram (fragSrc, vertSrc) {

@@ -112,3 +77,4 @@ this.fragSrc = fragSrc

this.attributes = []
this.poll = function () {}
this.draw = function () {}
this.batchCache = {}
}

@@ -146,14 +112,14 @@

var name = info.name.replace('[0]', '[' + j + ']')
uniforms.push(new UniformInfo(
uniforms.push(new ActiveInfo(
name,
gl.getUniformLocation(program, name),
info))
defUniform(name)
uniformState.def(name)
}
} else {
uniforms.push(new UniformInfo(
uniforms.push(new ActiveInfo(
info.name,
gl.getUniformLocation(program, info.name),
info))
defUniform(info.name)
uniformState.def(info.name)
}

@@ -171,7 +137,7 @@ }

if (info) {
attributes.push(new AttributeInfo(
attributes.push(new ActiveInfo(
info.name,
gl.getAttribLocation(program, info.name),
info))
defAttribute(info.name)
attributeState.def(info.name)
}

@@ -181,5 +147,6 @@ }

// -------------------------------
// compile poll()
// clear cached rendering methods
// -------------------------------
this.poll = compileShaderPoll(this)
this.draw = compileShaderDraw(this)
this.batchCache = {}
},

@@ -222,268 +189,6 @@

// ===================================================
// uniform state
// program state
// ===================================================
var uniformState = {}
function defUniform (name) {
if (name in uniformState) {
return
}
uniformState[name] = []
}
// ===================================================
// attribute state
// ===================================================
var attributeState = {}
function AttributeRecord () {
this.pointer = false
this.x = 0.0
this.y = 0.0
this.z = 0.0
this.w = 0.0
this.buffer = null
this.size = 0
this.normalized = false
this.type = GL_FLOAT
this.offset = 0
this.stride = 0
this.divisor = 0
}
Object.assign(AttributeRecord.prototype, {
equals: function (other, size) {
if (this.pointer) {
return other.pointer &&
this.x === other.x &&
this.y === other.y &&
this.z === other.z &&
this.w === other.w
} else {
return !other.pointer &&
this.buffer === other.buffer &&
this.size === size &&
this.normalized === other.normalized &&
this.type === other.type &&
this.offset === other.offset &&
this.stride === other.stride &&
this.divisor === other.divisor
}
},
set: function (other, size) {
var pointer = this.pointer = other.pointer
if (pointer) {
this.buffer = other.buffer
this.size = size
this.normalized = other.normalized
this.type = other.type
this.offset = other.offset
this.stride = other.stride
this.divisor = other.divisor
} else {
this.x = other.x
this.y = other.y
this.z = other.z
this.w = other.w
}
}
})
function AttributeStack () {
var records = new Array(16)
for (var i = 0; i < 16; ++i) {
records[i] = new AttributeRecord()
}
this.records = records
this.top = 0
}
function pushAttributeStack (stack) {
var records = stack.records
var top = stack.top
while (records.length - 1 <= top) {
records.push(new AttributeRecord())
}
return records[++stack.top]
}
Object.assign(AttributeStack.prototype, {
pushVec: function (x, y, z, w) {
var head = pushAttributeStack(this)
head.pointer = false
head.x = x
head.y = y
head.z = z
head.w = w
},
pushPtr: function (
buffer,
size,
offset,
stride,
divisor,
normalized,
type) {
var head = pushAttributeStack(this)
head.pointer = true
head.buffer = buffer
head.size = size
head.offset = offset
head.stride = stride
head.divisor = divisor
head.normalized = normalized
head.type = type
},
pop: function () {
this.top -= 1
}
})
function defAttribute (name) {
if (name in attributeState) {
return
}
attributeState[name] = new AttributeStack()
}
var attributeBindings = new Array(NUM_ATTRIBUTES)
for (var i = 0; i < NUM_ATTRIBUTES; ++i) {
attributeBindings[i] = new AttributeRecord()
}
function bindAttribute (index, current, stack, size) {
var next = stack.records[stack.top]
size = next.size || size
if (current.equals(next, size)) {
return
}
if (!next.pointer) {
if (current.pointer) {
gl.disableVertexAttribArray(index)
}
gl.vertexAttrib4f(index, next.x, next.y, next.z, next.w)
} else {
if (!current.pointer) {
gl.enableVertexAttribArray(index)
}
if (current.buffer !== next.buffer) {
next.buffer.bind()
}
gl.vertexAttribPointer(
index,
size,
next.type,
next.normalized,
next.stride,
next.offset)
if (INSTANCING) {
INSTANCING.vertexAttribDivisorANGLE(index, next.divisor)
}
}
current.set(next, size)
}
// ===================================================
// state diffing/polling
// ===================================================
function compileShaderPoll (program) {
var env = createEnvironment()
var link = env.link
var poll = env.proc('poll')
var GL = link(gl)
var PROGRAM = link(program.program)
var BIND_ATTRIBUTE = link(bindAttribute)
// bind the program
poll(GL, '.useProgram(', PROGRAM, ');')
// set up attribute state
program.attributes.forEach(function (attribute) {
poll(BIND_ATTRIBUTE, '(',
attribute.location, ',',
link(attributeBindings[attribute.location]), ',',
link(attributeState[attribute.name]), ',',
typeLength(attribute.info.type), ');')
})
// set up uniforms
program.uniforms.forEach(function (uniform) {
var LOCATION = link(uniform.location)
var STACK = link(uniformState[uniform.name])
var TOP = STACK + '[' + STACK + '.length-1]'
var infix
var separator = ','
switch (uniform.info.type) {
case GL_FLOAT:
infix = '1f'
break
case GL_FLOAT_VEC2:
infix = '2f'
break
case GL_FLOAT_VEC3:
infix = '3f'
break
case GL_FLOAT_VEC4:
infix = '4f'
break
case GL_BOOL:
case GL_INT:
infix = '1i'
break
case GL_BOOL_VEC2:
case GL_INT_VEC2:
infix = '2i'
break
case GL_BOOL_VEC3:
case GL_INT_VEC3:
infix = '3i'
break
case GL_BOOL_VEC4:
case GL_INT_VEC4:
infix = '4i'
break
case GL_FLOAT_MAT2:
infix = 'Matrix2f'
separator = ',true,'
break
case GL_FLOAT_MAT3:
infix = 'Matrix3f'
separator = ',true,'
break
case GL_FLOAT_MAT4:
infix = 'Matrix4f'
separator = ',true,'
break
default:
check.raise('unsupported uniform type')
}
poll(GL, '.uniform', infix, 'v(', LOCATION, separator, TOP, ');')
})
return env.compile().poll
}
// ===================================================
// context management
// ===================================================
var programState = [null]
function poll () {
var activeShader = programState[programState.length - 1]
if (activeShader) {
activeShader.poll()
} else {
gl.useProgram(null)
}
}
// ===================================================

@@ -507,15 +212,8 @@ // context management

create: getProgram,
clear: clear,
refresh: refresh,
poll: poll,
programs: programState,
uniforms: uniformState,
defUniform: defUniform,
attributes: attributeState,
defAttribute: defAttribute
fragShaders: fragShaders,
vertShaders: vertShaders
}
}

@@ -39,16 +39,11 @@ // A stack for managing the state of a scalar/vector parameter

push: function () {
var ptr = stack.length - n
for (var i = 0; i < n; ++i) {
var value = arguments[i]
dirty = dirty || (stack[ptr + i] === value)
stack.push(value)
stack.push(arguments[i])
}
dirty = true
},
pop: function () {
var ptr = stack.length - 2 * n
for (var i = 0; i < n; ++i) {
var top = stack.pop()
dirty = dirty || top === stack[ptr + i]
}
stack.length -= n
dirty = true
},

@@ -55,0 +50,0 @@

var createStack = require('./stack')
var check = require('./check')
var createEnvironment = require('./codegen')
var primTypes = require('./constants/primitives.json')
var glTypes = require('./constants/dtypes.json')

@@ -26,20 +23,6 @@ // WebGL constants

var GL_KEEP = 7680
var GL_TRIANGLES = 4
var GL_FLOAT = 5126
var DEFAULT_FRAG_SHADER = 'void main(){gl_FragColor=vec4(0,0,0,0);}'
var DEFAULT_VERT_SHADER = 'void main(){gl_Position=vec4(0,0,0,0);}'
module.exports = function wrapContextState (
gl,
extensions,
shaderState,
bufferState,
textureState,
fboState) {
var extInstancing = extensions.extensions.angle_instanced_arrays
var hasInstancing = !!extInstancing
function capStack (cap) {
return createStack([false], function (flag) {
module.exports = function wrapContextState (gl, shaderState) {
function capStack (cap, dflt) {
var result = createStack([!!dflt], function (flag) {
if (flag) {

@@ -51,28 +34,25 @@ gl.enable(cap)

})
result.flag = cap
return result
}
// Draw state
var primitiveState = [ GL_TRIANGLES ]
var countState = [ 0 ]
var offsetState = [ 0 ]
var instancesState = [ 0 ]
var viewportState = {
width: 0,
height: 0
}
// Caps, flags and other random WebGL context state
var contextState = {
// Caps
cull: capStack(GL_CULL_FACE),
blend: capStack(GL_BLEND),
dither: capStack(GL_DITHER),
stencilTest: capStack(GL_STENCIL_TEST),
depthTest: capStack(GL_DEPTH_TEST),
scissorTest: capStack(GL_SCISSOR_TEST),
polygonOffsetFill: capStack(GL_POLYGON_OFFSET_FILL),
sampleAlpha: capStack(GL_SAMPLE_ALPHA_TO_COVERAGE),
sampleCoverage: capStack(GL_SAMPLE_COVERAGE),
// Dithering
'dither': capStack(GL_DITHER),
// Blending
blendEquation: createStack([GL_FUNC_ADD, GL_FUNC_ADD], function (rgb, a) {
'blend.enable': capStack(GL_BLEND),
'blend.color': createStack([0, 0, 0, 0], function (r, g, b, a) {
gl.blendColor(r, g, b, a)
}),
'blend.equation': createStack([GL_FUNC_ADD, GL_FUNC_ADD], function (rgb, a) {
gl.blendEquationSeparate(rgb, a)
}),
blendFunc: createStack([
'blend.func': createStack([
GL_ONE, GL_ZERO, GL_ONE, GL_ZERO

@@ -84,14 +64,21 @@ ], function (srcRGB, dstRGB, srcAlpha, dstAlpha) {

// Depth
depthFunc: createStack([GL_LESS], function (func) {
'depth.enable': capStack(GL_DEPTH_TEST, true),
'depth.func': createStack([GL_LESS], function (func) {
gl.depthFunc(func)
}),
depthRange: createStack([0, 1], function (near, far) {
'depth.range': createStack([0, 1], function (near, far) {
gl.depthRange(near, far)
}),
'depth.mask': createStack([true], function (m) {
gl.depthMask(m)
}),
// Face culling
cullFace: createStack([GL_BACK], function (mode) {
'cull.enable': capStack(GL_CULL_FACE),
'cull.face': createStack([GL_BACK], function (mode) {
gl.cullFace(mode)
}),
frontFace: createStack([GL_CCW], function (mode) {
// Front face orientation
'frontFace': createStack([GL_CCW], function (mode) {
gl.frontFace(mode)

@@ -101,15 +88,8 @@ }),

// Write masks
colorMask: createStack([true, true, true, true], function (r, g, b, a) {
'colorMask': createStack([true, true, true, true], function (r, g, b, a) {
gl.colorMask(r, g, b, a)
}),
depthMask: createStack([true], function (m) {
gl.depthMask(m)
}),
stencilMask: createStack([-1, -1], function (front, back) {
gl.stencilMask(GL_FRONT, front)
gl.stencilMask(GL_BACK, back)
}),
// Line width
lineWidth: createStack([1], function (w) {
'lineWidth': createStack([1], function (w) {
gl.lineWidth(w)

@@ -119,3 +99,4 @@ }),

// Polygon offset
polygonOffset: createStack([0, 0], function (factor, units) {
'polygonOffset.enable': capStack(GL_POLYGON_OFFSET_FILL),
'polygonOffset.offset': createStack([0, 0], function (factor, units) {
gl.polygonOffset(factor, units)

@@ -125,3 +106,5 @@ }),

// Sample coverage
sampleCoverageParams: createStack([1, false], function (value, invert) {
'sample.alpha': capStack(GL_SAMPLE_ALPHA_TO_COVERAGE),
'sample.enable': capStack(GL_SAMPLE_COVERAGE),
'sample.coverage': createStack([1, false], function (value, invert) {
gl.sampleCoverage(value, invert)

@@ -131,373 +114,73 @@ }),

// Stencil
stencilFunc: createStack([
GL_ALWAYS, 0, -1,
'stencil.enable': capStack(GL_STENCIL_TEST),
'stencil.mask': createStack([-1], function (mask) {
gl.stencilMask(mask)
}),
'stencil.func': createStack([
GL_ALWAYS, 0, -1
], function (frontFunc, frontRef, frontMask,
backFunc, backRef, backMask) {
gl.stencilFuncSeparate(GL_FRONT, frontFunc, frontRef, frontMask)
gl.stencilFuncSeparate(GL_BACK, backFunc, backRef, backMask)
], function (func, ref, mask) {
gl.stencilFunc(func, ref, mask)
}),
stencilOp: createStack([
GL_KEEP, GL_KEEP, GL_KEEP,
'stencil.opFront': createStack([
GL_KEEP, GL_KEEP, GL_KEEP
], function (frontFail, frontDPFail, frontPass,
backFail, backDPFail, backPass) {
gl.stencilOpSeparate(GL_FRONT, frontFail, frontDPFail, frontPass)
gl.stencilOpSeparate(GL_BACK, backFail, backDPFail, backPass)
], function (fail, zfail, pass) {
gl.stencilOpSeparate(GL_FRONT, fail, zfail, pass)
}),
'stencil.opBack': createStack([
GL_KEEP, GL_KEEP, GL_KEEP
], function (fail, zfail, pass) {
gl.stencilOpSeparate(GL_BACK, fail, zfail, pass)
}),
// Scissor
scissor: createStack([0, 0, -1, -1], function (x, y, w, h) {
gl.scissor(
x, y,
w < 0 ? gl.drawingBufferWidth : w,
h < 0 ? gl.drawingBufferHeight : h)
'scissor.enable': capStack(GL_SCISSOR_TEST),
'scissor.box': createStack([0, 0, -1, -1], function (x, y, w, h) {
var w_ = w
if (w < 0) {
w_ = gl.drawingBufferWidth - x
}
var h_ = h
if (h < 0) {
h_ = gl.drawingBufferHeight - y
}
gl.scissor(x, y, w_, h_)
}),
// Viewport
viewport: createStack([0, 0, -1, -1], function (x, y, w, h) {
gl.viewport(
x, y,
w < 0 ? gl.drawingBufferWidth : w,
h < 0 ? gl.drawingBufferHeight : h)
})
// TODO: textures
// TODO: fbos
// TODO: extensions
}
var contextProps = Object.keys(contextState)
function refreshState () {
contextProps.forEach(function (state) {
contextState[state].setDirty()
})
}
// ==========================================================
// Update state bindings
// ==========================================================
function poll () {
shaderState.poll()
contextProps.forEach(function (state) {
contextState[state].poll()
})
}
// ==========================================================
// Partially evaluate a draw command
// ==========================================================
function partialEvaluateCommand (
staticOptions, staticUniforms, staticAttributes,
dynamicOptions, dynamicUniforms, dynamicAttributes,
hasDynamic) {
// Create code generation environment
var env = createEnvironment()
var link = env.link
var block = env.block
var proc = env.proc
// Helper functions
function stackTop (x) {
return x + '[' + x + '.length-1]'
}
// -------------------------------
// Common state variables
// -------------------------------
var GL = link(gl)
var POLL = link(poll)
var PROGRAM_STATE = link(shaderState.programs)
var DRAW_STATE = {
count: link(countState),
offset: link(offsetState),
instances: link(instancesState),
primitive: link(primitiveState)
}
var CONTEXT_STATE = {}
function linkContext (x) {
var result = CONTEXT_STATE[x]
if (result) {
return result
'viewport': createStack([0, 0, -1, -1], function (x, y, w, h) {
var w_ = w
if (w < 0) {
w_ = gl.drawingBufferWidth - x
}
result = CONTEXT_STATE[x] = link(contextState[x])
return result
}
// ==========================================================
// STATIC STATE
// ==========================================================
// Code blocks for the static sections
var entry = block()
var exit = block()
// -------------------------------
// update default context state variables
// -------------------------------
function handleStaticOption (param, value) {
var STATE_STACK = linkContext(param)
entry(STATE_STACK, '.push(', value, ');')
exit(STATE_STACK, '.pop();')
}
var hasShader = false
Object.keys(staticOptions).forEach(function (param) {
switch (param) {
case 'frag':
case 'vert':
hasShader = true
break
// Update draw state
case 'count':
case 'offset':
case 'instances':
var value = staticOptions[param]
check.nni(value, param)
entry(DRAW_STATE[param], '.push(', value, ');')
exit(DRAW_STATE[param], '.pop();')
break
// Update primitive type
case 'primitive':
check.parameter(staticOptions[param], primTypes,
'not a valid drawing primitive')
var primType = primTypes[staticOptions[param]]
entry(DRAW_STATE.primitive, '.push(', primType, ');')
exit(DRAW_STATE.primitive, '.pop();')
break
// Caps
case 'cull':
case 'blend':
case 'dither':
case 'stencilTest':
case 'depthTest':
case 'scissorTest':
case 'polygonOffsetFill':
case 'sampleAlpha':
case 'sampleCoverage':
case 'stencilMask':
case 'depthMask':
var flag = staticOptions[param]
check.type(flag, 'boolean', param)
handleStaticOption(param, staticOptions[param])
break
// TODO Handle the rest of the state values here
default:
// TODO Should this just be a warning instead?
check.raise('unsupported parameter ' + param)
break
var h_ = h
if (h < 0) {
h_ = gl.drawingBufferHeight - y
}
gl.viewport(x, y, w_, h_)
viewportState.width = w_
viewportState.height = h_
})
}
// -------------------------------
// update shader program
// -------------------------------
var program
if (hasShader) {
var fragSrc = staticOptions.frag || DEFAULT_FRAG_SHADER
var vertSrc = staticOptions.vert || DEFAULT_VERT_SHADER
program = shaderState.create(vertSrc, fragSrc)
entry(PROGRAM_STATE, '.push(', link(program), ');')
exit(PROGRAM_STATE, '.pop();')
}
var env = createEnvironment()
var poll = env.proc('poll')
var refresh = env.proc('refresh')
Object.keys(contextState).forEach(function (prop) {
var STACK = env.link(contextState[prop])
poll(STACK, '.poll();')
refresh(STACK, '.setDirty();')
})
var procs = env.compile()
// -------------------------------
// update static uniforms
// -------------------------------
Object.keys(staticUniforms).forEach(function (uniform) {
shaderState.defUniform(uniform)
var STACK = link(shaderState.uniforms[uniform])
var VALUE
var value = staticUniforms[uniform]
if (Array.isArray(value)) {
VALUE = link(value.slice())
} else {
VALUE = link([value])
}
entry(STACK, '.push(', VALUE, ');')
exit(STACK, '.pop();')
})
return {
contextState: contextState,
viewport: viewportState,
poll: procs.poll,
refresh: procs.refresh,
// -------------------------------
// update default attributes
// -------------------------------
Object.keys(staticAttributes).forEach(function (attribute) {
shaderState.defAttribute(attribute)
var ATTRIBUTE = link(shaderState.attributes[attribute])
var data = staticAttributes[attribute]
if (typeof data === 'number') {
entry(ATTRIBUTE, '.pushVec(', +data, ',0,0,0);')
} else {
check(!!data, 'invalid attribute: ' + attribute)
if (Array.isArray(data)) {
entry(
ATTRIBUTE, '.pushVec(',
[data[0] || 0, data[1] || 0, data[2] || 0, data[3] || 0], ');')
} else {
var buffer = bufferState.getBuffer(data)
var size = 0
var stride = 0
var offset = 0
var divisor = 0
var normalized = false
var type = GL_FLOAT
if (!buffer) {
check.type(data, 'object', 'invalid attribute "' + attribute + '"')
buffer = bufferState.getBuffer(data.buffer)
size = data.size || 0
stride = data.stride || 0
offset = data.offset || 0
divisor = data.divisor || 0
normalized = data.normalized || false
check(!!buffer, 'invalid attribute ' + attribute + '.buffer')
// Check for user defined type overloading
type = buffer.dtype
if ('type' in data) {
check.parameter(data.type, glTypes, 'attribute type')
type = glTypes[data.type]
}
} else {
type = buffer.dtype
}
check(!!buffer, 'invalid attribute ' + attribute + '.buffer')
check.nni(stride, attribute + '.stride')
check.nni(offset, attribute + '.offset')
check.nni(divisor, attribute + '.divisor')
check.type(normalized, 'boolean', attribute + '.normalized')
check.oneOf(size, [0, 1, 2, 3, 4], attribute + '.size')
entry(
ATTRIBUTE, '.pushPtr(', [
link(buffer), size, offset, stride,
divisor, normalized, type
].join(), ');')
}
}
exit(ATTRIBUTE, '.pop();')
})
// ==========================================================
// DYNAMIC STATE
// ==========================================================
// Generated code blocks for dynamic state flags
var dynamicEntry = env.block()
var dynamicExit = env.block()
// -------------------------------
// dynamic context state variables
// -------------------------------
Object.keys(dynamicOptions).forEach(function (param) {
switch (param) {
// Caps
case 'cull':
case 'blend':
case 'dither':
case 'stencilTest':
case 'depthTest':
case 'scissorTest':
case 'polygonOffsetFill':
case 'sampleAlpha':
case 'sampleCoverage':
case 'stencilMask':
case 'depthMask':
break
default:
break
}
})
// -------------------------------
// dynamic uniforms
// -------------------------------
// -------------------------------
// dynamic attributes
// -------------------------------
// ==========================================================
// SCOPE PROCEDURE
// ==========================================================
var scope = proc('scope')
var BODY = scope.arg()
scope(
entry,
hasDynamic ? dynamicEntry : '',
BODY, '();',
hasDynamic ? dynamicExit : '',
exit)
// ==========================================================
// DRAW PROCEDURE
// ==========================================================
var draw = proc('draw')
draw(
entry,
hasDynamic ? dynamicEntry : '',
POLL, '();')
// Generate draw command
var CUR_PRIMITIVE = stackTop(DRAW_STATE.primitive)
var CUR_COUNT = stackTop(DRAW_STATE.count)
var CUR_OFFSET = stackTop(DRAW_STATE.offset)
if (hasInstancing) {
var CUR_INSTANCES = draw.def(stackTop(DRAW_STATE.instances))
draw(
'if(', CUR_INSTANCES, '>0){',
// then
GL, '.drawArraysInstancedANGLE(',
CUR_PRIMITIVE, ',',
CUR_OFFSET, ',',
CUR_COUNT, ',',
CUR_INSTANCES, ');}else{',
// else
GL, '.drawArrays(',
CUR_PRIMITIVE, ',',
CUR_OFFSET, ',',
CUR_COUNT, ');}')
} else {
draw(
GL, '.drawArrays(',
CUR_PRIMITIVE, ',',
CUR_OFFSET, ',',
CUR_COUNT, ');')
notifyViewportChanged: function () {
contextState.viewport.setDirty()
contextState['scissor.box'].setDirty()
}
draw(
hasDynamic ? dynamicExit : '',
exit)
// ==========================================================
// BATCH DRAW
// ==========================================================
if (hasDynamic) {
// TODO
}
// -------------------------------
// eval and bind
// -------------------------------
return env.compile()
}
return {
create: partialEvaluateCommand,
refresh: refreshState
}
}

@@ -1,2 +0,60 @@

module.exports = function createTextureSet (gl) {
var check = require('./check')
var GL_TEXTURE_2D = 0x0DE1
var GL_DEPTH_COMPONENT = 0x1902
var GL_ALPHA = 0x1906
var GL_RGB = 0x1907
var GL_RGBA = 0x1908
var GL_LUMINANCE = 0x1909
var GL_LUMINANCE_ALPHA = 0x190A
var GL_UNSIGNED_BYTE = 0x1401
var GL_UNSIGNED_SHORT = 0x1403
var GL_FLOAT = 0x1406
var GL_TEXTURE_WRAP_S = 0x2802
var GL_TEXTURE_WRAP_T = 0x2803
var GL_REPEAT = 0x2901
var GL_CLAMP_TO_EDGE = 0x812F
var GL_MIRRORED_REPEAT = 0x8370
var GL_TEXTURE_MAG_FILTER = 0x2800
var GL_TEXTURE_MIN_FILTER = 0x2801
var GL_NEAREST = 0x2600
var GL_LINEAR = 0x2601
var GL_NEAREST_MIPMAP_NEAREST = 0x2700
var GL_LINEAR_MIPMAP_NEAREST = 0x2701
var GL_NEAREST_MIPMAP_LINEAR = 0x2702
var GL_LINEAR_MIPMAP_LINEAR = 0x2703
var GL_UNPACK_FLIP_Y_WEBGL = 0x9240
var GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241
var GL_UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243
var GL_BROWSER_DEFAULT_WEBGL = 0x9244
var wrapModes = {
'repeat': GL_REPEAT,
'clamp': GL_CLAMP_TO_EDGE,
'mirror': GL_MIRRORED_REPEAT
}
var magFilters = {
'nearest': GL_NEAREST,
'linear': GL_LINEAR
}
var minFilters = Object.assign({
'nearest mipmap nearest': GL_NEAREST_MIPMAP_NEAREST,
'linear mipmap nearest': GL_LINEAR_MIPMAP_NEAREST,
'nearest mipmap linear': GL_NEAREST_MIPMAP_LINEAR,
'linear mipmap linear': GL_LINEAR_MIPMAP_LINEAR,
'mipmap': GL_LINEAR_MIPMAP_LINEAR
}, magFilters)
module.exports = function createTextureSet (gl, extensionState) {
var extensions = extensionState.extensions
var textureCount = 0

@@ -7,2 +65,31 @@ var textureSet = {}

this.id = textureCount++
// Texture target
this.target = GL_TEXTURE_2D
// Texture handle
this.texture = null
// Texture format
this.format = GL_RGBA
this.type = GL_UNSIGNED_BYTE
// Data
this.mipLevels = []
// Shape
this.width = 0
this.height = 0
// Parameters
this.minFilter = GL_NEAREST
this.magFilter = GL_NEAREST
this.wrapS = GL_REPEAT
this.wrapT = GL_REPEAT
this.mipSamples = 0
// Storage flags
this.flipY = false
this.premultiplyAlpha = false
this.colorSpace = GL_BROWSER_DEFAULT_WEBGL
}

@@ -14,9 +101,54 @@

update: function (option) {
update: function (args) {
var options = args || {}
// Possible initialization pathways:
if (Array.isArray(args) ||
isTypedArray(args) ||
isHTMLElement(args)) {
options = {
data: args
}
}
var data = options.data || null
var width = options.width || 0
var height = options.height || 0
var format = options.format || 'rgba'
this.minFilter = GL_NEAREST
if ('min' in options) {
check.param(options.min, minFilters)
this.minFilter = minFilters[options.min]
}
this.magFilter = GL_NEAREST
if ('mag' in options) {
check.param(options.mag, magFilters)
this.magFilter = magFilters(options.mag)
}
if (Array.isArray(data)) {
} else if (isTypedArray(data)) {
} else if (isHTMLElement(data)) {
}
// Set tex image
},
refresh: function () {
gl.textureParameteri(GL_TEXTURE_MIN_FILTER, this.minFilter)
gl.textureParameteri(GL_TEXTURE_MAG_FILTER, this.magFilter)
gl.textureParameteri(GL_TEXTURE_WRAP_T, this.wrapT)
gl.textureParameteri(GL_TEXTURE_WRAP_S, this.wrapS)
},
destroy: function () {
check(this.texture, 'must not double free texture')
gl.deleteTexture(this.texture)
this.texture = null
delete textureSet[this.id]
}

@@ -26,3 +158,18 @@ })

function createTexture (options) {
return null
var texture = new REGLTexture()
texture.texture = gl.createTexture()
texture.update(options)
textureSet[texture.id] = texture
function updateTexture (options) {
texture.update(options)
return updateTexture
}
updateTexture._texture = texture
updateTexture.destroy = function () {
texture.destroy()
}
return updateTexture
}

@@ -45,3 +192,3 @@

refresh: refreshTextures,
destroy: destroyTextures,
clear: destroyTextures,
getTexture: function (wrapper) {

@@ -48,0 +195,0 @@ return null

{
"name": "regl",
"version": "0.0.0",
"description": "Dataflow programming for WebGL",
"version": "0.1.0",
"description": "WebGL",
"main": "regl.js",

@@ -9,11 +9,29 @@ "directories": {

},
"dependencies": {},
"devDependencies": {
"browserify": "^13.0.0",
"budo": "^8.1.0",
"coverify": "^1.4.1",
"derequire": "^2.0.3",
"faucet": "0.0.1",
"gl": "^3.0.3",
"indexhtmlify": "^1.2.1",
"runscript": "^1.1.0",
"smokestack": "^3.4.1",
"snazzy": "^3.0.0",
"standard": "^6.0.7",
"tape": "^4.4.0"
"tap-browser-color": "^0.1.2",
"tape": "^4.4.0",
"uglify-js": "^2.6.2"
},
"dependencies": {
"gl-format-compiler-error": "^1.0.2"
},
"scripts": {
"test": "standard && tape test/*.js"
"test": "standard | snazzy && tape test/*.js | faucet",
"test-browser": "budo test/util/browser.js --open",
"coverage": "browserify test/util/browser.js -t coverify | smokestack | coverify",
"bench": "budo bench/index.js --open",
"build": "npm run build-script && npm run build-min && npm run build-bench && npm run build-gallery",
"build-script": "browserify regl.js -s regl | derequire > dist/regl.js",
"build-min": "uglifyjs < dist/regl.js > dist/regl.min.js",
"build-bench": "browserify bench/index.js | indexhtmlify > www/bench.html",
"build-gallery": "node bin/build-gallery.js"
},

@@ -30,3 +48,3 @@ "repository": {

"graphics",
"cg",
"computer graphics",
"opengl",

@@ -44,3 +62,6 @@ "glsl",

},
"homepage": "https://github.com/mikolalysenko/regl#readme"
"standard": {
"ignore": "dist/*"
},
"homepage": "https://mikolalysenko.github.io/regl"
}
# New abstractions for WebGL
The high level goal of stack.gl is to deconstruct a 3D engine into reusable, interchangeable, composable modules. More precisely, we mean that a module is,
The high level goal of stack.gl is to deconstruct a 3D engine into modules. Ideally these modules should be
* *Reusable* if it can be extracted from its original environment and used again
* *Interchangeable* if it can be replaced with a module having an equivalent interface
* *Composable* if it is composed itself of simpler, smaller modules
* *Reusable*: if it can be extracted from its original environment and used again
* *Interchangeable*: if it can be replaced with a module having an equivalent interface
* *Composable*: if it is composed itself of simpler, smaller modules

@@ -81,3 +81,3 @@ stack.gl is a loosely coupled collection of modules that communicate using standard interfaces. At a high level, there are three basic parts of stack.gl,

## Rendering as change detection
## Functional rendering
Thinking in terms of data flow reframes the problem of rendering as detecting changes in the properties of the `render()` function.

@@ -84,0 +84,0 @@

# regl
[![Circle CI](https://circleci.com/gh/mikolalysenko/regl.svg?style=svg)](https://circleci.com/gh/mikolalysenko/regl) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
This repo is an attempt at building some new functional abstractions for working with WebGL. It is still pretty experimental right now, so expect things to change a lot in the near future. If you want to know more about why I am writing this thing, take a look at the [rationale](RATIONALE.md).
This repo is an attempt at building new functional abstractions for working with WebGL. It is still **experimental**, so expect things to change a lot in the near future! If you want to know more about why I am writing this thing and why it looks the way it does, take a look at the [rationale](RATIONALE.md).
## Some sketches
### Why use regl
In regl, you write functions which transform data into sequences of WebGL draw calls. These functions are then partially evaluated at run time into optimized JavaScript code. Here is a sketch of how this might look:
`regl` offers the following advantages over raw WebGL code:
* **Just one function**
* **Less state** Draw commands in regl are self contained, so you don't have to worry about some other weird subroutine breaking your rendering code
* **No `bind()`** In regl, shaders, buffers, textures and fbos are specified declaratively, so there is no need to ever `bind()` them or unbind them.
* **Fewer silent failure** If you pass incorrect parameters to some WebGL method, the default behavior is to set an error code and continue on. Because `regl` commands have more structure, we can do more validation up front without the run time performance cost.
* **Sane defaults** Many WebGL APIs have redundant or outright broken parameters (for example `border` in `gl.texImage2D` or `transpose` in `gl.uniformMatrix4fv`). `regl` wraps these APIs in such a way that you will never have to see this mess.
## Simple example
In `regl`, there are two fundamental abstractions, **resources** and **commands**:
* A **resource** is a handle to a GPU resident object, like a texture, FBO or buffer.
* A **command** is a complete representation of the WebGL state required to perform some draw call.
To define a command you specify a mixture of static and dynamic data for the object. Once this is done, `regl` takes this description and then compiles it into optimized JavaScript code. For example, here is a simple `regl` program to draw a colored triangle:
```JavaScript
// NOTE: This doesn't work yet, it is just for illustration
// Calling the regl module with no arguments creates a full screen canvas and
// WebGL context, and then uses this context to initialize a new REGL instance
const regl = require('regl')()
// This creates a new partially evaluated draw call. We flag the dynamic
// parts of the draw call using the special `regl.dynamic` variable
const draw = regl({
// Calling regl() creates a new partially evaluated draw command
const drawTriangle = regl({
// Shaders in regl are just strings. You can use glslify or whatever you want
// to define them. No need to manually create shader objects.
frag: `

@@ -31,15 +49,23 @@ precision mediump float;

// Here we define the vertex attributes for the above shader
attributes: {
position: regl.buffer(new Float32Array([-2, -2, 4, -2, 4, 4]))
// regl.buffer creates a new array buffer object
position: regl.buffer([
[-2, -2], // no need to flatten nested arrays, regl automatically
[4, -2], // unrolls them into a typedarray (default Float32)
[4, 4]
]))
// regl automatically infers sane defaults for the vertex attribute pointers
},
uniforms: {
// This makes the color uniform dynamic
color: regl.dynamic
// This defines the color of the triangle to be a dynamic variable
color: regl.prop('color')
},
// This tells regl the number of vertices to draw in this command
count: 3
}).draw
})
function render() {
regl.frame(() => {
// clear contents of the drawing buffer

@@ -51,65 +77,111 @@ regl.clear({

// draw a triangle
// draw a triangle using the command defined above
drawTriangle({
uniforms: {
color: [
Math.cos(Date.now() * 0.001),
Math.sin(Date.now() * 0.0008),
Math.cos(Date.now() * 0.003),
1
]
}
color: [
Math.cos(Date.now() * 0.001),
Math.sin(Date.now() * 0.0008),
Math.cos(Date.now() * 0.003),
1
]
})
// schedule next render event
requestAnimationFrame(render)
}
render()
})
```
# API (WORK IN PROGRESS)
## More examples
## Constructors
[Check out the demo gallery](https://mikolalysenko.github.io/regl/www/gallery.html)
#### `var regl = require('regl')([options])`
## Setup
#### `var regl = require('regl')(element, [options])`
regl has no dependencies, so setting it up is pretty easy
#### `var regl = require('regl')(canvas, [options])`
#### Live editing
To try out regl right away, you can use [RequireBin](http://requirebin.com/) or [codepen](http://codepen.io/). The following links should help get you started:
#### `var regl = require('regl')(gl, [options])`
* requirebin
* codepen
## Resources
#### npm
The easiest way to use `regl` in a project is via [npm](http://npmjs.com). Once you have node set up, you can install and use `regl` in your project using the following command:
### Resource constructors
```sh
npm i -S regl
```
#### `regl.buffer(options)`
For more info on how to use npm, [check out the official docs](https://docs.npmjs.com/).
#### `regl.texture(options)`
#### Standalone script tag
You can also use `regl` as a standalone script if you are really stubborn. The most recent versions can be found under the [releases tab](releases). To do this, add the following script tag to your HTML:
#### `regl.fbo(options)`
```html
<script src="[some cdn tbd]/regl.min.js"></script>
```
### Resource methods
## Comparisons
#### `resource(options)`
Updates a resource
TODO implement spinning textured cube in each of the following frameworks
#### `resource.destroy()`
Destroy resource
* vs WebGL
* vs gl-* modules from stack.gl
* vs TWGL
* vs THREE.js
## Rendering
## Benchmarks
You can run benchmarks locally using `npm run bench` or check them out here:
#### `regl(options)`
* [Interactive benchmarks](https://mikolalysenko.github.io/regl/www/bench.html)
## Clean up
## [API](API.md)
* [Initialization](API.md#initialization)
* [As a fullscreen canvas](API.md#as-a-fullscreen-canvas)
* [From a container div](API.md#from-a-container-div)
* [From a canvas](API.md#from-a-canvas)
* [From a WebGL context](API.md#from-a-webgl-context)
* [Commands](API.md#commands)
+ [Dynamic properties](API.md#dynamic-properties)
+ [Executing commands](API.md#executing-commands)
- [One-shot rendering](API.md#one-shot-rendering)
- [Batch rendering](API.md#batch-rendering)
- [Scoped parameters](API.md#scoped-parameters)
+ [Parameters](API.md#parameters)
- [Shaders](API.md#shaders)
- [Uniforms](API.md#uniforms)
- [Attributes](API.md#attributes)
- [Drawing](API.md#drawing)
- [Framebuffer](API.md#framebuffer)
- [Depth buffer](API.md#depth-buffer)
- [Blending](API.md#blending)
- [Stencil](API.md#stencil)
- [Polygon offset](API.md#polygon-offset)
- [Culling](API.md#culling)
- [Front face](API.md#front-face)
- [Dithering](API.md#dithering)
- [Line width](API.md#line-width)
- [Color mask](API.md#color-mask)
- [Sample coverage](API.md#sample-coverage)
- [Scissor](API.md#scissor)
- [Viewport](API.md#viewport)
* [Resources](API.md#resources)
+ [Basic usage](API.md#basic-usage)
- [Updating a resource](API.md#updating-a-resource)
- [Destroying a resource](API.md#destroying-a-resource)
+ [Types](API.md#types)
- [`regl.buffer(options)`](API.md#-reglbuffer-options--)
- [`regl.elements(options)`](API.md#-reglelements-options--)
* [Other features](API.md#other-properties)
+ [Clear the draw buffer](API.md#clear-the-draw-buffer)
+ [Reading pixels](API.md#reading-pixels)
+ [Per-frame callbacks](API.md#per-frame-callbacks)
+ [Frame stats](API.md#frame-stats)
+ [WebGL capabilities](API.md#webgl-capabilities)
+ [Clean up](API.md#clean-up)
+ [Context loss](API.md#context-loss)
#### `regl.destroy()`
## Contributing
## Errors
[For info on how to build and test headless, see the contributing guide here](DEVELOPING.md)
#### `var REGLError = require('regl/error')`
## License
(c) 2016 MIT License
Supported by the Freeman Lab and the Howard Hughes Medical Institute
Supported by the [Freeman Lab](https://www.janelia.org/lab/freeman-lab) and the Howard Hughes Medical Institute
var check = require('./lib/check')
var getContext = require('./lib/context')
var wrapExtensions = require('./lib/extension')
var wrapShaders = require('./lib/shader')
var wrapBuffers = require('./lib/buffer')
var wrapElements = require('./lib/elements')
var wrapTextures = require('./lib/texture')
var wrapFBOs = require('./lib/fbo')
var wrapUniforms = require('./lib/uniform')
var wrapAttributes = require('./lib/attribute')
var wrapShaders = require('./lib/shader')
var wrapDraw = require('./lib/draw')
var wrapContext = require('./lib/state')
var createCompiler = require('./lib/compile')
var wrapRead = require('./lib/read')
var dynamic = require('./lib/dynamic')
var raf = require('./lib/raf')
var clock = require('./lib/clock')
var GL_COLOR_BUFFER_BIT = 16384
var GL_DEPTH_BUFFER_BIT = 256
var GL_STENCIL_BUFFER_BIT = 1024
var GL_ARRAY_BUFFER = 34962
var CONTEXT_LOST_EVENT = 'webglcontextlost'

@@ -19,21 +33,85 @@ var CONTEXT_RESTORED_EVENT = 'webglcontextrestored'

var GL_COLOR_BUFFER_BIT = 16384
var GL_DEPTH_BUFFER_BIT = 256
var GL_STENCIL_BUFFER_BIT = 1024
var extensionState = wrapExtensions(gl, options.requiredExtensions || [])
var bufferState = wrapBuffers(gl, extensionState)
var bufferState = wrapBuffers(gl)
var elementState = wrapElements(gl, extensionState, bufferState)
var textureState = wrapTextures(gl, extensionState)
var fboState = wrapFBOs(gl, extensionState, textureState)
var shaderState = wrapShaders(gl, extensionState)
var contextState = wrapContext(
var uniformState = wrapUniforms()
var attributeState = wrapAttributes(gl, extensionState, bufferState)
var shaderState = wrapShaders(
gl,
extensionState,
shaderState,
attributeState,
uniformState,
function (program) {
return compiler.draw(program)
})
var drawState = wrapDraw(gl, extensionState, bufferState)
var glState = wrapContext(gl, shaderState)
var frameState = {
count: 0,
start: clock(),
dt: 0,
t: clock(),
renderTime: 0,
width: gl.drawingBufferWidth,
height: gl.drawingBufferHeight
}
var readPixels = wrapRead(gl, glState)
var compiler = createCompiler(
gl,
extensionState,
bufferState,
elementState,
textureState,
fboState)
fboState,
glState,
uniformState,
attributeState,
shaderState,
drawState,
frameState)
var canvas = gl.canvas
// raf stuff
var rafCallbacks = []
var activeRAF = 0
function handleRAF () {
activeRAF = raf.next(handleRAF)
frameState.count += 1
if (frameState.width !== gl.drawingBufferWidth ||
frameState.height !== gl.drawingBufferHeight) {
frameState.width = gl.drawingBufferWidth
frameState.height = gl.drawingBufferHeight
glState.notifyViewportChanged()
}
var now = clock()
frameState.dt = now - frameState.t
frameState.t = now
for (var i = 0; i < rafCallbacks.length; ++i) {
var cb = rafCallbacks[i]
cb(frameState.count, frameState.t, frameState.dt)
}
frameState.renderTime = clock() - now
}
function startRAF () {
if (!activeRAF && rafCallbacks.length > 0) {
handleRAF()
}
}
function stopRAF () {
if (activeRAF) {
raf.cancel(handleRAF)
activeRAF = 0
}
}
function handleContextLoss (event) {
stopRAF()
event.preventDefault()

@@ -52,6 +130,7 @@ if (options.onContextLost) {

shaderState.refresh()
contextState.refresh()
glState.refresh()
if (options.onContextRestored) {
options.onContextRestored()
}
handleRAF()
}

@@ -66,2 +145,4 @@

function destroy () {
stopRAF()
if (canvas) {

@@ -72,3 +153,2 @@ canvas.removeEventListener(CONTEXT_LOST_EVENT, handleContextLoss)

contextState.clear()
shaderState.clear()

@@ -92,4 +172,32 @@ fboState.clear()

function compileProcedure (options) {
check(!!options, 'invalid args to regl({...})')
check.type(options, 'object', 'invalid args to regl({...})')
var hasDynamic = false
function flattenNestedOptions (options) {
var result = Object.assign({}, options)
delete result.uniforms
delete result.attributes
function merge (name) {
if (name in result) {
var child = result[name]
delete result[name]
Object.keys(child).forEach(function (prop) {
result[name + '.' + prop] = child[prop]
})
}
}
merge('blend')
merge('depth')
merge('cull')
merge('stencil')
merge('polygonOffset')
merge('scissor')
merge('sample')
return result
}
// First we separate the options into static and dynamic components

@@ -116,23 +224,35 @@ function separateDynamic (object) {

var attributes = separateDynamic(options.attributes || {})
var parts = separateDynamic(options)
var staticOptions = parts.static
delete staticOptions.uniforms
delete staticOptions.attributes
var opts = separateDynamic(flattenNestedOptions(options))
return contextState.create(
staticOptions,
uniforms.static,
attributes.static,
parts.dynamic,
uniforms.dynamic,
attributes.dynamic,
var compiled = compiler.command(
opts.static, uniforms.static, attributes.static,
opts.dynamic, uniforms.dynamic, attributes.dynamic,
hasDynamic)
}
// The main regl entry point
function regl (options) {
var compiled = compileProcedure(options)
var result = compiled.scope
result.draw = compiled.draw
return result
var draw = compiled.draw
var batch = compiled.batch
var scope = compiled.scope
var EMPTY_ARRAY = []
function reserve (count) {
while (EMPTY_ARRAY.length < count) {
EMPTY_ARRAY.push(null)
}
return EMPTY_ARRAY
}
function REGLCommand (args, body) {
if (typeof args === 'number') {
return batch(args | 0, reserve(args | 0))
} else if (Array.isArray(args)) {
return batch(args.length, args)
} else if (typeof args === 'function') {
return scope(null, args)
} else if (typeof body === 'function') {
return scope(args, body)
}
return draw(args)
}
return REGLCommand
}

@@ -144,2 +264,5 @@

// Update context state
glState.poll()
var c = options.color

@@ -165,14 +288,48 @@ if (c) {

return Object.assign(regl, {
// Registers another requestAnimationFrame callback
function frame (cb) {
rafCallbacks.push(cb)
function cancel () {
var index = rafCallbacks.find(function (item) {
return item === cb
})
if (index < 0) {
return
}
rafCallbacks.splice(index, 1)
if (rafCallbacks.length <= 0) {
stopRAF()
}
}
startRAF()
return {
cancel: cancel
}
}
return Object.assign(compileProcedure, {
// Clear current FBO
clear: clear,
// Place holder for dynamic keys
dynamic: dynamic.define,
// Dynamic variable binding
prop: dynamic.define,
// Object constructors
buffer: create(bufferState),
elements: create(elementState),
buffer: function (options) {
return bufferState.create(options, GL_ARRAY_BUFFER)
},
texture: create(textureState),
fbo: create(fboState),
// Frame rendering
frame: frame,
stats: frameState,
// Read pixels
read: readPixels,
// Destroy regl and all associated resources

@@ -179,0 +336,0 @@ destroy: destroy

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc