Skip to content

Instantly share code, notes, and snippets.

@adrianseeley
Last active December 19, 2015 00:28
Show Gist options
  • Save adrianseeley/5868524 to your computer and use it in GitHub Desktop.
Save adrianseeley/5868524 to your computer and use it in GitHub Desktop.
GPU encoding floats on gpu, and reading those floats works, textures dont seem to be binding though...
<html>
<head>
<title>GPU</title>
<script>
function log (msg) { if (window.console && window.console.log) { console.log(msg); } }
function handleContextLost (e) { log("handle context lost"); e.preventDefault(); }
function handleContextRestored () { log("handle context restored"); init(); }
function checkGLError () { var error = GPU_Static.gl_context.getError(); if (error != GPU_Static.gl_context.NO_ERROR && error != GPU_Static.gl_context.CONTEXT_LOST_WEBGL) { var str = "GL Error: " + error; document.body.appendChild(document.createTextNode(str)); throw str; } }
WebGLUtils = function () {
var makeFailHTML = function (msg) {
return '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr><td align="center"><div style="display: table-cell; vertical-align: middle;"><div style="">' + msg + '</div></div></td></tr></table>';
};
var GET_A_WEBGL_BROWSER = 'This page requires a browser that supports WebGL.<br/><a href="http://get.webgl.org">lick here to upgrade your browser.</a>';
var OTHER_PROBLEM = 'It doesn\'t appear your computer can support WebGL.<br/><a href="http://get.webgl.org/troubleshooting/">Click here for more information.</a>';
var setupWebGL = function (canvas, opt_attribs) {
function showLink (str) {
var container = canvas.parentNode;
if (container) {
container.innerHTML = makeFailHTML(str);
}
};
if (!window.WebGLRenderingContext) {
showLink(GET_A_WEBGL_BROWSER);
return null;
}
var context = create3DContext(canvas, opt_attribs);
if (!context) {
showLink(OTHER_PROBLEM);
}
return context;
};
var create3DContext = function(canvas, opt_attribs) {
var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
var context = null;
for (var ii = 0; ii < names.length; ++ii) {
try {
context = canvas.getContext(names[ii], opt_attribs);
} catch(e) {}
if (context) {
break;
}
}
return context;
}
return {create3DContext: create3DContext, setupWebGL: setupWebGL};
}();
WebGLDebugUtils = function() {
var log = function(msg) {
if (window.console && window.console.log) {
window.console.log(msg);
}
};
var error = function(msg) {
if (window.console && window.console.error) {
window.console.error(msg);
} else {
log(msg);
}
};
var glValidEnumContexts = {'enable': {1: { 0:true }}, 'disable': {1: {0: true}}, 'getParameter': {1: {0: true}}, 'drawArrays': {3: {0: true}}, 'drawElements': {4: {0: true, 2: true}}, 'createShader': {1: {0: true}}, 'getShaderParameter': {2: {1: true}}, 'getProgramParameter': {2: {1: true}}, 'getShaderPrecisionFormat': {2: {0: true, 1: true}}, 'getVertexAttrib': {2: {1: true}}, 'vertexAttribPointer': {6: {2: true}}, 'bindTexture': {2: {0: true}}, 'activeTexture': {1: {0: true}}, 'getTexParameter': {2: {0: true, 1: true}}, 'texParameterf': {3: {0:true, 1: true}}, 'texParameteri': {3: {0: true, 1: true, 2: true}}, 'texImage2D': {9: {0: true, 2: true, 6: true, 7: true}, 6: {0: true, 2: true, 3: true, 4: true}}, 'texSubImage2D': {9: {0: true, 6: true, 7: true}, 7: {0: true, 4: true, 5: true}}, 'copyTexImage2D': {8: {0: true, 2: true}}, 'copyTexSubImage2D': {8: {0: true}}, 'generateMipmap': {1: {0: true}}, 'compressedTexImage2D': {7: {0: true, 2: true}}, 'compressedTexSubImage2D': {8: {0: true, 6: true}},'bindBuffer': {2: {0: true}},'bufferData': {3: {0: true, 2: true}},'bufferSubData': {3: {0: true}},'getBufferParameter': {2: {0: true, 1: true}}, 'pixelStorei': {2: {0: true, 1: true}}, 'readPixels': {7: {4: true, 5: true}}, 'bindRenderbuffer': {2: {0: true}}, 'bindFramebuffer': {2: {0: true}}, 'checkFramebufferStatus': {1: {0: true}}, 'framebufferRenderbuffer': {4: {0: true, 1: true, 2: true}}, 'framebufferTexture2D': {5: {0: true, 1: true, 2: true}}, 'getFramebufferAttachmentParameter': {3: {0: true, 1: true, 2: true}}, 'getRenderbufferParameter': {2: {0: true, 1: true}}, 'renderbufferStorage': {4: {0: true, 1: true}}, 'clear': {1: {0: true}}, 'depthFunc': {1: {0: true}}, 'blendFunc': {2: {0: true, 1: true}}, 'blendFuncSeparate': {4: { 0: true, 1: true, 2: true, 3: true}}, 'blendEquation': {1: {0: true}}, 'blendEquationSeparate': {2: {0: true, 1: true}}, 'stencilFunc': {3: {0: true}}, 'stencilFuncSeparate': {4: {0: true, 1: true}}, 'stencilMaskSeparate': {2: { 0: true}}, 'stencilOp': {3: {0: true, 1: true, 2: true}}, 'stencilOpSeparate': {4: {0: true, 1: true, 2: true, 3: true}}, 'cullFace': {1: {0: true}}, 'frontFace': {1: {0: true}}};
var glEnums = null;
function init (ctx) {
if (glEnums == null) {
glEnums = {};
for (var propertyName in ctx) {
if (typeof ctx[propertyName] == 'number') {
glEnums[ctx[propertyName]] = propertyName;
}
}
}
}
function checkInit () {
if (glEnums == null) {
throw 'WebGLDebugUtils.init(ctx) not called';
}
}
function mightBeEnum (value) {
checkInit();
return (glEnums[value] !== undefined);
}
function glEnumToString (value) {
checkInit();
var name = glEnums[value];
return (name !== undefined) ? ("gl." + name) : ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + "");
}
function glFunctionArgToString (functionName, numArgs, argumentIndex, value) {
var funcInfo = glValidEnumContexts[functionName];
if (funcInfo !== undefined) {
var funcInfo = funcInfo[numArgs];
if (funcInfo !== undefined) {
if (funcInfo[argumentIndex]) {
return glEnumToString(value);
}
}
}
if (value === null) {
return "null";
} else if (value === undefined) {
return "undefined";
} else {
return value.toString();
}
}
function glFunctionArgsToString (functionName, args) {
// apparently we can't do args.join(",");
var argStr = "";
var numArgs = args.length;
for (var ii = 0; ii < numArgs; ++ii) {
argStr += ((ii == 0) ? '' : ', ') + glFunctionArgToString(functionName, numArgs, ii, args[ii]);
}
return argStr;
};
function makePropertyWrapper (wrapper, original, propertyName) {
wrapper.__defineGetter__(propertyName, function() {
return original[propertyName];
});
wrapper.__defineSetter__(propertyName, function(value) {
original[propertyName] = value;
});
}
function makeFunctionWrapper (original, functionName) {
var f = original[functionName];
return function() {
var result = f.apply(original, arguments);
return result;
};
}
function makeDebugContext (ctx, opt_onErrorFunc, opt_onFunc) {
init(ctx);
opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
var argStr = "";
var numArgs = args.length;
for (var ii = 0; ii < numArgs; ++ii) {
argStr += ((ii == 0) ? '' : ', ') +
glFunctionArgToString(functionName, numArgs, ii, args[ii]);
}
error("WebGL error "+ glEnumToString(err) + " in "+ functionName + "(" + argStr + ")");
};
var glErrorShadow = {};
function makeErrorWrapper (ctx, functionName) {
return function() {
if (opt_onFunc) {
opt_onFunc(functionName, arguments);
}
var result = ctx[functionName].apply(ctx, arguments);
var err = ctx.getError();
if (err != 0) {
glErrorShadow[err] = true;
opt_onErrorFunc(err, functionName, arguments);
}
return result;
};
}
var wrapper = {};
for (var propertyName in ctx) {
if (typeof ctx[propertyName] == 'function') {
wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
} else {
makePropertyWrapper(wrapper, ctx, propertyName);
}
}
wrapper.getError = function() {
for (var err in glErrorShadow) {
if (glErrorShadow.hasOwnProperty(err)) {
if (glErrorShadow[err]) {
glErrorShadow[err] = false;
return err;
}
}
}
return ctx.NO_ERROR;
};
return wrapper;
}
function resetToInitialState (ctx) {
var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
var tmp = ctx.createBuffer();
ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp);
for (var ii = 0; ii < numAttribs; ++ii) {
ctx.disableVertexAttribArray(ii);
ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0);
ctx.vertexAttrib1f(ii, 0);
}
ctx.deleteBuffer(tmp);
var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
for (var ii = 0; ii < numTextureUnits; ++ii) {
ctx.activeTexture(ctx.TEXTURE0 + ii);
ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null);
ctx.bindTexture(ctx.TEXTURE_2D, null);
}
ctx.activeTexture(ctx.TEXTURE0);
ctx.useProgram(null);
ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
ctx.bindFramebuffer(ctx.FRAMEBUFFER, null);
ctx.bindRenderbuffer(ctx.RENDERBUFFER, null);
ctx.disable(ctx.BLEND);
ctx.disable(ctx.CULL_FACE);
ctx.disable(ctx.DEPTH_TEST);
ctx.disable(ctx.DITHER);
ctx.disable(ctx.SCISSOR_TEST);
ctx.blendColor(0, 0, 0, 0);
ctx.blendEquation(ctx.FUNC_ADD);
ctx.blendFunc(ctx.ONE, ctx.ZERO);
ctx.clearColor(0, 0, 0, 0);
ctx.clearDepth(1);
ctx.clearStencil(-1);
ctx.colorMask(true, true, true, true);
ctx.cullFace(ctx.BACK);
ctx.depthFunc(ctx.LESS);
ctx.depthMask(true);
ctx.depthRange(0, 1);
ctx.frontFace(ctx.CCW);
ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE);
ctx.lineWidth(1);
ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4);
ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4);
ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false);
ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) {
ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL);
}
ctx.polygonOffset(0, 0);
ctx.sampleCoverage(1, false);
ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF);
ctx.stencilMask(0xFFFFFFFF);
ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP);
ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
while(ctx.getError());
}
function makeLostContextSimulatingCanvas (canvas) {
var unwrappedContext_;
var wrappedContext_;
var onLost_ = [];
var onRestored_ = [];
var wrappedContext_ = {};
var contextId_ = 1;
var contextLost_ = false;
var resourceId_ = 0;
var resourceDb_ = [];
var numCallsToLoseContext_ = 0;
var numCalls_ = 0;
var canRestore_ = false;
var restoreTimeout_ = 0;
var glErrorShadow_ = {};
canvas.getContext = function (f) {
return function() {
var ctx = f.apply(canvas, arguments);
// Did we get a context and is it a WebGL context?
if (ctx instanceof WebGLRenderingContext) {
if (ctx != unwrappedContext_) {
if (unwrappedContext_) {
throw "got different context"
}
unwrappedContext_ = ctx;
wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_);
}
return wrappedContext_;
}
return ctx;
}
}(canvas.getContext);
function wrapEvent (listener) {
if (typeof(listener) == "function") {
return listener;
} else {
return function(info) {
listener.handleEvent(info);
}
}
}
var addOnContextLostListener = function (listener) {
onLost_.push(wrapEvent(listener));
};
var addOnContextRestoredListener = function (listener) {
onRestored_.push(wrapEvent(listener));
};
function wrapAddEventListener(canvas) {
var f = canvas.addEventListener;
canvas.addEventListener = function(type, listener, bubble) {
switch (type) {
case 'webglcontextlost':
addOnContextLostListener(listener);
break;
case 'webglcontextrestored':
addOnContextRestoredListener(listener);
break;
default:
f.apply(canvas, arguments);
break;
}
};
}
wrapAddEventListener(canvas);
canvas.loseContext = function() {
if (!contextLost_) {
contextLost_ = true;
numCallsToLoseContext_ = 0;
++contextId_;
while (unwrappedContext_.getError());
clearErrors();
glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true;
var event = makeWebGLContextEvent("context lost");
var callbacks = onLost_.slice();
setTimeout(function() {
for (var ii = 0; ii < callbacks.length; ++ii) {
callbacks[ii](event);
}
if (restoreTimeout_ >= 0) {
setTimeout(function() {
canvas.restoreContext();
}, restoreTimeout_);
}
}, 0);
}
};
canvas.restoreContext = function() {
if (contextLost_) {
if (onRestored_.length) {
setTimeout(function() {
if (!canRestore_) {
throw "can not restore. webglcontestlost listener did not call event.preventDefault";
}
freeResources();
resetToInitialState(unwrappedContext_);
contextLost_ = false;
numCalls_ = 0;
canRestore_ = false;
var callbacks = onRestored_.slice();
var event = makeWebGLContextEvent("context restored");
for (var ii = 0; ii < callbacks.length; ++ii) {
callbacks[ii](event);
}
}, 0);
}
}
};
canvas.loseContextInNCalls = function(numCalls) {
if (contextLost_) {
throw "You can not ask a lost contet to be lost";
}
numCallsToLoseContext_ = numCalls_ + numCalls;
};
canvas.getNumCalls = function() {
return numCalls_;
};
canvas.setRestoreTimeout = function(timeout) {
restoreTimeout_ = timeout;
};
function isWebGLObject(obj) {
return (obj instanceof WebGLBuffer || obj instanceof WebGLFramebuffer || obj instanceof WebGLProgram || obj instanceof WebGLRenderbuffer || obj instanceof WebGLShader || obj instanceof WebGLTexture);
}
function checkResources(args) {
for (var ii = 0; ii < args.length; ++ii) {
var arg = args[ii];
if (isWebGLObject(arg)) {
return arg.__webglDebugContextLostId__ == contextId_;
}
}
return true;
}
function clearErrors() {
var k = Object.keys(glErrorShadow_);
for (var ii = 0; ii < k.length; ++ii) {
delete glErrorShadow_[k];
}
}
function loseContextIfTime() {
++numCalls_;
if (!contextLost_) {
if (numCallsToLoseContext_ == numCalls_) {
canvas.loseContext();
}
}
}
function makeLostContextFunctionWrapper(ctx, functionName) {
var f = ctx[functionName];
return function() {
loseContextIfTime();
if (!contextLost_) {
var result = f.apply(ctx, arguments);
return result;
}
};
}
function freeResources() {
for (var ii = 0; ii < resourceDb_.length; ++ii) {
var resource = resourceDb_[ii];
if (resource instanceof WebGLBuffer) {
unwrappedContext_.deleteBuffer(resource);
} else if (resource instanceof WebGLFramebuffer) {
unwrappedContext_.deleteFramebuffer(resource);
} else if (resource instanceof WebGLProgram) {
unwrappedContext_.deleteProgram(resource);
} else if (resource instanceof WebGLRenderbuffer) {
unwrappedContext_.deleteRenderbuffer(resource);
} else if (resource instanceof WebGLShader) {
unwrappedContext_.deleteShader(resource);
} else if (resource instanceof WebGLTexture) {
unwrappedContext_.deleteTexture(resource);
}
}
}
function makeWebGLContextEvent(statusMessage) {
return {
statusMessage: statusMessage,
preventDefault: function() {
canRestore_ = true;
}
};
}
return canvas;
function makeLostContextSimulatingContext(ctx) {
for (var propertyName in ctx) {
if (typeof ctx[propertyName] == 'function') {
wrappedContext_[propertyName] = makeLostContextFunctionWrapper(ctx, propertyName);
} else {
makePropertyWrapper(wrappedContext_, ctx, propertyName);
}
}
wrappedContext_.getError = function() {
loseContextIfTime();
if (!contextLost_) {
var err;
while (err = unwrappedContext_.getError()) {
glErrorShadow_[err] = true;
}
}
for (var err in glErrorShadow_) {
if (glErrorShadow_[err]) {
delete glErrorShadow_[err];
return err;
}
}
return wrappedContext_.NO_ERROR;
};
var creationFunctions = [
"createBuffer",
"createFramebuffer",
"createProgram",
"createRenderbuffer",
"createShader",
"createTexture"
];
for (var ii = 0; ii < creationFunctions.length; ++ii) {
var functionName = creationFunctions[ii];
wrappedContext_[functionName] = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return null;
}
var obj = f.apply(ctx, arguments);
obj.__webglDebugContextLostId__ = contextId_;
resourceDb_.push(obj);
return obj;
};
}(ctx[functionName]);
}
var functionsThatShouldReturnNull = [
"getActiveAttrib",
"getActiveUniform",
"getBufferParameter",
"getContextAttributes",
"getAttachedShaders",
"getFramebufferAttachmentParameter",
"getParameter",
"getProgramParameter",
"getProgramInfoLog",
"getRenderbufferParameter",
"getShaderParameter",
"getShaderInfoLog",
"getShaderSource",
"getTexParameter",
"getUniform",
"getUniformLocation",
"getVertexAttrib"
];
for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) {
var functionName = functionsThatShouldReturnNull[ii];
wrappedContext_[functionName] = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return null;
}
return f.apply(ctx, arguments);
}
}(wrappedContext_[functionName]);
}
var isFunctions = [
"isBuffer",
"isEnabled",
"isFramebuffer",
"isProgram",
"isRenderbuffer",
"isShader",
"isTexture"
];
for (var ii = 0; ii < isFunctions.length; ++ii) {
var functionName = isFunctions[ii];
wrappedContext_[functionName] = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return false;
}
return f.apply(ctx, arguments);
}
}(wrappedContext_[functionName]);
}
wrappedContext_.checkFramebufferStatus = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return wrappedContext_.FRAMEBUFFER_UNSUPPORTED;
}
return f.apply(ctx, arguments);
};
}(wrappedContext_.checkFramebufferStatus);
wrappedContext_.getAttribLocation = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return -1;
}
return f.apply(ctx, arguments);
};
}(wrappedContext_.getAttribLocation);
wrappedContext_.getVertexAttribOffset = function(f) {
return function() {
loseContextIfTime();
if (contextLost_) {
return 0;
}
return f.apply(ctx, arguments);
};
}(wrappedContext_.getVertexAttribOffset);
wrappedContext_.isContextLost = function() {
return contextLost_;
};
return wrappedContext_;
}
}
return {
'init': init,
'mightBeEnum': mightBeEnum,
'glEnumToString': glEnumToString,
'glFunctionArgsToString': glFunctionArgsToString,
'makeDebugContext': makeDebugContext,
'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas,
'resetToInitialState': resetToInitialState
};
}();
window.requestAnimFrame = (function () { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) { return window.setTimeout(callback, 1000 / 60); }; })();
window.cancelAnimFrame = (function() { return window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame || window.clearTimeout; })();
function Matrix4x4() {
this.elements = Array(16);
this.loadIdentity();
}
Matrix4x4.prototype = {
scale: function (sx, sy, sz) {
this.elements[0*4+0] *= sx;
this.elements[0*4+1] *= sx;
this.elements[0*4+2] *= sx;
this.elements[0*4+3] *= sx;
this.elements[1*4+0] *= sy;
this.elements[1*4+1] *= sy;
this.elements[1*4+2] *= sy;
this.elements[1*4+3] *= sy;
this.elements[2*4+0] *= sz;
this.elements[2*4+1] *= sz;
this.elements[2*4+2] *= sz;
this.elements[2*4+3] *= sz;
return this;
},
translate: function (tx, ty, tz) {
this.elements[3*4+0] += this.elements[0*4+0] * tx + this.elements[1*4+0] * ty + this.elements[2*4+0] * tz;
this.elements[3*4+1] += this.elements[0*4+1] * tx + this.elements[1*4+1] * ty + this.elements[2*4+1] * tz;
this.elements[3*4+2] += this.elements[0*4+2] * tx + this.elements[1*4+2] * ty + this.elements[2*4+2] * tz;
this.elements[3*4+3] += this.elements[0*4+3] * tx + this.elements[1*4+3] * ty + this.elements[2*4+3] * tz;
return this;
},
rotate: function (angle, x, y, z) {
var mag = Math.sqrt(x*x + y*y + z*z);
var sinAngle = Math.sin(angle * Math.PI / 180.0);
var cosAngle = Math.cos(angle * Math.PI / 180.0);
if (mag > 0) {
var xx, yy, zz, xy, yz, zx, xs, ys, zs;
var oneMinusCos;
var rotMat;
x /= mag;
y /= mag;
z /= mag;
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * sinAngle;
ys = y * sinAngle;
zs = z * sinAngle;
oneMinusCos = 1.0 - cosAngle;
rotMat = new Matrix4x4();
rotMat.elements[0*4+0] = (oneMinusCos * xx) + cosAngle;
rotMat.elements[0*4+1] = (oneMinusCos * xy) - zs;
rotMat.elements[0*4+2] = (oneMinusCos * zx) + ys;
rotMat.elements[0*4+3] = 0.0;
rotMat.elements[1*4+0] = (oneMinusCos * xy) + zs;
rotMat.elements[1*4+1] = (oneMinusCos * yy) + cosAngle;
rotMat.elements[1*4+2] = (oneMinusCos * yz) - xs;
rotMat.elements[1*4+3] = 0.0;
rotMat.elements[2*4+0] = (oneMinusCos * zx) - ys;
rotMat.elements[2*4+1] = (oneMinusCos * yz) + xs;
rotMat.elements[2*4+2] = (oneMinusCos * zz) + cosAngle;
rotMat.elements[2*4+3] = 0.0;
rotMat.elements[3*4+0] = 0.0;
rotMat.elements[3*4+1] = 0.0;
rotMat.elements[3*4+2] = 0.0;
rotMat.elements[3*4+3] = 1.0;
rotMat = rotMat.multiply(this);
this.elements = rotMat.elements;
}
return this;
},
frustum: function (left, right, bottom, top, nearZ, farZ) {
var deltaX = right - left;
var deltaY = top - bottom;
var deltaZ = farZ - nearZ;
var frust;
if ( (nearZ <= 0.0) || (farZ <= 0.0) ||
(deltaX <= 0.0) || (deltaY <= 0.0) || (deltaZ <= 0.0) )
return this;
frust = new Matrix4x4();
frust.elements[0*4+0] = 2.0 * nearZ / deltaX;
frust.elements[0*4+1] = frust.elements[0*4+2] = frust.elements[0*4+3] = 0.0;
frust.elements[1*4+1] = 2.0 * nearZ / deltaY;
frust.elements[1*4+0] = frust.elements[1*4+2] = frust.elements[1*4+3] = 0.0;
frust.elements[2*4+0] = (right + left) / deltaX;
frust.elements[2*4+1] = (top + bottom) / deltaY;
frust.elements[2*4+2] = -(nearZ + farZ) / deltaZ;
frust.elements[2*4+3] = -1.0;
frust.elements[3*4+2] = -2.0 * nearZ * farZ / deltaZ;
frust.elements[3*4+0] = frust.elements[3*4+1] = frust.elements[3*4+3] = 0.0;
frust = frust.multiply(this);
this.elements = frust.elements;
return this;
},
perspective: function (fovy, aspect, nearZ, farZ) {
var frustumH = Math.tan(fovy / 360.0 * Math.PI) * nearZ;
var frustumW = frustumH * aspect;
return this.frustum(-frustumW, frustumW, -frustumH, frustumH, nearZ, farZ);
},
ortho: function (left, right, bottom, top, nearZ, farZ) {
var deltaX = right - left;
var deltaY = top - bottom;
var deltaZ = farZ - nearZ;
var ortho = new Matrix4x4();
if ( (deltaX == 0.0) || (deltaY == 0.0) || (deltaZ == 0.0) )
return this;
ortho.elements[0*4+0] = 2.0 / deltaX;
ortho.elements[3*4+0] = -(right + left) / deltaX;
ortho.elements[1*4+1] = 2.0 / deltaY;
ortho.elements[3*4+1] = -(top + bottom) / deltaY;
ortho.elements[2*4+2] = -2.0 / deltaZ;
ortho.elements[3*4+2] = -(nearZ + farZ) / deltaZ;
ortho = ortho.multiply(this);
this.elements = ortho.elements;
return this;
},
multiply: function (right) {
var tmp = new Matrix4x4();
for (var i = 0; i < 4; i++) {
tmp.elements[i*4+0] =
(this.elements[i*4+0] * right.elements[0*4+0]) +
(this.elements[i*4+1] * right.elements[1*4+0]) +
(this.elements[i*4+2] * right.elements[2*4+0]) +
(this.elements[i*4+3] * right.elements[3*4+0]) ;
tmp.elements[i*4+1] =
(this.elements[i*4+0] * right.elements[0*4+1]) +
(this.elements[i*4+1] * right.elements[1*4+1]) +
(this.elements[i*4+2] * right.elements[2*4+1]) +
(this.elements[i*4+3] * right.elements[3*4+1]) ;
tmp.elements[i*4+2] =
(this.elements[i*4+0] * right.elements[0*4+2]) +
(this.elements[i*4+1] * right.elements[1*4+2]) +
(this.elements[i*4+2] * right.elements[2*4+2]) +
(this.elements[i*4+3] * right.elements[3*4+2]) ;
tmp.elements[i*4+3] =
(this.elements[i*4+0] * right.elements[0*4+3]) +
(this.elements[i*4+1] * right.elements[1*4+3]) +
(this.elements[i*4+2] * right.elements[2*4+3]) +
(this.elements[i*4+3] * right.elements[3*4+3]) ;
}
this.elements = tmp.elements;
return this;
},
copy: function () {
var tmp = new Matrix4x4();
for (var i = 0; i < 16; i++) {
tmp.elements[i] = this.elements[i];
}
return tmp;
},
get: function (row, col) {
return this.elements[4*row+col];
},
// In-place inversion
invert: function () {
var tmp_0 = this.get(2,2) * this.get(3,3);
var tmp_1 = this.get(3,2) * this.get(2,3);
var tmp_2 = this.get(1,2) * this.get(3,3);
var tmp_3 = this.get(3,2) * this.get(1,3);
var tmp_4 = this.get(1,2) * this.get(2,3);
var tmp_5 = this.get(2,2) * this.get(1,3);
var tmp_6 = this.get(0,2) * this.get(3,3);
var tmp_7 = this.get(3,2) * this.get(0,3);
var tmp_8 = this.get(0,2) * this.get(2,3);
var tmp_9 = this.get(2,2) * this.get(0,3);
var tmp_10 = this.get(0,2) * this.get(1,3);
var tmp_11 = this.get(1,2) * this.get(0,3);
var tmp_12 = this.get(2,0) * this.get(3,1);
var tmp_13 = this.get(3,0) * this.get(2,1);
var tmp_14 = this.get(1,0) * this.get(3,1);
var tmp_15 = this.get(3,0) * this.get(1,1);
var tmp_16 = this.get(1,0) * this.get(2,1);
var tmp_17 = this.get(2,0) * this.get(1,1);
var tmp_18 = this.get(0,0) * this.get(3,1);
var tmp_19 = this.get(3,0) * this.get(0,1);
var tmp_20 = this.get(0,0) * this.get(2,1);
var tmp_21 = this.get(2,0) * this.get(0,1);
var tmp_22 = this.get(0,0) * this.get(1,1);
var tmp_23 = this.get(1,0) * this.get(0,1);
var t0 = ((tmp_0 * this.get(1,1) + tmp_3 * this.get(2,1) + tmp_4 * this.get(3,1)) -
(tmp_1 * this.get(1,1) + tmp_2 * this.get(2,1) + tmp_5 * this.get(3,1)));
var t1 = ((tmp_1 * this.get(0,1) + tmp_6 * this.get(2,1) + tmp_9 * this.get(3,1)) -
(tmp_0 * this.get(0,1) + tmp_7 * this.get(2,1) + tmp_8 * this.get(3,1)));
var t2 = ((tmp_2 * this.get(0,1) + tmp_7 * this.get(1,1) + tmp_10 * this.get(3,1)) -
(tmp_3 * this.get(0,1) + tmp_6 * this.get(1,1) + tmp_11 * this.get(3,1)));
var t3 = ((tmp_5 * this.get(0,1) + tmp_8 * this.get(1,1) + tmp_11 * this.get(2,1)) -
(tmp_4 * this.get(0,1) + tmp_9 * this.get(1,1) + tmp_10 * this.get(2,1)));
var d = 1.0 / (this.get(0,0) * t0 + this.get(1,0) * t1 + this.get(2,0) * t2 + this.get(3,0) * t3);
var out_00 = d * t0;
var out_01 = d * t1;
var out_02 = d * t2;
var out_03 = d * t3;
var out_10 = d * ((tmp_1 * this.get(1,0) + tmp_2 * this.get(2,0) + tmp_5 * this.get(3,0)) -
(tmp_0 * this.get(1,0) + tmp_3 * this.get(2,0) + tmp_4 * this.get(3,0)));
var out_11 = d * ((tmp_0 * this.get(0,0) + tmp_7 * this.get(2,0) + tmp_8 * this.get(3,0)) -
(tmp_1 * this.get(0,0) + tmp_6 * this.get(2,0) + tmp_9 * this.get(3,0)));
var out_12 = d * ((tmp_3 * this.get(0,0) + tmp_6 * this.get(1,0) + tmp_11 * this.get(3,0)) -
(tmp_2 * this.get(0,0) + tmp_7 * this.get(1,0) + tmp_10 * this.get(3,0)));
var out_13 = d * ((tmp_4 * this.get(0,0) + tmp_9 * this.get(1,0) + tmp_10 * this.get(2,0)) -
(tmp_5 * this.get(0,0) + tmp_8 * this.get(1,0) + tmp_11 * this.get(2,0)));
var out_20 = d * ((tmp_12 * this.get(1,3) + tmp_15 * this.get(2,3) + tmp_16 * this.get(3,3)) -
(tmp_13 * this.get(1,3) + tmp_14 * this.get(2,3) + tmp_17 * this.get(3,3)));
var out_21 = d * ((tmp_13 * this.get(0,3) + tmp_18 * this.get(2,3) + tmp_21 * this.get(3,3)) -
(tmp_12 * this.get(0,3) + tmp_19 * this.get(2,3) + tmp_20 * this.get(3,3)));
var out_22 = d * ((tmp_14 * this.get(0,3) + tmp_19 * this.get(1,3) + tmp_22 * this.get(3,3)) -
(tmp_15 * this.get(0,3) + tmp_18 * this.get(1,3) + tmp_23 * this.get(3,3)));
var out_23 = d * ((tmp_17 * this.get(0,3) + tmp_20 * this.get(1,3) + tmp_23 * this.get(2,3)) -
(tmp_16 * this.get(0,3) + tmp_21 * this.get(1,3) + tmp_22 * this.get(2,3)));
var out_30 = d * ((tmp_14 * this.get(2,2) + tmp_17 * this.get(3,2) + tmp_13 * this.get(1,2)) -
(tmp_16 * this.get(3,2) + tmp_12 * this.get(1,2) + tmp_15 * this.get(2,2)));
var out_31 = d * ((tmp_20 * this.get(3,2) + tmp_12 * this.get(0,2) + tmp_19 * this.get(2,2)) -
(tmp_18 * this.get(2,2) + tmp_21 * this.get(3,2) + tmp_13 * this.get(0,2)));
var out_32 = d * ((tmp_18 * this.get(1,2) + tmp_23 * this.get(3,2) + tmp_15 * this.get(0,2)) -
(tmp_22 * this.get(3,2) + tmp_14 * this.get(0,2) + tmp_19 * this.get(1,2)));
var out_33 = d * ((tmp_22 * this.get(2,2) + tmp_16 * this.get(0,2) + tmp_21 * this.get(1,2)) -
(tmp_20 * this.get(1,2) + tmp_23 * this.get(2,2) + tmp_17 * this.get(0,2)));
this.elements[0*4+0] = out_00;
this.elements[0*4+1] = out_01;
this.elements[0*4+2] = out_02;
this.elements[0*4+3] = out_03;
this.elements[1*4+0] = out_10;
this.elements[1*4+1] = out_11;
this.elements[1*4+2] = out_12;
this.elements[1*4+3] = out_13;
this.elements[2*4+0] = out_20;
this.elements[2*4+1] = out_21;
this.elements[2*4+2] = out_22;
this.elements[2*4+3] = out_23;
this.elements[3*4+0] = out_30;
this.elements[3*4+1] = out_31;
this.elements[3*4+2] = out_32;
this.elements[3*4+3] = out_33;
return this;
},
// Returns new matrix which is the inverse of this
inverse: function () {
var tmp = this.copy();
return tmp.invert();
},
// In-place transpose
transpose: function () {
var tmp = this.elements[0*4+1];
this.elements[0*4+1] = this.elements[1*4+0];
this.elements[1*4+0] = tmp;
tmp = this.elements[0*4+2];
this.elements[0*4+2] = this.elements[2*4+0];
this.elements[2*4+0] = tmp;
tmp = this.elements[0*4+3];
this.elements[0*4+3] = this.elements[3*4+0];
this.elements[3*4+0] = tmp;
tmp = this.elements[1*4+2];
this.elements[1*4+2] = this.elements[2*4+1];
this.elements[2*4+1] = tmp;
tmp = this.elements[1*4+3];
this.elements[1*4+3] = this.elements[3*4+1];
this.elements[3*4+1] = tmp;
tmp = this.elements[2*4+3];
this.elements[2*4+3] = this.elements[3*4+2];
this.elements[3*4+2] = tmp;
return this;
},
loadIdentity: function () {
for (var i = 0; i < 16; i++)
this.elements[i] = 0;
this.elements[0*4+0] = 1.0;
this.elements[1*4+1] = 1.0;
this.elements[2*4+2] = 1.0;
this.elements[3*4+3] = 1.0;
return this;
}
};
</script>
<script>
var fragment_SHADER_STRING = [
'precision mediump float;',
'uniform float time;',
'uniform sampler2D tex0;',
'uniform sampler2D tex1;',
'uniform sampler2D tex2;',
'uniform sampler2D tex3;',
'uniform sampler2D tex4;',
'uniform sampler2D tex5;',
'uniform sampler2D tex6;',
'uniform sampler2D tex7;',
'uniform sampler2D tex8;',
'uniform sampler2D tex9;',
'uniform sampler2D tex10;',
'uniform sampler2D tex11;',
'uniform sampler2D tex12;',
'uniform sampler2D tex13;',
'uniform sampler2D tex14;',
'uniform sampler2D tex15;',
'varying vec2 texCoord;',
'float random(vec2 seed) { return fract(cos(mod(123456780., 1024. * dot(seed / time, vec2(23.1406926327792690, 2.6651441426902251))))); }',
'float shift_right(float v, float amt) { v = floor(v) + 0.5; return floor(v / exp2(amt)); }',
'float shift_left(float v, float amt) { return floor(v * exp2(amt) + 0.5); }',
'float mask_last(float v, float bits) { return mod(v, shift_left(1.0, bits)); }',
'float extract_bits(float num, float from, float to) { from = floor(from + 0.5); to = floor(to + 0.5); return mask_last(shift_right(num, from), to - from); }',
'vec4 encode_float(float val) { if (val == 0.0) return vec4(0, 0, 0, 0); float sign = val > 0.0 ? 0.0 : 1.0; val = abs(val); float exponent = floor(log2(val)); float biased_exponent = exponent + 127.0; float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0; float t = biased_exponent / 2.0; float last_bit_of_biased_exponent = fract(t) * 2.0; float remaining_bits_of_biased_exponent = floor(t); float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0; float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0; float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0; float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0; return vec4(byte4, byte3, byte2, byte1); }',
'',
'{{user_functions}}',
'',
'void main() {',
'{{body}}',
//' vec4 data = texture2D(tex, texCoord);',
//' gl_FragColor = encode_float(random(texCoord));',
'}'
].join('\n');
var VERTEX_SHADER_STRING = 'attribute vec3 g_Position; attribute vec2 g_TexCoord0; varying vec2 texCoord; void main() { gl_Position = vec4(g_Position.x, g_Position.y, g_Position.z, 1.0); texCoord = g_TexCoord0; }';
function main () {
GPU_FloatsInFloatOut(document.getElementById('canvas'), {
user_functions: '',
body: ['vec4 data = texture2D(tex0, texCoord);',
'gl_FragColor = encode_float(30.);',
//'gl_FragColor.r = 1.;',
//'gl_FragColor.a = 1.;'
].join('\n')
}, 1,
function (fn) {
for (var i = 0; i < 20000; i++)
fn.set_input_value(i, 0, 5);
fn.prep_draw();
fn.bind_textures_to_GPU();
fn.draw();
fn.read_floats_out();
console.log(fn);
for (var i = 0; i < 10; i++) console.log(fn.output[i]);
});
};
var GPU_Static = {};
function GPU_Initialize_Static (canvas) {
console.log('initialiing static gl instance with canvas', canvas);
// if a gl context hasnt already been created
if (!GPU_Static.hasOwnProperty('gl_context')) {
console.log('static instance did not already exist, creating');
// hold the canvas
GPU_Static.canvas = canvas;
// initialize a WebGL context on the provided canvas
GPU_Static.gl_context = internal__initialize_gl(canvas);
// check for gl errors
checkGLError();
// create the draw verticies
GPU_Static.verticies = new Float32Array([1, 1, 0, -1, 1, 0, -1, -1, 0, 1, 1, 0, -1, -1, 0, 1, -1, 0]);
// create the draw texture coordinates (UVs)
GPU_Static.texture_coordinates = new Float32Array([1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0]);
// create the draw texture coordinates (UVs) offset
GPU_Static.texture_coordinates_offset = GPU_Static.verticies.byteLength;
// load the vertex shader
GPU_Static.vertex_shader = internal__load_shader(GPU_Static.gl_context.VERTEX_SHADER, VERTEX_SHADER_STRING);
// check for gl errors
checkGLError();
// get support for floating point texture components
// (RGBA values per pixel as floats instead of bytes)
GPU_Static.gl_context.getExtension('OES_texture_float');
// check for gl errors
checkGLError();
// create the vertex buffer object
GPU_Static.vertex_buffer_object = GPU_Static.gl_context.createBuffer();
// check for gl errors
checkGLError();
// bind the vertex buffer object
GPU_Static.gl_context.bindBuffer(GPU_Static.gl_context.ARRAY_BUFFER, GPU_Static.vertex_buffer_object);
// check for gl errors
checkGLError();
// initilize the vertex buffer object
GPU_Static.gl_context.bufferData(GPU_Static.gl_context.ARRAY_BUFFER, GPU_Static.texture_coordinates_offset + GPU_Static.texture_coordinates.byteLength, GPU_Static.gl_context.STATIC_DRAW);
// check for gl errors
checkGLError();
// fill vertex buffer object with our verticies
GPU_Static.gl_context.bufferSubData(GPU_Static.gl_context.ARRAY_BUFFER, 0, GPU_Static.verticies);
// check for gl errors
checkGLError();
// fill vertex buffer object with our texture coordinates (UVs)
GPU_Static.gl_context.bufferSubData(GPU_Static.gl_context.ARRAY_BUFFER, GPU_Static.texture_coordinates_offset, GPU_Static.texture_coordinates);
// check for gl errors
checkGLError();
}
console.log('static instance created');
};
function internal__initialize_gl (canvas) {
// attach handlers to loss/restoration of the gl context
canvas.addEventListener('webglcontextlost', handleContextLost, false);
canvas.addEventListener('webglcontextrestored', handleContextRestored, false);
// create the WebGL context
var gl_context = WebGLUtils.setupWebGL(canvas);
// if we were unable to create a context alert the user
if (!gl_context) throw 'ERROR: COULD NOT CREATE A GL CONTEXT';
// set the clear color of the context
gl_context.clearColor(1, 0, 0, 0);
console.log('gl initialized');
// return the created context
return gl_context;
};
function GPU_BytesInBytesOut (canvas, fragment_shader_descriptor, in_parameter_count, callback) {
// wrapped function constructor
internal__GPU_constructor(canvas, fragment_shader_descriptor, in_parameter_count, true, true, callback);
};
function GPU_BytesInFloatOut (canvas, fragment_shader_descriptor, in_parameter_count, callback) {
// wrapped function constructor
internal__GPU_constructor(canvas, fragment_shader_descriptor, in_parameter_count, true, false, callback);
};
function GPU_FloatsInBytesOut (canvas, fragment_shader_descriptor, in_parameter_count, callback) {
// wrapped function constructor
internal__GPU_constructor(canvas, fragment_shader_descriptor, in_parameter_count, false, false, callback);
};
function GPU_FloatsInFloatOut (canvas, fragment_shader_descriptor, in_parameter_count, callback) {
// wrapped function constructor
internal__GPU_constructor(canvas, fragment_shader_descriptor, in_parameter_count, false, false, callback);
};
function internal__GPU_constructor (canvas, fragment_shader_descriptor, in_parameter_count, bytes_in_flag, bytes_out_flag, callback) {
// initialize/ensure webgl
GPU_Initialize_Static(canvas);
// load the fragment shader
var fragment_shader = internal__initialize_fragment_shader(fragment_shader_descriptor);
// build the shader program
var shader_program = internal__build_shader_program(GPU_Static.vertex_shader, fragment_shader);
// bake an object for making GPU calls
var ref = {
canvas: canvas,
shader_program: shader_program,
in_parameter_count: in_parameter_count,
bytes_in_flag: bytes_in_flag,
bytes_out_flag: bytes_out_flag,
tex: internal__setup_textures(in_parameter_count, bytes_in_flag),
output: null,
set_input_value: function (work_unit_index, parameter_index, value) {
// set the input value, calculating the texture index from the parameter index
ref.tex[Math.floor(parameter_index / 4)][work_unit_index] = value;
},
prep_draw: function () {
console.log('prepping draw');
// clear the context
GPU_Static.gl_context.clear(GPU_Static.gl_context.COLOR_BUFFER_BIT); checkGLError(); // do we actually need to though?
// use the shader program
GPU_Static.gl_context.useProgram(ref.shader_program); checkGLError();
// bind the vertex buffer object
GPU_Static.gl_context.bindBuffer(GPU_Static.gl_context.ARRAY_BUFFER, GPU_Static.vertex_buffer_object); checkGLError();
// enable attribute 0 (verticies)
GPU_Static.gl_context.enableVertexAttribArray(0); checkGLError();
// mark verticies as represented by 3 component floats
GPU_Static.gl_context.vertexAttribPointer(0, 3, GPU_Static.gl_context.FLOAT, GPU_Static.gl_context.FALSE, 0, 0); checkGLError();
// enable attribute 1 (texture coordinates (UVs))
GPU_Static.gl_context.enableVertexAttribArray(1); checkGLError();
// mark texture coordinates (UVs) as 2 component floats
GPU_Static.gl_context.vertexAttribPointer(1, 2, GPU_Static.gl_context.FLOAT, GPU_Static.gl_context.FALSE, 0, GPU_Static.gl_context.texture_coordinates_offset); checkGLError();
// load time into shader
GPU_Static.gl_context.uniform1f(GPU_Static.gl_context.getUniformLocation(ref.shader_program, 'time'), new Date().getTime()); checkGLError();
console.log('draw prepped');
},
bind_textures_to_GPU: function () {
console.log('binding textures to gpu');
// iterate through textures
for (var t = 0; t < ref.tex.length; t++) {
console.log('binding texture ' + t + ' to gpu');
// mark active texture
GPU_Static.gl_context.activeTexture(GPU_Static.gl_context.TEXTURE0 + t); checkGLError();
// create a texture on the gpu
var texture = GPU_Static.gl_context.createTexture(); checkGLError();
// bind the created texture
GPU_Static.gl_context.bindTexture(GPU_Static.gl_context.TEXTURE_2D, texture); checkGLError();
// set texture wrap S to clamp to edge (this is critical for the pipeline to function)
GPU_Static.gl_context.texParameteri(GPU_Static.gl_context.TEXTURE_2D, GPU_Static.gl_context.TEXTURE_WRAP_S, GPU_Static.gl_context.CLAMP_TO_EDGE); checkGLError();
// set texture wrap T to clamp to edge (this is critical for the pipeline to function)
GPU_Static.gl_context.texParameteri(GPU_Static.gl_context.TEXTURE_2D, GPU_Static.gl_context.TEXTURE_WRAP_T, GPU_Static.gl_context.CLAMP_TO_EDGE); checkGLError();
// set texture minification filter to nearest (this is critical for the pipeline to function)
GPU_Static.gl_context.texParameteri(GPU_Static.gl_context.TEXTURE_2D, GPU_Static.gl_context.TEXTURE_MIN_FILTER, GPU_Static.gl_context.NEAREST); checkGLError();
// set texture magnification to nearest (this is critical for the pipeline to function)
GPU_Static.gl_context.texParameteri(GPU_Static.gl_context.TEXTURE_2D, GPU_Static.gl_context.TEXTURE_MAG_FILTER, GPU_Static.gl_context.NEAREST); checkGLError();
// set texture unpack alignment (this is critical for the pipeline to function)
GPU_Static.gl_context.pixelStorei(GPU_Static.gl_context.UNPACK_ALIGNMENT, 1); checkGLError();
// set texture type (RGBA), size (width/height), type (float/byte), and copy texture buffer
GPU_Static.gl_context.texImage2D(GPU_Static.gl_context.TEXTURE_2D, 0, GPU_Static.gl_context.RGBA, ref.canvas.width, ref.canvas.height, 0, GPU_Static.gl_context.RGBA, ref.bytes_in_flag ? GPU_Static.gl_context.UNSIGNED_BYTE : GPU_Static.gl_context.FLOAT, ref.tex[t]); checkGLError();
// get texture locator from context
var texture_location = GPU_Static.gl_context.getUniformLocation(ref.shader_program, 'tex' + t); checkGLError();
// connect texture?
GPU_Static.gl_context.uniform1i(texture_location, t); checkGLError();
}
console.log('bound ' + t + ' textures to gpu');
},
draw: function () {
console.log('drawing');
// anticlimactic draw call
GPU_Static.gl_context.drawArrays(GPU_Static.gl_context.TRIANGLES, 0, 6);
// check for gl errors
checkGLError();
// finish up our draw
GPU_Static.gl_context.finish();
console.log('draw done');
},
read_bytes_out: function () {
console.log('reading bytes out');
// allocate array of texture size by components RGBA
ref.output = new Uint8Array(ref.canvas.width * ref.canvas.height * 4);
// read output into output
GPU_Static.gl_context.readPixels(0, 0, ref.canvas.width, ref.canvas.height, GPU_Static.gl_context.RGBA, GPU_Static.gl_context.UNSIGNED_BYTE, ref.output);
console.log('read bytes out');
},
read_floats_out: function () {
// read output as bytes
ref.read_bytes_out();
console.log('reading floats from bytes');
// convert output to floats
ref.output = new Float32Array(ref.output.buffer);
console.log('read floats from bytes');
}
};
// return the baked GPU calling object
return callback(ref);
};
function internal__load_shader (type, shader_source_string) {
// create the shader base
var shader = GPU_Static.gl_context.createShader(type);
// provide the shader source
GPU_Static.gl_context.shaderSource(shader, shader_source_string);
// attempt to compile the shader
GPU_Static.gl_context.compileShader(shader);
// if an error occured while compiling the shader
if (!GPU_Static.gl_context.getShaderParameter(shader, GPU_Static.gl_context.COMPILE_STATUS) || GPU_Static.gl_context.isContextLost()) {
// alert the user of the error
throw 'ERROR COMPILING SHADER:\n' + GPU_Static.gl_context.getShaderInfoLog(shader);
// attempt to cleanup the mess
GPU_Static.gl_context.deleteShader(shader);
// return no shader
return null;
}
// shader compiled successfully, return shader
return shader;
};
function internal__initialize_fragment_shader (fragment_shader_descriptor) {
console.log('initializing fragment shader');
// mustache swap in the user functions and main body
var fragment_shader = fragment_SHADER_STRING.split('{{user_functions}}').join(fragment_shader_descriptor.user_functions)
.split('{{body}}') .join(fragment_shader_descriptor.body);
// load the fragment shader
fragment_shader = internal__load_shader(GPU_Static.gl_context.FRAGMENT_SHADER, fragment_shader);
console.log('fragment shader initialized');
// return the loaded shader
return fragment_shader;
};
function internal__build_shader_program (vertex_shader, fragment_shader) {
// create the shader program
var shader_program = GPU_Static.gl_context.createProgram();
// attach the vertex shader to the program
GPU_Static.gl_context.attachShader(shader_program, vertex_shader);
// attach the fragment shader to the program
GPU_Static.gl_context.attachShader(shader_program, fragment_shader);
// bind the position attribute location in the program
GPU_Static.gl_context.bindAttribLocation(shader_program, 0, 'g_Position');
// bind the texture coordinate (UV) attribute location in the program
GPU_Static.gl_context.bindAttribLocation(shader_program, 1, 'g_TexCoord0');
// perform the compilation/linkage of the programs
GPU_Static.gl_context.linkProgram(shader_program);
// check the result of linking the shader program
var result = GPU_Static.gl_context.getProgramParameter(shader_program, GPU_Static.gl_context.LINK_STATUS);
// if linking failed or we lost context
if (!result || GPU_Static.gl_context.isContextLost()) {
// alert the user there was an error
throw 'ERROR LINKED SHADER PROGRAM:\n' + GPU_Static.gl_context.getProgramInfoLog(shader_program);
// attempt to cleanup the program
GPU_Static.gl_context.deleteProgram(SHADER_PROGRAM);
// return no shader program
return null;
}
// linking suceeded, return linked shader program
return shader_program;
};
function internal__setup_textures (in_parameter_count, bytes_in_flag) {
// ensure the bounding of the in parameters
if (in_parameter_count < 0 || in_parameter_count > 64) throw 'ERROR: in_parameter_count OUT OF BOUNDS (0-64)';
// calculate the number of textures needed
var textures_needed = Math.ceil(in_parameter_count / 4);
// create an array to represent pixel components
var pixels = [];
// iterate over the width of the context canvas
for (var x = 0; x < GPU_Static.canvas.width; x++) {
// iterate over the height of the context canvas
for (var y = 0; y < GPU_Static.canvas.height; y++) {
// iterate over the components of a pixel RGBA
for (var r = 0; r < 4; r++) {
// add a pixel
pixels.push(0);
}
}
}
// create texture holder
var textures = [];
// iterate to create textures
for (var t = 0; t < textures_needed; t++) {
// if we are inputting bytes
if (bytes_in_flag) {
// add a byte texture
textures.push(new Uint8Array(pixels));
// otherwise we are inputting floats
} else {
// add a float texture
textures.push(new Float32Array(pixels));
}
}
// return created zero textures
return textures;
};
</script>
</head>
<body style="padding-left: 10%; padding-top: 5%;" onload="main()">
<div style="text-align: center">
<canvas id="canvas" width="1024" height="1024">
</canvas>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment