Comparing version 0.6.0 to 0.7.1
76
API.md
# REGL API | ||
* [Initialization](#initialization) | ||
* [As a fullscreen canvas](#as-a-fullscreen-canvas) | ||
* [From a container div](#from-a-container-div) | ||
* [From a canvas](#from-a-canvas) | ||
* [From a WebGL context](#from-a-webgl-context) | ||
- [As a fullscreen canvas](#as-a-fullscreen-canvas) | ||
- [From a container div](#from-a-container-div) | ||
- [From a canvas](#from-a-canvas) | ||
- [From a WebGL context](#from-a-webgl-context) | ||
+ [Initialization options](#initialization-options) | ||
@@ -1153,3 +1153,3 @@ * [Commands](#commands) | ||
#### Update | ||
Reinitialize a buffer in place, we call the buffer as a function: | ||
To reinitialize a buffer in place, we can call the buffer as a function: | ||
@@ -1170,3 +1170,3 @@ ```javascript | ||
The arguments to the update pathway are the same as the constructor. | ||
The arguments to the update pathway are the same as the constructor and the returned value will be a reference to the buffer. | ||
@@ -1176,5 +1176,38 @@ **Relevant WebGL APIs** | ||
* [`gl.bufferData`](https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml) | ||
* [`gl.bufferData`](https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferData.xml) | ||
##### In place update | ||
For performance reasons we may sometimes want to update just a portion of | ||
We can also update a portion of the buffer using the `subdata` method. This can be useful if you are dealing with frequently changing or streaming vertex data. Here is an example: | ||
```javascript | ||
// First we preallocate a buffer with 100 bytes of data | ||
var myBuffer = regl.buffer({ | ||
usage: 'dynamic', // give the WebGL driver a hint that this buffer may change | ||
type: 'float', | ||
length: 100 | ||
}) | ||
// Now we initialize the head of the buffer with the following data | ||
myBuffer.subdata([ 0, 1, 2, 3, 4, 5 ]) | ||
// | ||
// untyped arrays and arrays-of-arrays are converted to the same data type as | ||
// the buffer. typedarrays are copied bit-for-bit into the buffer | ||
// with no type conversion. | ||
// | ||
// We can also update the buffer at some byte offset by passing this as | ||
// the second argument to subdata | ||
myBuffer.subdata([[7, 8], [9, 10]], 8) | ||
// | ||
// now the contents of myBuffer are: | ||
// | ||
// new Float32Array([0, 1, 7, 8, 9, 10, 0, 0, 0, .... ]) | ||
// | ||
``` | ||
**Relevant WebGL APIs** | ||
* [`gl.bufferSubData`](https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferSubData.xml) | ||
#### Destroy | ||
@@ -1253,6 +1286,7 @@ Calling `.destroy()` on a buffer releases all resources associated to the buffer: | ||
#### Update | ||
As in the case of buffers, calling an element buffer as a function reinitializes an element buffer in place. The arguments are the same as for the constructor. For example: | ||
```javascript | ||
// First we create an element buffer | ||
var myElements = regl.elements({ ... }) | ||
var myElements = regl.elements() | ||
@@ -1272,2 +1306,25 @@ // Then we update it by calling it directly | ||
##### In-place update | ||
Again like buffers it is possible to preallocate an element buffer and update regions of the elements using the `subdata` command. | ||
```javascript | ||
// First we preallocate the element buffer | ||
var myElements = regl.elements({ | ||
primitive: 'triangles', | ||
usage: 'dynamic', | ||
type: 'uint16', | ||
length: 4096, | ||
count: 0 | ||
}) | ||
// Then we can update into ranges of the element buffer using subdata | ||
myElements.subdata( | ||
[ [0, 1, 2], | ||
[2, 1, 3] ]) | ||
``` | ||
**Relevant WebGL APIs** | ||
* [`gl.bufferSubData`](https://www.khronos.org/opengles/sdk/docs/man/xhtml/glBufferSubData.xml) | ||
#### Destroy | ||
@@ -1279,3 +1336,4 @@ | ||
// Calling .destroy() on a | ||
// Calling .destroy() on an element buffer releases all resources associated to | ||
// it | ||
myElements.destroy() | ||
@@ -1282,0 +1340,0 @@ ``` |
@@ -5,8 +5,9 @@ # Release notes | ||
* Optimize buffer creation, reduce memory allocation | ||
* Pool stream buffers | ||
* Resource API improvements | ||
+ Support dynamic variables (context and props) in resource constructors | ||
+ Add in place update methods to buffers and textures | ||
+ Add support for polling buffers and animated GIFs (useful for web audio) | ||
* subimage updates for textures | ||
* Optimize constructors/updates for textures, renderbuffers and framebuffers | ||
* Remove DDS parsing | ||
* Cubic frame buffer objects | ||
* More test cases for textures | ||
* More test cases for framebuffers | ||
* Implement a standard method for handling context creation errors | ||
@@ -16,8 +17,12 @@ * Add a mechanism for managing webgl extensions | ||
+ Allow users to disable extensions for testing/mocking | ||
* Cubic frame buffer objects | ||
* Performance monitoring hooks | ||
* WebVR integration (need to think how this will work) | ||
* Benchmark suite | ||
+ Dashboard for test cases and benchmarks | ||
+ Create some more typical drawing examples | ||
* Context loss handling | ||
* Documentation | ||
+ Write "regl for react programmers" | ||
+ Rewrite resource section, bring individual resources to the top | ||
* Testing | ||
@@ -33,2 +38,5 @@ + Instancing | ||
+ Test weird invocation sequences | ||
* Create comparisons | ||
* Benchmark suite | ||
@@ -38,4 +46,3 @@ + Dashboard for test cases and benchmarks | ||
* Support more DDS texture formats (HDR, PVRTC, etc.) | ||
* Build a website (@freeman-lab is on it!) | ||
* Render to glTF (maybe?), could be useful for dumping previews | ||
* Build a website (preview at [regl.party](http://regl.party)) | ||
* Recipe book/example set | ||
@@ -54,2 +61,9 @@ + Minecraft example | ||
## 0.7.0 | ||
* Add in place update methods to buffers and elements via `buffer.subdata` and `elements.subdata` | ||
* Pool stream buffers | ||
* Rewrite resource section of API, bring individual resources to the top | ||
* Optimized buffer and elements creation, no more memory allocation | ||
## 0.6.0 | ||
@@ -56,0 +70,0 @@ |
@@ -1,27 +0,19 @@ | ||
// Array and element buffer creation | ||
var check = require('./util/check') | ||
var isTypedArray = require('./util/is-typed-array') | ||
var isNDArrayLike = require('./util/is-ndarray') | ||
var values = require('./util/values') | ||
var flatten = require('./util/flatten') | ||
var transpose = require('./util/transpose') | ||
var pool = require('./util/pool') | ||
var arrayTypes = require('./constants/arraytypes.json') | ||
var bufferTypes = require('./constants/dtypes.json') | ||
var values = require('./util/values') | ||
var usageTypes = require('./constants/usage.json') | ||
var GL_STATIC_DRAW = 35044 | ||
var GL_STATIC_DRAW = 0x88E4 | ||
var GL_STREAM_DRAW = 0x88E0 | ||
var GL_ARRAY_BUFFER = 34962 | ||
var GL_BYTE = 5120 | ||
var GL_UNSIGNED_BYTE = 5121 | ||
var GL_SHORT = 5122 | ||
var GL_UNSIGNED_SHORT = 5123 | ||
var GL_INT = 5124 | ||
var GL_UNSIGNED_INT = 5125 | ||
var GL_FLOAT = 5126 | ||
var usageTypes = { | ||
'static': 35044, | ||
'dynamic': 35048, | ||
'stream': 35040 | ||
} | ||
function typedArrayCode (data) { | ||
@@ -31,43 +23,8 @@ return arrayTypes[Object.prototype.toString.call(data)] | 0 | ||
function makeTypedArray (dtype, args) { | ||
switch (dtype) { | ||
case GL_UNSIGNED_BYTE: | ||
return new Uint8Array(args) | ||
case GL_UNSIGNED_SHORT: | ||
return new Uint16Array(args) | ||
case GL_UNSIGNED_INT: | ||
return new Uint32Array(args) | ||
case GL_BYTE: | ||
return new Int8Array(args) | ||
case GL_SHORT: | ||
return new Int16Array(args) | ||
case GL_INT: | ||
return new Int32Array(args) | ||
case GL_FLOAT: | ||
return new Float32Array(args) | ||
default: | ||
return null | ||
function copyArray (out, inp) { | ||
for (var i = 0; i < inp.length; ++i) { | ||
out[i] = inp[i] | ||
} | ||
} | ||
function flatten (result, data, 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] | ||
} | ||
} | ||
} | ||
function transpose (result, data, shapeX, shapeY, strideX, strideY, offset) { | ||
var ptr = 0 | ||
for (var i = 0; i < shapeX; ++i) { | ||
for (var j = 0; j < shapeY; ++j) { | ||
result[ptr++] = data[strideX * i + strideY * j + offset] | ||
} | ||
} | ||
return result | ||
} | ||
module.exports = function wrapBufferState (gl) { | ||
@@ -79,3 +36,3 @@ var bufferCount = 0 | ||
this.id = bufferCount++ | ||
this.buffer = null | ||
this.buffer = gl.createBuffer() | ||
this.type = type | ||
@@ -85,3 +42,2 @@ this.usage = GL_STATIC_DRAW | ||
this.dimension = 1 | ||
this.data = null | ||
this.dtype = GL_UNSIGNED_BYTE | ||
@@ -94,10 +50,86 @@ } | ||
function refresh (buffer) { | ||
if (!gl.isBuffer(buffer.buffer)) { | ||
var streamPool = [] | ||
function createStream (type, data) { | ||
var buffer = streamPool.pop() | ||
if (!buffer) { | ||
buffer = new REGLBuffer(type) | ||
buffer.buffer = gl.createBuffer() | ||
} | ||
buffer.bind() | ||
gl.bufferData(buffer.type, buffer.data || buffer.byteLength, buffer.usage) | ||
initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1) | ||
return buffer | ||
} | ||
function destroyStream (stream) { | ||
streamPool.push(stream) | ||
} | ||
function initBufferFromTypedArray (buffer, data, usage) { | ||
buffer.byteLength = data.byteLength | ||
gl.bufferData(buffer.type, data, usage) | ||
} | ||
function initBufferFromData (buffer, data, usage, dtype, dimension) { | ||
buffer.usage = usage | ||
if (Array.isArray(data)) { | ||
buffer.dtype = dtype || GL_FLOAT | ||
if (data.length > 0 && Array.isArray(data[0])) { | ||
buffer.dimension = data[0].length | ||
var flatData = pool.allocType( | ||
buffer.dtype, | ||
data.length * buffer.dimension) | ||
flatten(flatData, data, buffer.dimension) | ||
initBufferFromTypedArray(buffer, flatData, usage) | ||
pool.freeType(flatData) | ||
} else { | ||
buffer.dimension = dimension | ||
var typedData = pool.allocType(buffer.dtype, data.length) | ||
copyArray(typedData, data) | ||
initBufferFromTypedArray(buffer, typedData, usage) | ||
pool.freeType(typedData) | ||
} | ||
} else if (isTypedArray(data)) { | ||
buffer.dtype = dtype || typedArrayCode(data) | ||
buffer.dimension = dimension | ||
initBufferFromTypedArray(buffer, data, usage) | ||
} else if (isNDArrayLike(data)) { | ||
var shape = data.shape | ||
var stride = data.stride | ||
var offset = data.offset | ||
var shapeX = 0 | ||
var shapeY = 0 | ||
var strideX = 0 | ||
var strideY = 0 | ||
if (shape.length === 1) { | ||
shapeX = shape[0] | ||
shapeY = 1 | ||
strideX = stride[0] | ||
strideY = 0 | ||
} else if (shape.length === 2) { | ||
shapeX = shape[0] | ||
shapeY = shape[1] | ||
strideX = stride[0] | ||
strideY = stride[1] | ||
} else { | ||
check.raise('invalid shape') | ||
} | ||
buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT | ||
buffer.dimension = shapeY | ||
var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY) | ||
transpose(transposeData, | ||
data.data, | ||
shapeX, shapeY, | ||
strideX, strideY, | ||
offset) | ||
initBufferFromTypedArray(buffer, transposeData, usage) | ||
pool.freeType(transposeData) | ||
} else { | ||
check.raise('invalid buffer data') | ||
} | ||
} | ||
function destroy (buffer) { | ||
@@ -113,17 +145,2 @@ var handle = buffer.buffer | ||
// TODO Implement pooled allocator for stream buffers | ||
function createStream (data) { | ||
var result = createBuffer({ | ||
data: data, | ||
usage: 'stream' | ||
}, | ||
GL_ARRAY_BUFFER, | ||
false) | ||
return result._buffer | ||
} | ||
function destroyStream (stream) { | ||
destroy(stream) | ||
} | ||
function createBuffer (options, type, deferInit) { | ||
@@ -133,104 +150,124 @@ var buffer = new REGLBuffer(type) | ||
function reglBuffer (input) { | ||
var options = input || {} | ||
function reglBuffer (options) { | ||
var usage = GL_STATIC_DRAW | ||
var data = null | ||
var byteLength = 0 | ||
var dtype = 0 | ||
var dimension = 1 | ||
if (Array.isArray(options) || | ||
isTypedArray(options) || | ||
isNDArrayLike(options)) { | ||
options = { | ||
data: options | ||
} | ||
data = options | ||
} else if (typeof options === 'number') { | ||
options = { | ||
length: options | 0 | ||
byteLength = options | 0 | ||
} else if (options) { | ||
check.type( | ||
options, 'object', | ||
'buffer arguments must be an object, a number or an array') | ||
if ('data' in options) { | ||
check( | ||
data === null || | ||
Array.isArray(data) || | ||
isTypedArray(data) || | ||
isNDArrayLike(data), | ||
'invalid data for buffer') | ||
data = options.data | ||
} | ||
} else if (options === null || options === void 0) { | ||
options = {} | ||
} | ||
check.type( | ||
options, 'object', | ||
'buffer arguments must be an object, a number or an array') | ||
if ('usage' in options) { | ||
check.parameter(options.usage, usageTypes, 'invalid buffer usage') | ||
usage = usageTypes[options.usage] | ||
} | ||
if ('usage' in options) { | ||
var usage = options.usage | ||
check.parameter(usage, usageTypes, 'invalid buffer usage') | ||
buffer.usage = usageTypes[options.usage] | ||
} else { | ||
buffer.usage = GL_STATIC_DRAW | ||
if ('type' in options) { | ||
check.parameter(options.type, bufferTypes, 'invalid buffer type') | ||
dtype = bufferTypes[options.type] | ||
} | ||
if ('dimension' in options) { | ||
check.type(options.dimension, 'number', 'invalid dimension') | ||
dimension = options.dimension | 0 | ||
} | ||
if ('length' in options) { | ||
check.nni(byteLength, 'buffer length must be a nonnegative integer') | ||
byteLength = options.length | 0 | ||
} | ||
} | ||
var dtype = 0 | ||
if ('type' in options) { | ||
check.parameter(options.type, bufferTypes, 'invalid buffer type') | ||
dtype = bufferTypes[options.type] | ||
buffer.bind() | ||
if (!data) { | ||
gl.bufferData(buffer.type, byteLength, usage) | ||
buffer.dtype = dtype || GL_UNSIGNED_BYTE | ||
buffer.usage = usage | ||
buffer.dimension = dimension | ||
buffer.byteLength = byteLength | ||
} else { | ||
initBufferFromData(buffer, data, usage, dtype, dimension) | ||
} | ||
var dimension = (options.dimension | 0) || 1 | ||
var byteLength = 0 | ||
var data = null | ||
if ('data' in options) { | ||
data = options.data | ||
if (data === null) { | ||
byteLength = options.length | 0 | ||
} else { | ||
if (isNDArrayLike(data)) { | ||
var shape = data.shape | ||
var stride = data.stride | ||
var offset = data.offset | ||
return reglBuffer | ||
} | ||
var shapeX = 0 | ||
var shapeY = 0 | ||
var strideX = 0 | ||
var strideY = 0 | ||
if (shape.length === 1) { | ||
shapeX = shape[0] | ||
shapeY = 1 | ||
strideX = stride[0] | ||
strideY = 0 | ||
} else if (shape.length === 2) { | ||
shapeX = shape[0] | ||
shapeY = shape[1] | ||
strideX = stride[0] | ||
strideY = stride[1] | ||
} else { | ||
check.raise('invalid shape') | ||
} | ||
function setSubData (data, offset) { | ||
check(offset + data.byteLength <= buffer.byteLength, | ||
'invalid buffer subdata call, buffer is too small') | ||
gl.bufferSubData(buffer.type, offset, data) | ||
} | ||
dtype = dtype || typedArrayCode(data.data) || GL_FLOAT | ||
dimension = shapeY | ||
data = transpose( | ||
makeTypedArray(dtype, shapeX * shapeY), | ||
data.data, | ||
shapeX, shapeY, | ||
strideX, strideY, | ||
offset) | ||
} else if (Array.isArray(data)) { | ||
if (data.length > 0 && Array.isArray(data[0])) { | ||
dimension = data[0].length | ||
dtype = dtype || GL_FLOAT | ||
var result = makeTypedArray(dtype, data.length * dimension) | ||
data = flatten(result, data, dimension) | ||
data = result | ||
} else { | ||
dtype = dtype || GL_FLOAT | ||
data = makeTypedArray(dtype, data) | ||
} | ||
} else { | ||
check.isTypedArray(data, 'invalid data type buffer data') | ||
dtype = dtype || typedArrayCode(data) | ||
} | ||
byteLength = data.byteLength | ||
function subdata (data, offset_) { | ||
var offset = (offset_ || 0) | 0 | ||
buffer.bind() | ||
if (Array.isArray(data)) { | ||
if (data.length > 0 && Array.isArray(data[0])) { | ||
var dimension = data[0].length | ||
var flatData = pool.allocType(buffer.dtype, data.length * dimension) | ||
flatten(flatData, data, dimension) | ||
setSubData(flatData, offset) | ||
pool.freeType(flatData) | ||
} else { | ||
var converted = pool.allocType(buffer.dtype, data.length) | ||
copyArray(converted, data) | ||
setSubData(converted, offset) | ||
pool.freeType(converted) | ||
} | ||
} else if ('length' in options) { | ||
byteLength = options.length | 0 | ||
check.nni(byteLength, 'buffer length must be a nonnegative integer') | ||
} | ||
} else if (isTypedArray(data)) { | ||
setSubData(data, offset) | ||
} else if (isNDArrayLike(data)) { | ||
var shape = data.shape | ||
var stride = data.stride | ||
buffer.data = data | ||
buffer.dtype = dtype || GL_UNSIGNED_BYTE | ||
buffer.byteLength = byteLength | ||
buffer.dimension = dimension | ||
var shapeX = 0 | ||
var shapeY = 0 | ||
var strideX = 0 | ||
var strideY = 0 | ||
if (shape.length === 1) { | ||
shapeX = shape[0] | ||
shapeY = 1 | ||
strideX = stride[0] | ||
strideY = 0 | ||
} else if (shape.length === 2) { | ||
shapeX = shape[0] | ||
shapeY = shape[1] | ||
strideX = stride[0] | ||
strideY = stride[1] | ||
} else { | ||
check.raise('invalid shape') | ||
} | ||
var dtype = Array.isArray(data.data) | ||
? buffer.dtype | ||
: typedArrayCode(data.data) | ||
refresh(buffer) | ||
var transposeData = pool.allocType(dtype, shapeX * shapeY) | ||
transpose(transposeData, | ||
data.data, | ||
shapeX, shapeY, | ||
strideX, strideY, | ||
data.offset) | ||
setSubData(transposeData, offset) | ||
pool.freeType(transposeData) | ||
} else { | ||
check.raise('invalid data for buffer subdata') | ||
} | ||
return reglBuffer | ||
@@ -245,2 +282,3 @@ } | ||
reglBuffer._buffer = buffer | ||
reglBuffer.subdata = subdata | ||
reglBuffer.destroy = function () { destroy(buffer) } | ||
@@ -261,6 +299,2 @@ | ||
refresh: function () { | ||
values(bufferSet).forEach(refresh) | ||
}, | ||
getBuffer: function (wrapper) { | ||
@@ -271,4 +305,6 @@ if (wrapper && wrapper._buffer instanceof REGLBuffer) { | ||
return null | ||
} | ||
}, | ||
_initBuffer: initBufferFromData | ||
} | ||
} |
var check = require('./util/check') | ||
var isTypedArray = require('./util/is-typed-array') | ||
var isNDArrayLike = require('./util/is-ndarray') | ||
var primTypes = require('./constants/primitives.json') | ||
var usageTypes = require('./constants/usage.json') | ||
@@ -19,5 +21,17 @@ var GL_POINTS = 0 | ||
var GL_STREAM_DRAW = 0x88E0 | ||
var GL_STATIC_DRAW = 0x88E4 | ||
module.exports = function wrapElementsState (gl, extensions, bufferState) { | ||
function REGLElementBuffer () { | ||
this.buffer = null | ||
var elementTypes = { | ||
'uint8': GL_UNSIGNED_BYTE, | ||
'uint16': GL_UNSIGNED_SHORT | ||
} | ||
if (extensions.oes_element_index_uint) { | ||
elementTypes.uint32 = GL_UNSIGNED_INT | ||
} | ||
function REGLElementBuffer (buffer) { | ||
this.buffer = buffer | ||
this.primType = GL_TRIANGLES | ||
@@ -32,62 +46,50 @@ this.vertCount = 0 | ||
function createElements (options) { | ||
var elements = new REGLElementBuffer() | ||
var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true) | ||
elements.buffer = buffer._buffer | ||
var bufferPool = [] | ||
function reglElements (input) { | ||
var options = input | ||
var ext32bit = extensions.oes_element_index_uint | ||
function createElementStream (data) { | ||
var result = bufferPool.pop() | ||
if (!result) { | ||
result = new REGLElementBuffer(bufferState.create( | ||
null, | ||
GL_ELEMENT_ARRAY_BUFFER, | ||
true)._buffer) | ||
} | ||
initElements(result, data, GL_STREAM_DRAW, -1, -1, 0, 0) | ||
return result | ||
} | ||
// Upload data to vertex buffer | ||
if (!options) { | ||
buffer() | ||
} else if (typeof options === 'number') { | ||
buffer(options) | ||
} else { | ||
var data = null | ||
var usage = 'static' | ||
if ( | ||
Array.isArray(options) || | ||
isTypedArray(options) || | ||
isNDArrayLike(options)) { | ||
data = options | ||
} else { | ||
check.type(options, 'object', 'invalid arguments for elements') | ||
if ('data' in options) { | ||
data = options.data | ||
} | ||
if ('usage' in options) { | ||
usage = options.usage | ||
} | ||
} | ||
if (Array.isArray(data) || | ||
(isNDArrayLike(data) && Array.isArray(data.data)) || | ||
'type' in options) { | ||
buffer({ | ||
type: options.type || | ||
(ext32bit | ||
? 'uint32' | ||
: 'uint16'), | ||
usage: usage, | ||
data: data | ||
}) | ||
} else { | ||
buffer({ | ||
usage: usage, | ||
data: data | ||
}) | ||
} | ||
if (Array.isArray(data) || isTypedArray(data)) { | ||
buffer.dimension = 3 | ||
} | ||
} | ||
function destroyElementStream (elements) { | ||
bufferPool.push(elements) | ||
} | ||
// try to guess default primitive type and arguments | ||
var vertCount = elements.buffer.byteLength | ||
var type = 0 | ||
function initElements ( | ||
elements, | ||
data, | ||
usage, | ||
prim, | ||
count, | ||
byteLength, | ||
type) { | ||
var predictedType = type | ||
if (!type && ( | ||
!isTypedArray(data) || | ||
(isNDArrayLike(data) && !isTypedArray(data.data)))) { | ||
predictedType = extensions.oes_element_index_uint | ||
? GL_UNSIGNED_INT | ||
: GL_UNSIGNED_SHORT | ||
} | ||
elements.buffer.bind() | ||
bufferState._initBuffer( | ||
elements.buffer, | ||
data, | ||
usage, | ||
predictedType, | ||
3) | ||
var dtype = type | ||
if (!type) { | ||
switch (elements.buffer.dtype) { | ||
case GL_UNSIGNED_BYTE: | ||
case GL_BYTE: | ||
type = GL_UNSIGNED_BYTE | ||
dtype = GL_UNSIGNED_BYTE | ||
break | ||
@@ -97,4 +99,3 @@ | ||
case GL_SHORT: | ||
type = GL_UNSIGNED_SHORT | ||
vertCount >>= 1 | ||
dtype = GL_UNSIGNED_SHORT | ||
break | ||
@@ -104,13 +105,34 @@ | ||
case GL_INT: | ||
check(ext32bit, '32 bit element buffers not supported') | ||
type = GL_UNSIGNED_INT | ||
vertCount >>= 2 | ||
dtype = GL_UNSIGNED_INT | ||
break | ||
default: | ||
check.raise('invalid element buffer type') | ||
check.raise('unsupported type for element array') | ||
} | ||
elements.buffer.dtype = dtype | ||
} | ||
elements.type = dtype | ||
// try to guess primitive type from cell dimension | ||
var primType = GL_TRIANGLES | ||
// Check oes_element_index_uint extension | ||
check( | ||
dtype !== GL_UNSIGNED_INT || | ||
!!extensions.oes_element_index_uint, | ||
'32 bit element buffers not supported, enable oes_element_index_uint first') | ||
// try to guess default primitive type and arguments | ||
var vertCount = count | ||
if (vertCount < 0) { | ||
vertCount = elements.buffer.byteLength | ||
if (dtype === GL_UNSIGNED_SHORT) { | ||
vertCount >>= 1 | ||
} else if (dtype === GL_UNSIGNED_INT) { | ||
vertCount >>= 2 | ||
} | ||
} | ||
elements.vertCount = vertCount | ||
// try to guess primitive type from cell dimension | ||
var primType = prim | ||
if (prim < 0) { | ||
primType = GL_TRIANGLES | ||
var dimension = elements.buffer.dimension | ||
@@ -120,21 +142,96 @@ if (dimension === 1) primType = GL_POINTS | ||
if (dimension === 3) primType = GL_TRIANGLES | ||
} | ||
elements.primType = primType | ||
} | ||
// if manual override present, use that | ||
if (typeof options === 'object') { | ||
if ('primitive' in options) { | ||
var primitive = options.primitive | ||
check.parameter(primitive, primTypes) | ||
primType = primTypes[primitive] | ||
} | ||
function createElements (options) { | ||
var buffer = bufferState.create(null, GL_ELEMENT_ARRAY_BUFFER, true) | ||
var elements = new REGLElementBuffer(buffer._buffer) | ||
if ('count' in options) { | ||
vertCount = options.vertCount | 0 | ||
function reglElements (options) { | ||
if (!options) { | ||
buffer() | ||
elements.primType = GL_TRIANGLES | ||
elements.vertCount = 0 | ||
elements.type = GL_UNSIGNED_BYTE | ||
} else if (typeof options === 'number') { | ||
buffer(options) | ||
elements.primType = GL_TRIANGLES | ||
elements.vertCount = options | 0 | ||
elements.type = GL_UNSIGNED_BYTE | ||
} else { | ||
var data = null | ||
var usage = GL_STATIC_DRAW | ||
var primType = -1 | ||
var vertCount = -1 | ||
var byteLength = 0 | ||
var dtype = 0 | ||
if (Array.isArray(options) || | ||
isTypedArray(options) || | ||
isNDArrayLike(options)) { | ||
data = options | ||
} else { | ||
check.type(options, 'object', 'invalid arguments for elements') | ||
if ('data' in options) { | ||
data = options.data | ||
check( | ||
Array.isArray(data) || | ||
isTypedArray(data) || | ||
isNDArrayLike(data), | ||
'invalid data for element buffer') | ||
} | ||
if ('usage' in options) { | ||
check.parameter( | ||
options.usage, | ||
usageTypes, | ||
'invalid element buffer usage') | ||
usage = usageTypes[options.usage] | ||
} | ||
if ('primitive' in options) { | ||
check.parameter( | ||
options.primitive, | ||
primTypes, | ||
'invalid element buffer primitive') | ||
primType = primTypes[options.primitive] | ||
} | ||
if ('count' in options) { | ||
check( | ||
typeof options.count === 'number' && options.count >= 0, | ||
'invalid vertex count for elements') | ||
vertCount = options.count | 0 | ||
} | ||
if ('length' in options) { | ||
byteLength = options.length | 0 | ||
} | ||
if ('type' in options) { | ||
check.parameter( | ||
options.type, | ||
elementTypes, | ||
'invalid buffer type') | ||
dtype = elementTypes[options.type] | ||
} | ||
} | ||
if (data) { | ||
initElements( | ||
elements, | ||
data, | ||
usage, | ||
primType, | ||
vertCount, | ||
byteLength, | ||
dtype) | ||
} else { | ||
var _buffer = elements.buffer | ||
_buffer.bind() | ||
gl.bufferData(GL_ELEMENT_ARRAY_BUFFER, byteLength, usage) | ||
_buffer.dtype = dtype || GL_UNSIGNED_BYTE | ||
_buffer.usage = usage | ||
_buffer.dimension = 3 | ||
_buffer.byteLength = byteLength | ||
elements.primType = primType < 0 ? GL_TRIANGLES : primType | ||
elements.vertCount = vertCount < 0 ? 0 : vertCount | ||
elements.type = _buffer.dtype | ||
} | ||
} | ||
// update properties for element buffer | ||
elements.primType = primType | ||
elements.vertCount = vertCount | ||
elements.type = type | ||
return reglElements | ||
@@ -147,2 +244,6 @@ } | ||
reglElements._elements = elements | ||
reglElements.subdata = function (data, offset) { | ||
buffer.subdata(data, offset) | ||
return reglElements | ||
} | ||
reglElements.destroy = function () { | ||
@@ -157,14 +258,2 @@ check(elements.buffer !== null, 'must not double destroy elements') | ||
// TODO implemented pooled allocator for element buffer streams | ||
function createElementStream (data) { | ||
return createElements({ | ||
usage: 'stream', | ||
data: data | ||
})._elements | ||
} | ||
function destroyElementStream (elements) { | ||
bufferState.destroyStream(elements.buffer) | ||
} | ||
return { | ||
@@ -171,0 +260,0 @@ create: createElements, |
{ | ||
"name": "regl", | ||
"version": "0.6.0", | ||
"version": "0.7.1", | ||
"description": "WebGL", | ||
@@ -21,2 +21,3 @@ "main": "regl.js", | ||
"faucet": "0.0.1", | ||
"getusermedia": "^1.3.7", | ||
"gl": "^4.0.1", | ||
@@ -23,0 +24,0 @@ "gl-mat4": "^1.1.4", |
@@ -80,5 +80,7 @@ # regl | ||
See this example [live](http://regl.party/examples/?basic) | ||
#### More examples | ||
[Check out the demo gallery](https://mikolalysenko.github.io/regl/www/gallery.html) | ||
Check out the [gallery](http://regl.party/examples). | ||
@@ -90,7 +92,4 @@ ## Setup | ||
#### 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: | ||
To try out regl right away, you can use the live editor in the [gallery](http://regl.party.examples). | ||
* requirebin | ||
* codepen | ||
#### npm | ||
@@ -97,0 +96,0 @@ 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: |
@@ -167,2 +167,3 @@ var check = require('./lib/util/check') | ||
function handleContextLoss (event) { | ||
/* | ||
stopRAF() | ||
@@ -173,5 +174,7 @@ event.preventDefault() | ||
} | ||
*/ | ||
} | ||
function handleContextRestored (event) { | ||
/* | ||
gl.getError() | ||
@@ -189,2 +192,3 @@ extensionState.refresh() | ||
handleRAF() | ||
*/ | ||
} | ||
@@ -191,0 +195,0 @@ |
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 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
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2230723
89
14368
28
224