"use strict" //============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piCamera // //============================================================================== function piCamera() { var mMatrix = setIdentity(); var mMatrixInv = setIdentity(); var mPosition = [0.0,0.0,0.0]; var mXRotation = 0.0; var mYRotation = 0.0; var mPositionTarget = [0.0,0.0,0.0]; var mXRotationTarget = 0.0; var mYRotationTarget = 0.0; var me = {}; me.SetPos = function(pos) { mPosition = pos; }; me.LocalMove = function( dis ) { dis = matMulvec( setRotationY(-mYRotation), dis); mPositionTarget = sub(mPositionTarget,dis) }; me.RotateXY = function( x, y) { mXRotationTarget -= x; mYRotationTarget -= y; mXRotationTarget = Math.min( Math.max( mXRotationTarget, -Math.PI/2), Math.PI/2 ); }; me.CameraExectue = function( dt ) { // smooth position mXRotation += (mXRotationTarget-mXRotation) * 12.0*dt; mYRotation += (mYRotationTarget-mYRotation) * 12.0*dt; mPosition = add(mPosition, mul( sub(mPositionTarget, mPosition), 12.0*dt)); // Make Camera matrix mMatrix = matMul( matMul(setRotationX(mXRotation), setRotationY(mYRotation)), setTranslation(mPosition)); mMatrixInv = invertFast(mMatrix); } me.GetMatrix = function() { return mMatrix; }; me.GetMatrixInverse = function() { return mMatrixInv; }; me.SetMatrix = function( mat ) { mMatrix = mat; mMatrixInv = invertFast(mMatrix); mPosition = getXYZ(matMulpoint(mat, [0.0,0.0,0.0])); mPositionTarget = mPosition; }; me.GetPos = function() { return getXYZ(matMulpoint(mMatrixInv, [0.0,0.0,0.0])); } me.GetDir = function() { return getXYZ(normalize(matMulvec(mMatrixInv, [0.0,0.0,-1.0]))); } return me; } //============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piFile // //============================================================================== function piFile( binaryDataArrayBuffer ) { // private var mDataView = binaryDataArrayBuffer; var mOffset = 0; // public members var me = {}; me.mDummy = 0; me.Seek = function( off ) { mOffset = off; }; me.ReadUInt8 = function() { var res = (new Uint8Array(mDataView,mOffset))[0]; mOffset+=1; return res; }; me.ReadUInt16 = function() { var res = (new Uint16Array(mDataView,mOffset))[0]; mOffset+=2; return res; }; me.ReadUInt32 = function() { var res = (new Uint32Array(mDataView,mOffset))[0]; mOffset+=4; return res; }; me.ReadUInt64 = function() { return me.ReadUInt32() + (me.ReadUInt32()<<32); }; me.ReadFloat32 = function() { var res = (new Float32Array(mDataView,mOffset))[0]; mOffset+=4; return res; }; me.ReadFloat32Array = function(n) { var src = new Float32Array(mDataView, mOffset); var res = []; for( var i=0; i 0 && t0 != null) { mGL.activeTexture(mGL.TEXTURE0); if (t0.mType === me.TEXTYPE.T2D) mGL.bindTexture(mGL.TEXTURE_2D, t0.mObjectID); else if (t0.mType === me.TEXTYPE.T3D) mGL.bindTexture(mGL.TEXTURE_3D, t0.mObjectID); else if (t0.mType === me.TEXTYPE.CUBEMAP) mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, t0.mObjectID); } if (num > 1 && t1 != null) { mGL.activeTexture(mGL.TEXTURE1); if (t1.mType === me.TEXTYPE.T2D) mGL.bindTexture(mGL.TEXTURE_2D, t1.mObjectID); else if (t1.mType === me.TEXTYPE.T3D) mGL.bindTexture(mGL.TEXTURE_3D, t1.mObjectID); else if (t1.mType === me.TEXTYPE.CUBEMAP) mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, t1.mObjectID); } if (num > 2 && t2 != null) { mGL.activeTexture(mGL.TEXTURE2); if (t2.mType === me.TEXTYPE.T2D) mGL.bindTexture(mGL.TEXTURE_2D, t2.mObjectID); else if (t2.mType === me.TEXTYPE.T3D) mGL.bindTexture(mGL.TEXTURE_3D, t2.mObjectID); else if (t2.mType === me.TEXTYPE.CUBEMAP) mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, t2.mObjectID); } if (num > 3 && t3 != null) { mGL.activeTexture(mGL.TEXTURE3); if (t3.mType === me.TEXTYPE.T2D) mGL.bindTexture(mGL.TEXTURE_2D, t3.mObjectID); else if (t3.mType === me.TEXTYPE.T3D) mGL.bindTexture(mGL.TEXTURE_3D, t3.mObjectID); else if (t3.mType === me.TEXTYPE.CUBEMAP) mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, t3.mObjectID); } }; me.DettachTextures = function() { mGL.activeTexture(mGL.TEXTURE0); mGL.bindTexture(mGL.TEXTURE_2D, null); mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, null); mGL.activeTexture(mGL.TEXTURE1); mGL.bindTexture(mGL.TEXTURE_2D, null); mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, null); mGL.activeTexture(mGL.TEXTURE2); mGL.bindTexture(mGL.TEXTURE_2D, null); mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, null); mGL.activeTexture(mGL.TEXTURE3); mGL.bindTexture(mGL.TEXTURE_2D, null); mGL.bindTexture(mGL.TEXTURE_CUBE_MAP, null); }; me.CreateRenderTarget = function ( color0, color1, color2, color3, depth, wantZbuffer ) { var id = mGL.createFramebuffer(); mGL.bindFramebuffer(mGL.FRAMEBUFFER, id); if (depth === null) { if( wantZbuffer===true ) { var zb = mGL.createRenderbuffer(); mGL.bindRenderbuffer(mGL.RENDERBUFFER, zb); mGL.renderbufferStorage(mGL.RENDERBUFFER, mGL.DEPTH_COMPONENT16, color0.mXres, color0.mYres); mGL.framebufferRenderbuffer(mGL.FRAMEBUFFER, mGL.DEPTH_ATTACHMENT, mGL.RENDERBUFFER, zb); } } else { mGL.framebufferTexture2D(mGL.FRAMEBUFFER, mGL.DEPTH_ATTACHMENT, mGL.TEXTURE_2D, depth.mObjectID, 0); } if( color0 !=null ) mGL.framebufferTexture2D(mGL.FRAMEBUFFER, mGL.COLOR_ATTACHMENT0, mGL.TEXTURE_2D, color0.mObjectID, 0); if (mGL.checkFramebufferStatus(mGL.FRAMEBUFFER) != mGL.FRAMEBUFFER_COMPLETE) return null; mGL.bindRenderbuffer(mGL.RENDERBUFFER, null); mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); return { mObjectID: id, mTex0: color0 }; }; me.DestroyRenderTarget = function ( tex ) { mGL.deleteFramebuffer(tex.mObjectID); }; me.SetRenderTarget = function (tex) { if( tex===null ) mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); else mGL.bindFramebuffer(mGL.FRAMEBUFFER, tex.mObjectID); //mGL.drawBuffers([mGL.COLOR_ATTACHMENT0, mGL.COLOR_ATTACHMENT1]); }; me.CreateRenderTargetNew = function ( wantColor0, wantZbuffer, xres, yres, samples ) { var id = mGL.createFramebuffer(); mGL.bindFramebuffer(mGL.FRAMEBUFFER, id); if( wantZbuffer===true ) { var zb = mGL.createRenderbuffer(); mGL.bindRenderbuffer(mGL.RENDERBUFFER, zb); if( samples==1 ) mGL.renderbufferStorage(mGL.RENDERBUFFER, mGL.DEPTH_COMPONENT16, xres, yres); else mGL.renderbufferStorageMultisample(mGL.RENDERBUFFER, samples, mGL.DEPTH_COMPONENT16, xres, yres); mGL.framebufferRenderbuffer(mGL.FRAMEBUFFER, mGL.DEPTH_ATTACHMENT, mGL.RENDERBUFFER, zb); } if( wantColor0 ) { var cb = mGL.createRenderbuffer(); mGL.bindRenderbuffer(mGL.RENDERBUFFER, cb); if( samples==1 ) mGL.renderbufferStorage(mGL.RENDERBUFFER, mGL.RGBA8, xres, yres); else mGL.renderbufferStorageMultisample(mGL.RENDERBUFFER, samples, mGL.RGBA8, xres, yres); mGL.framebufferRenderbuffer(mGL.FRAMEBUFFER, mGL.COLOR_ATTACHMENT0, mGL.RENDERBUFFER, cb); } if (mGL.checkFramebufferStatus(mGL.FRAMEBUFFER) != mGL.FRAMEBUFFER_COMPLETE) { return null; } mGL.bindRenderbuffer(mGL.RENDERBUFFER, null); mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); return { mObjectID: id, mXres: xres, mYres:yres, mTex0: color0 }; }; me.CreateRenderTargetCubeMap = function ( color0, depth, wantZbuffer ) { var id = mGL.createFramebuffer(); mGL.bindFramebuffer(mGL.FRAMEBUFFER, id); if (depth === null) { if( wantZbuffer===true ) { var zb = mGL.createRenderbuffer(); mGL.bindRenderbuffer(mGL.RENDERBUFFER, zb); mGL.renderbufferStorage(mGL.RENDERBUFFER, mGL.DEPTH_COMPONENT16, color0.mXres, color0.mYres); mGL.framebufferRenderbuffer(mGL.FRAMEBUFFER, mGL.DEPTH_ATTACHMENT, mGL.RENDERBUFFER, zb); } } else { mGL.framebufferTexture2D(mGL.FRAMEBUFFER, mGL.DEPTH_ATTACHMENT, mGL.TEXTURE_2D, depth.mObjectID, 0); } if( color0 !=null ) mGL.framebufferTexture2D(mGL.FRAMEBUFFER, mGL.COLOR_ATTACHMENT0, mGL.TEXTURE_CUBE_MAP_POSITIVE_X, color0.mObjectID, 0); if (mGL.checkFramebufferStatus(mGL.FRAMEBUFFER) != mGL.FRAMEBUFFER_COMPLETE) return null; mGL.bindRenderbuffer(mGL.RENDERBUFFER, null); mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); return { mObjectID: id, mTex0: color0 }; }; me.SetRenderTargetCubeMap = function (fbo, face) { if( fbo===null ) mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); else { mGL.bindFramebuffer(mGL.FRAMEBUFFER, fbo.mObjectID); mGL.framebufferTexture2D(mGL.FRAMEBUFFER, mGL.COLOR_ATTACHMENT0, mGL.TEXTURE_CUBE_MAP_POSITIVE_X+face, fbo.mTex0.mObjectID, 0); } }; me.BlitRenderTarget = function( dst, src ) { mGL.bindFramebuffer(mGL.READ_FRAMEBUFFER, src.mObjectID); mGL.bindFramebuffer(mGL.DRAW_FRAMEBUFFER, dst.mObjectID); mGL.clearBufferfv(mGL.COLOR, 0, [0.0, 0.0, 0.0, 1.0]); mGL.blitFramebuffer( 0, 0, src.mXres, src.mYres, 0, 0, src.mXres, src.mYres, mGL.COLOR_BUFFER_BIT, mGL.LINEAR ); }; me.SetViewport = function( vp ) { mGL.viewport( vp[0], vp[1], vp[2], vp[3] ); }; me.SetWriteMask = function( c0, c1, c2, c3, z ) { mGL.depthMask(z); mGL.colorMask(c0,c0,c0,c0); }; me.SetState = function( stateName, stateValue ) { if (stateName === me.RENDSTGATE.WIREFRAME) { if( stateValue ) mGL.polygonMode( mGL.FRONT_AND_BACK, mGL.LINE ); else mGL.polygonMode( mGL.FRONT_AND_BACK, mGL.FILL ); } else if (stateName === me.RENDSTGATE.FRONT_FACE) { if( stateValue ) mGL.cullFace( mGL.BACK ); else mGL.cullFace( mGL.FRONT ); } else if (stateName === me.RENDSTGATE.CULL_FACE) { if( stateValue ) mGL.enable( mGL.CULL_FACE ); else mGL.disable( mGL.CULL_FACE ); } else if (stateName === me.RENDSTGATE.DEPTH_TEST) { if( stateValue ) mGL.enable( mGL.DEPTH_TEST ); else mGL.disable( mGL.DEPTH_TEST ); } else if (stateName === me.RENDSTGATE.ALPHA_TO_COVERAGE) { if( stateValue ) { mGL.enable( mGL.SAMPLE_ALPHA_TO_COVERAGE ); } else { mGL.disable( mGL.SAMPLE_ALPHA_TO_COVERAGE ); } } }; me.SetMultisample = function( v) { if( v===true ) { mGL.enable(mGL.SAMPLE_COVERAGE); mGL.sampleCoverage(1.0, false); } else { mGL.disable(mGL.SAMPLE_COVERAGE); } }; me.GetTranslatedShaderSource = function (shader) { if( mGL===null ) return null; if( mDebugShader===null ) return null; let vfs = mGL.getAttachedShaders(shader.mProgram); let str = mDebugShader.getTranslatedShaderSource(vfs[1]); let parts = str.split("GLSL END"); str = (parts.length<2) ? str : parts[1]; return str; }; me.CreateShader = function (vsSource, fsSource, preventCache, forceSynch, onResolve) { if( mGL===null ) return; var vs = mGL.createShader( mGL.VERTEX_SHADER ); var fs = mGL.createShader( mGL.FRAGMENT_SHADER ); vsSource = mShaderHeader[0] + vsSource; fsSource = mShaderHeader[1] + fsSource; if( preventCache ) { let vran = Math.random().toString(36).substring(7); let fran = Math.random().toString(36).substring(7); vsSource += "\n#define K" + vran + "\n"; fsSource += "\n#define K" + fran + "\n"; } var timeStart = (new Date()).getTime(); mGL.shaderSource(vs, vsSource); mGL.shaderSource(fs, fsSource); mGL.compileShader(vs); mGL.compileShader(fs); var pr = mGL.createProgram(); mGL.attachShader(pr, vs); mGL.attachShader(pr, fs); mGL.linkProgram(pr); //------------- let checkErrors = function() { if (!mGL.getProgramParameter(pr, mGL.LINK_STATUS)) { // vs error if (!mGL.getShaderParameter(vs, mGL.COMPILE_STATUS)) { let vsLog = mGL.getShaderInfoLog(vs); onResolve(false, { mErrorType: 0, mErrorStr: vsLog }); mGL.deleteProgram(pr); } // fs error else if (!mGL.getShaderParameter(fs, mGL.COMPILE_STATUS)) { let fsLog = mGL.getShaderInfoLog(fs); onResolve(false, { mErrorType: 1, mErrorStr: fsLog }); mGL.deleteProgram(pr); } // link error else { let infoLog = mGL.getProgramInfoLog(pr); onResolve(false, { mErrorType: 2, mErrorStr: infoLog }); mGL.deleteProgram(pr); } } // no errors else { let compilationTime = (new Date()).getTime() - timeStart; onResolve(true, { mProgram: pr, mTime: compilationTime }); } }; // check compilation if (mAsynchCompile === null || forceSynch===true ) { checkErrors(); } else { let loopCheckCompletion = function () { if( mGL.getProgramParameter(pr, mAsynchCompile.COMPLETION_STATUS_KHR) === true ) checkErrors(); else setTimeout(loopCheckCompletion, 10); }; setTimeout(loopCheckCompletion, 10); } }; me.AttachShader = function( shader ) { if( shader===null ) { mBindedShader = null; mGL.useProgram( null ); } else { mBindedShader = shader; mGL.useProgram(shader.mProgram); } }; me.DetachShader = function () { mGL.useProgram(null); }; me.DestroyShader = function( tex ) { mGL.deleteProgram(tex.mProgram); }; me.GetAttribLocation = function (shader, name) { return mGL.getAttribLocation(shader.mProgram, name); }; me.SetShaderConstantLocation = function (shader, name) { return mGL.getUniformLocation(shader.mProgram, name); }; me.SetShaderConstantMat4F = function( uname, params, istranspose ) { var program = mBindedShader; let pos = mGL.getUniformLocation( program.mProgram, uname ); if( pos===null ) return false; if( istranspose===false ) { var tmp = new Float32Array( [ params[0], params[4], params[ 8], params[12], params[1], params[5], params[ 9], params[13], params[2], params[6], params[10], params[14], params[3], params[7], params[11], params[15] ] ); mGL.uniformMatrix4fv(pos,false,tmp); } else mGL.uniformMatrix4fv(pos,false,new Float32Array(params) ); return true; }; me.SetShaderConstant1F_Pos = function(pos, x) { mGL.uniform1f(pos, x); return true; }; me.SetShaderConstant1FV_Pos = function(pos, x) { mGL.uniform1fv(pos, x); return true; }; me.SetShaderConstant1F = function( uname, x ) { var pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform1f(pos, x); return true; }; me.SetShaderConstant1I = function(uname, x) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform1i(pos, x); return true; }; me.SetShaderConstant1I_Pos = function(pos, x) { mGL.uniform1i(pos, x); return true; }; me.SetShaderConstant2F = function(uname, x) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform2fv(pos, x); return true; }; me.SetShaderConstant3F = function(uname, x, y, z) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform3f(pos, x, y, z); return true; }; me.SetShaderConstant1FV = function(uname, x) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform1fv(pos, new Float32Array(x)); return true; }; me.SetShaderConstant3FV = function(uname, x) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform3fv(pos, new Float32Array(x) ); return true; }; me.SetShaderConstant4FV = function(uname, x) { let pos = mGL.getUniformLocation(mBindedShader.mProgram, uname); if (pos === null) return false; mGL.uniform4fv(pos, new Float32Array(x) ); return true; }; me.SetShaderTextureUnit = function( uname, unit ) { var program = mBindedShader; let pos = mGL.getUniformLocation(program.mProgram, uname); if (pos === null) return false; mGL.uniform1i(pos, unit); return true; }; me.CreateVertexArray = function( data, mode ) { let id = mGL.createBuffer(); mGL.bindBuffer(mGL.ARRAY_BUFFER, id); if (mode === me.BUFTYPE.STATIC) mGL.bufferData(mGL.ARRAY_BUFFER, data, mGL.STATIC_DRAW); else mGL.bufferData(mGL.ARRAY_BUFFER, data, mGL.DYNAMIC_DRAW); return { mObject: id }; }; me.CreateIndexArray = function( data, mode ) { let id = mGL.createBuffer(); mGL.bindBuffer(mGL.ELEMENT_ARRAY_BUFFER, id ); if (mode === me.BUFTYPE.STATIC) mGL.bufferData(mGL.ELEMENT_ARRAY_BUFFER, data, mGL.STATIC_DRAW); else mGL.bufferData(mGL.ELEMENT_ARRAY_BUFFER, data, mGL.DYNAMIC_DRAW); return { mObject: id }; }; me.DestroyArray = function( tex ) { mGL.destroyBuffer(tex.mObject); }; me.AttachVertexArray = function( tex, attribs, pos ) { let shader = mBindedShader; mGL.bindBuffer( mGL.ARRAY_BUFFER, tex.mObject); var num = attribs.mChannels.length; var stride = attribs.mStride; var offset = 0; for (var i = 0; i < num; i++) { var id = pos[i]; mGL.enableVertexAttribArray(id); var dtype = mGL.FLOAT; var dsize = 4; if( attribs.mChannels[i].mType === me.TYPE.UINT8 ) { dtype = mGL.UNSIGNED_BYTE; dsize = 1; } else if( attribs.mChannels[i].mType === me.TYPE.UINT16 ) { dtype = mGL.UNSIGNED_SHORT; dsize = 2; } else if( attribs.mChannels[i].mType === me.TYPE.FLOAT32 ) { dtype = mGL.FLOAT; dsize = 4; } mGL.vertexAttribPointer(id, attribs.mChannels[i].mNumComponents, dtype, attribs.mChannels[i].mNormalize, stride, offset); offset += attribs.mChannels[i].mNumComponents * dsize; } }; me.AttachIndexArray = function( tex ) { mGL.bindBuffer(mGL.ELEMENT_ARRAY_BUFFER, tex.mObject); }; me.DetachVertexArray = function (tex, attribs) { let num = attribs.mChannels.length; for (let i = 0; i < num; i++) mGL.disableVertexAttribArray(i); mGL.bindBuffer(mGL.ARRAY_BUFFER, null); }; me.DetachIndexArray = function( tex ) { mGL.bindBuffer(mGL.ELEMENT_ARRAY_BUFFER, null); }; me.DrawPrimitive = function( typeOfPrimitive, num, useIndexArray, numInstances ) { let glType = mGL.POINTS; if( typeOfPrimitive===me.PRIMTYPE.POINTS ) glType = mGL.POINTS; if( typeOfPrimitive===me.PRIMTYPE.LINES ) glType = mGL.LINES; if( typeOfPrimitive===me.PRIMTYPE.LINE_LOOP ) glType = mGL.LINE_LOOP; if( typeOfPrimitive===me.PRIMTYPE.LINE_STRIP ) glType = mGL.LINE_STRIP; if( typeOfPrimitive===me.PRIMTYPE.TRIANGLES ) glType = mGL.TRIANGLES; if( typeOfPrimitive===me.PRIMTYPE.TRIANGLE_STRIP ) glType = mGL.TRIANGLE_STRIP; if( numInstances<=1 ) { if( useIndexArray ) mGL.drawElements( glType, num, mGL.UNSIGNED_SHORT, 0 ); else mGL.drawArrays( glType, 0, num ); } else { mGL.drawArraysInstanced(glType, 0, num, numInstances); mGL.drawElementsInstanced( glType, num, mGL.UNSIGNED_SHORT, 0, numInstances); } }; me.DrawFullScreenTriangle_XY = function( vpos ) { mGL.bindBuffer( mGL.ARRAY_BUFFER, mVBO_Tri ); mGL.vertexAttribPointer( vpos, 2, mGL.FLOAT, false, 0, 0 ); mGL.enableVertexAttribArray( vpos ); mGL.drawArrays( mGL.TRIANGLES, 0, 3 ); mGL.disableVertexAttribArray( vpos ); mGL.bindBuffer( mGL.ARRAY_BUFFER, null ); }; me.DrawUnitQuad_XY = function( vpos ) { mGL.bindBuffer( mGL.ARRAY_BUFFER, mVBO_Quad ); mGL.vertexAttribPointer( vpos, 2, mGL.FLOAT, false, 0, 0 ); mGL.enableVertexAttribArray( vpos ); mGL.drawArrays( mGL.TRIANGLES, 0, 6 ); mGL.disableVertexAttribArray( vpos ); mGL.bindBuffer( mGL.ARRAY_BUFFER, null ); }; me.DrawUnitCube_XYZ_NOR = function( vpos ) { mGL.bindBuffer( mGL.ARRAY_BUFFER, mVBO_CubePosNor ); mGL.vertexAttribPointer( vpos[0], 3, mGL.FLOAT, false, 0, 0 ); mGL.vertexAttribPointer( vpos[1], 3, mGL.FLOAT, false, 0, 0 ); mGL.enableVertexAttribArray( vpos[0] ); mGL.enableVertexAttribArray( vpos[1] ); mGL.drawArrays(mGL.TRIANGLE_STRIP, 0, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 4, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 8, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 12, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 16, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 20, 4); mGL.disableVertexAttribArray( vpos[0] ); mGL.disableVertexAttribArray( vpos[1] ); mGL.bindBuffer( mGL.ARRAY_BUFFER, null ); } me.DrawUnitCube_XYZ = function( vpos ) { mGL.bindBuffer( mGL.ARRAY_BUFFER, mVBO_CubePos ); mGL.vertexAttribPointer( vpos, 3, mGL.FLOAT, false, 0, 0 ); mGL.enableVertexAttribArray( vpos ); mGL.drawArrays(mGL.TRIANGLE_STRIP, 0, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 4, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 8, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 12, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 16, 4); mGL.drawArrays(mGL.TRIANGLE_STRIP, 20, 4); mGL.disableVertexAttribArray( vpos ); mGL.bindBuffer( mGL.ARRAY_BUFFER, null ); } me.SetBlend = function( enabled ) { if( enabled ) { mGL.enable( mGL.BLEND ); mGL.blendEquationSeparate( mGL.FUNC_ADD, mGL.FUNC_ADD ); mGL.blendFuncSeparate( mGL.SRC_ALPHA, mGL.ONE_MINUS_SRC_ALPHA, mGL.ONE, mGL.ONE_MINUS_SRC_ALPHA ); } else { mGL.disable( mGL.BLEND ); } }; me.GetPixelData = function( data, offset, xres, yres ) { mGL.readPixels(0, 0, xres, yres, mGL.RGBA, mGL.UNSIGNED_BYTE, data, offset); }; me.GetPixelDataRenderTarget = function( obj, data, xres, yres ) { mGL.bindFramebuffer(mGL.FRAMEBUFFER, obj.mObjectID); mGL.readBuffer(mGL.COLOR_ATTACHMENT0); mGL.readPixels(0, 0, xres, yres, mGL.RGBA, mGL.FLOAT, data, 0); mGL.bindFramebuffer(mGL.FRAMEBUFFER, null); }; return me; } //============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piShading // //============================================================================== function smoothstep(a, b, x) { x = (x - a) / (b - a); if (x < 0) x = 0; else if (x > 1) x = 1; return x * x * (3.0 - 2.0 * x); } function clamp01(x) { if( x < 0.0 ) x = 0.0; if( x > 1.0 ) x = 1.0; return x; } function clamp(x, a, b) { if( x < a ) x = a; if( x > b ) x = b; return x; } function screen(a, b) { return 1.0 - (1.0 - a) * (1.0 - b); } function parabola(x) { return 4.0 * x * (1.0 - x); } function min(a, b) { return (a < b) ? a : b; } function max(a, b) { return (a > b) ? a : b; } function noise( x ) { function grad(i, j, x, y) { var h = 7 * i + 131 * j; h = (h << 13) ^ h; h = (h * (h * h * 15731 + 789221) + 1376312589); var rx = (h & 0x20000000) ? x : -x; var ry = (h & 0x10000000) ? y : -y; return rx + ry; } var i = [ Math.floor(x[0]), Math.floor(x[1]) ]; var f = [ x[0] - i[0], x[1] - i[1] ]; var w = [ f[0]*f[0]*(3.0-2.0*f[0]), f[1]*f[1]*(3.0-2.0*f[1]) ]; var a = grad( i[0]+0, i[1]+0, f[0]+0.0, f[1]+0.0 ); var b = grad( i[0]+1, i[1]+0, f[0]-1.0, f[1]+0.0 ); var c = grad( i[0]+0, i[1]+1, f[0]+0.0, f[1]-1.0 ); var d = grad( i[0]+1, i[1]+1, f[0]-1.0, f[1]-1.0 ); return a + (b-a)*w[0] + (c-a)*w[1] + (a-b-c+d)*w[0]*w[1]; }//============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piVecTypes // //============================================================================== function vec3( a, b, c ) { return [ a, b, c ]; } function add( a, b ) { return [ a[0]+b[0], a[1]+b[1], a[2]+b[2] ]; } function sub( a, b ) { return [ a[0]-b[0], a[1]-b[1], a[2]-b[2] ]; } function mul( a, s ) { return [ a[0]*s, a[1]*s, a[2]*s ]; } function cross( a, b ) { return [ a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0] ]; } function dot( a, b ) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } function normalize( v ) { var is = 1.0 / Math.sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ); return [ v[0]*is, v[1]*is, v[2]*is ]; } function createCirclePoint( cen, uuu, vvv, rad, s, t ) { return [ cen[0] + rad*(uuu[0]*s + vvv[0]*t), cen[1] + rad*(uuu[1]*s + vvv[1]*t), cen[2] + rad*(uuu[2]*s + vvv[2]*t) ]; } function createTangent( a, b, c ) { var cb = normalize( [ c[0]-b[0], c[1]-b[1], c[2]-b[2] ] ); var ba = normalize( [ b[0]-a[0], b[1]-a[1], b[2]-a[2] ] ); return normalize( [ ba[0]+cb[0], ba[1]+cb[1], ba[2]+cb[2] ] ); } //=================================== function vec4( a, b, c, d ) { return [ a, b, c, d ]; } function getXYZ( v ) { return [ v[0], v[1], v[2] ]; } //=================================== function setIdentity() { return [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ]; } function setRotationX( t ) { var sint = Math.sin(t); var cost = Math.cos(t); return [ 1.0, 0.0, 0.0, 0.0, 0.0, cost, -sint, 0.0, 0.0, sint, cost, 0.0, 0.0, 0.0, 0.0, 1.0 ]; } function setRotationY( t ) { var sint = Math.sin(t); var cost = Math.cos(t); return [ cost, 0.0, -sint, 0.0, 0.0, 1.0, 0.0, 0.0, sint, 0.0, cost, 0.0, 0.0, 0.0, 0.0, 1.0 ]; } function extractRotationEuler( m) { var res = []; if (m[0] == 1.0) { res[0] = Math.atan2(m[2], m[11]); res[1] = 0.0; res[2] = 0.0; } else if (m[0] == -1.0) { res[0] = Math.atan2( m[2], m[11]); res[1] = 0.0; res[2] = 0.0; } else { res[0] = Math.atan2( -m[9], m[10]); res[1] = Math.atan2( m[8], Math.sqrt(m[9]*m[9] + m[10]*m[10])); res[2] = Math.atan2( m[4], m[0]); } return res; } function setFromQuaternion( q ) { var ww = q[3]*q[3]; var xx = q[0]*q[0]; var yy = q[1]*q[1]; var zz = q[2]*q[2]; return [ ww+xx-yy-zz, 2.0*(q[0]*q[1] - q[3]*q[2]), 2.0*(q[0]*q[2] + q[3]*q[1]), 0.0, 2.0*(q[0]*q[1] + q[3]*q[2]), ww-xx+yy-zz, 2.0*(q[1]*q[2] - q[3]*q[0]), 0.0, 2.0*(q[0]*q[2] - q[3]*q[1]), 2.0*(q[1]*q[2] + q[3]*q[0]), ww-xx-yy+zz, 0.0, 0.0, 0.0, 0.0, 1.0 ]; } function setPerspective( fovy, aspect, znear, zfar ) { var tan = Math.tan(fovy * Math.PI/180.0); var x = 1.0 / (tan*aspect); var y = 1.0 / (tan); var c = -(zfar + znear) / ( zfar - znear); var d = -(2.0 * zfar * znear) / (zfar - znear); return [ x, 0.0, 0.0, 0.0, 0.0, y, 0.0, 0.0, 0.0, 0.0, c, d, 0.0, 0.0, -1.0, 0.0 ]; } function setLookAt( eye, tar, up ) { var dir = [ -tar[0]+eye[0], -tar[1]+eye[1], -tar[2]+eye[2] ]; var m00 = dir[2]*up[1] - dir[1]*up[2]; var m01 = dir[0]*up[2] - dir[2]*up[0]; var m02 = dir[1]*up[0] - dir[0]*up[1]; var im = 1.0/Math.sqrt( m00*m00 + m01*m01 + m02*m02 ); m00 *= im; m01 *= im; m02 *= im; var m04 = m02*dir[1] - m01*dir[2]; var m05 = m00*dir[2] - m02*dir[0]; var m06 = m01*dir[0] - m00*dir[1]; im = 1.0/Math.sqrt( m04*m04 + m05*m05 + m06*m06 ); m04 *= im; m05 *= im; m06 *= im; var m08 = dir[0]; var m09 = dir[1]; var m10 = dir[2]; im = 1.0/Math.sqrt( m08*m08 + m09*m09 + m10*m10 ); m08 *= im; m09 *= im; m10 *= im; var m03 = -(m00*eye[0] + m01*eye[1] + m02*eye[2] ); var m07 = -(m04*eye[0] + m05*eye[1] + m06*eye[2] ); var m11 = -(m08*eye[0] + m09*eye[1] + m10*eye[2] ); return [ m00, m01, m02, m03, m04, m05, m06, m07, m08, m09, m10, m11, 0.0, 0.0, 0.0, 1.0 ]; } function setOrtho( left, right, bottom, top, znear, zfar ) { var x = 2.0 / (right - left); var y = 2.0 / (top - bottom); var a = (right + left) / (right - left); var b = (top + bottom) / (top - bottom); var c = -2.0 / (zfar - znear); var d = -(zfar + znear) / ( zfar - znear); return [ x, 0.0, 0.0, a, 0.0, y, 0.0, b, 0.0, 0.0, c, d, 0.0, 0.0, 0.0, 1.0 ]; } function setTranslation( p ) { return [ 1.0, 0.0, 0.0, p[0], 0.0, 1.0, 0.0, p[1], 0.0, 0.0, 1.0, p[2], 0.0, 0.0, 0.0, 1.0 ]; } function setScale( s ) { return [ s[0], 0.0, 0.0, 0.0, 0.0, s[1], 0.0, 0.0, 0.0, 0.0, s[2], 0.0, 0.0, 0.0, 0.0, 1.0]; } function setProjection( fov, znear, zfar ) { var x = 2.0 / (fov[3]+fov[2]); var y = 2.0 / (fov[0]+fov[1]); var a = (fov[3]-fov[2]) / (fov[3]+fov[2]); var b = (fov[0]-fov[1]) / (fov[0]+fov[1]); var c = -(zfar + znear) / ( zfar - znear); var d = -(2.0*zfar*znear) / (zfar - znear); return [ x, 0.0, a, 0.0, 0.0, y, b, 0.0, 0.0, 0.0, c, d, 0.0, 0.0, -1.0, 0.0 ]; // inverse is: //return mat4x4( 1.0/x, 0.0f, 0.0f, a/x, // 0.0f, 1.0/y, 0.0f, b/x, // 0.0f, 0.0f, 0.0f, -1.0, // 0.0f, 0.0f, 1.0f/d, c/d ); } function invertFast( m ) { var inv = [ m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10], -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10], m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6], -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6], -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10], m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10], -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6], m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6], m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9], -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9], m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5], -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5], -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9], m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9], -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5], m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5] ]; var det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12]; det = 1.0/det; for( var i = 0; i<16; i++ ) inv[i] = inv[i] * det; return inv; } function matMul( a, b ) { var res = []; for( var i=0; i<4; i++ ) { var x = a[4*i+0]; var y = a[4*i+1]; var z = a[4*i+2]; var w = a[4*i+3]; res[4*i+0] = x * b[ 0] + y * b[ 4] + z * b[ 8] + w * b[12]; res[4*i+1] = x * b[ 1] + y * b[ 5] + z * b[ 9] + w * b[13]; res[4*i+2] = x * b[ 2] + y * b[ 6] + z * b[10] + w * b[14]; res[4*i+3] = x * b[ 3] + y * b[ 7] + z * b[11] + w * b[15]; } return res; } function matMulpoint( m, v ) { return [ m[0]*v[0] + m[1]*v[1] + m[ 2]*v[2] + m[ 3], m[4]*v[0] + m[5]*v[1] + m[ 6]*v[2] + m[ 7], m[8]*v[0] + m[9]*v[1] + m[10]*v[2] + m[11] ]; } function matMulvec( m, v ) { return [ m[0]*v[0] + m[1]*v[1] + m[ 2]*v[2], m[4]*v[0] + m[5]*v[1] + m[ 6]*v[2], m[8]*v[0] + m[9]*v[1] + m[10]*v[2] ]; } function bound3( infi ) { return [ infi, -infi, infi, -infi, infi, -infi ]; } function bound3_include( a, p ) { return [ (p[0]a[1]) ? p[0] : a[1], (p[1]a[3]) ? p[1] : a[3], (p[2]a[5]) ? p[2] : a[5] ]; } function bound3_center( b ) { return [ 0.5*(b[0]+b[1]), 0.5*(b[2]+b[3]), 0.5*(b[4]+b[5]) ]; } function bound3_radius( b ) { return [ 0.5*(b[1]-b[0]), 0.5*(b[3]-b[2]), 0.5*(b[5]-b[4]) ]; } //============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piWebVR // //============================================================================== function WebVR( isVREnabledCallback, canvasElement ) { isVREnabledCallback(false); } WebVR.prototype.IsSupported = function() { return false; //return this.mSupportVR; } WebVR.prototype.GetData = function( id ) { return {}; } WebVR.prototype.Enable = function( id ) { } WebVR.prototype.Disable = function( id ) { } WebVR.prototype.RequestAnimationFrame = function (id) { } WebVR.prototype.IsPresenting = function (id) { return false; } WebVR.prototype.Finish = function (id) { } //============================================================================== // // piLibs 2015-2017 - http://www.iquilezles.org/www/material/piLibs/piLibs.htm // // piWebUtils // //============================================================================== function htmlEntities(str) { return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g,'''); } function piDisableTouch() {} var piGetTime = function ( timestamp ) { if (timestamp == 0) return ""; return new Date(timestamp * 1000).toISOString().substr(0, 10); } function piGetCoords( obj ) { var x = 0; var y = 0; do { x += obj.offsetLeft; y += obj.offsetTop; }while( obj = obj.offsetParent ); return { mX:x, mY:y }; } function piGetMouseCoords( ev, canvasElement ) { var pos = piGetCoords(canvasElement ); var mcx = (ev.pageX - pos.mX) * canvasElement.width / canvasElement.offsetWidth; var mcy = canvasElement.height - (ev.pageY - pos.mY) * canvasElement.height / canvasElement.offsetHeight; return { mX: mcx, mY: mcy }; } function piGetSourceElement( e ) { var ele = null; if( e.target ) ele = e.target; if( e.srcElement ) ele = e.srcElement; return ele; } function piRequestFullScreen( ele ) {} function piIsFullScreen() { return false; } function piExitFullScreen() {} function piIsMobile() { return false; } function piCreateGlContext( cv, useAlpha, useDepth, usePreserveBuffer, useSupersampling ) { var opts = { alpha: useAlpha, depth: useDepth, stencil: false, premultipliedAlpha: false, antialias: useSupersampling, preserveDrawingBuffer: usePreserveBuffer, powerPreference: "high-performance" }; // "low_power", "high_performance", "default" var gl = null; if( gl === null) gl = cv.getContext( "webgl2", opts ); if( gl === null) gl = cv.getContext( "experimental-webgl2", opts ); if( gl === null) gl = cv.getContext( "webgl", opts ); if( gl === null) gl = cv.getContext( "experimental-webgl", opts ); return gl; } function piCreateAudioContext() { return null; } function piHexColorToRGB(str) // "#ff3041" { var rgb = parseInt(str.slice(1), 16); var r = (rgb >> 16) & 255; var g = (rgb >> 8) & 255; var b = (rgb >> 0) & 255; return [r, g, b]; } function piCreateFPSCounter() { var mFrame; var mTo; var mFPS; var iReset = function( time ) { mFrame = 0; mTo = time; mFPS = 60.0; } var iCount = function( time ) { mFrame++; if( (time-mTo)>500.0 ) { mFPS = 1000.0*mFrame/(time-mTo); mFrame = 0; mTo = time; return true; } return false; } var iGetFPS = function() { return mFPS; } return { Reset : iReset, Count : iCount, GetFPS : iGetFPS }; } function piCanMediaRecorded(canvas) { return true; } function piCreateMediaRecorder(isRecordingCallback, canvas) { if (piCanMediaRecorded(canvas) == false) { return null; } var options = { audioBitsPerSecond : 0, videoBitsPerSecond : 8000000 }; if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) options.mimeType = 'video/webm;codecs=h264'; else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9' )) options.mimeType = 'video/webm;codecs=vp9'; else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8' )) options.mimeType = 'video/webm;codecs=vp8'; else options.mimeType = 'video/webm;'; var mediaRecorder = new MediaRecorder(canvas.captureStream(), options); var chunks = []; mediaRecorder.ondataavailable = function(e) { if (e.data.size > 0) { chunks.push(e.data); } }; mediaRecorder.onstart = function(){ isRecordingCallback( true ); }; mediaRecorder.onstop = function() { isRecordingCallback( false ); }; return mediaRecorder; } function piExportToEXR(width, height, numComponents, type, bytes) { var bytesPerComponent = 0; if (type=="Uint") bytesPerComponent = 4; else if (type=="Half") bytesPerComponent = 2; else if (type=="Float") bytesPerComponent = 4; var tHeader = 258 + (18 * numComponents + 1); var tTable = 8 * height; var tScanlines = height * (4 + 4 + (numComponents * bytesPerComponent * width)); var tTotal = tHeader + tTable + tScanlines; var buffer = new ArrayBuffer(tTotal); var data = new DataView(buffer); // Header { // Header : 4 bytes -> 0x76, 0x2f, 0x31, 0x01 var c = 0; data.setUint8 (c++, 0x76); data.setUint8 (c++, 0x2f); data.setUint8 (c++, 0x31); data.setUint8 (c++, 0x01); // Version : 4 bytes -> 2, 0, 0, 0 data.setUint8 (c++, 0x02); data.setUint8 (c++, 0x0); data.setUint8 (c++, 0x0); data.setUint8 (c++, 0x0); // Write channel info // Write attribute name : "channels" data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x68); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x0); // Write attribute type : "chlist" data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x68); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x00); // Write attribute size : 18 x 3 + 1 = 55 var attribSize = 18 * numComponents + 1; data.setUint8 (c++, attribSize); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); var i; for (i = 0; i < numComponents; i++) { // Attribute : "B" (42) "G" (47) "R" (52) if (i==0) data.setUint8 (c++, 0x42); else if (i==1) data.setUint8 (c++, 0x47); else if (i==2) data.setUint8 (c++, 0x52); data.setUint8 (c++, 0x00); // Value : Float (2), Half (1), Uint (0) if (type=="Uint") data.setUint8 (c++, 0x00); else if (type=="Half") data.setUint8 (c++, 0x01); else if (type=="Float") data.setUint8 (c++, 0x02); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // Plinear data.setUint8 (c++, 0x01); // Reserved data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // X sampling data.setUint8 (c++, 0x01); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // Y sampling data.setUint8 (c++, 0x01); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); } // End attribute data.setUint8 (c++, 0x00); // Write attribute name : "compression" data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x6d); data.setUint8 (c++, 0x70); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x00); // Write attribute type : "compression" data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x6d); data.setUint8 (c++, 0x70); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x00); // Write attribute size : "1" data.setUint8 (c++, 0x01); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // Write attribute value : "0" (None) data.setUint8 (c++, 0x00); // datawindow data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x57); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x77); data.setUint8 (c++, 0x00); // box2i data.setUint8 (c++, 0x62); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x78); data.setUint8 (c++, 0x32); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x00); // size 16 data.setUint8 (c++, 0x10); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value 0 0 3 2 data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint32 (c, width-1, true); c += 4; data.setUint32 (c, height-1, true); c += 4; // displayWindow data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x70); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x79); data.setUint8 (c++, 0x57); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x77); data.setUint8 (c++, 0x00); // box2i data.setUint8 (c++, 0x62); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x78); data.setUint8 (c++, 0x32); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x00); // size 16 data.setUint8 (c++, 0x10); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value 0 0 3 2 data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint32 (c, width-1, true); c += 4; data.setUint32 (c, height-1, true); c += 4; // lineOrder data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x4f); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x00); // lineOrder data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x4f); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x00); // size data.setUint8 (c++, 0x01); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value data.setUint8 (c++, 0x00); // PixelAspectRatio data.setUint8 (c++, 0x70); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x78); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x41); data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x70); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x52); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x00); // float data.setUint8 (c++, 0x66); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x00); // size 4 data.setUint8 (c++, 0x04); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value 1.0 data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x80); data.setUint8 (c++, 0x3f); // screenWindowCenter data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x57); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x77); data.setUint8 (c++, 0x43); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x00); // v2f data.setUint8 (c++, 0x76); data.setUint8 (c++, 0x32); data.setUint8 (c++, 0x66); data.setUint8 (c++, 0x00); // size 8 data.setUint8 (c++, 0x08); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value 0 0 data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // screenWindowWidth data.setUint8 (c++, 0x73); data.setUint8 (c++, 0x63); data.setUint8 (c++, 0x72); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x65); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x57); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x6e); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x77); data.setUint8 (c++, 0x57); data.setUint8 (c++, 0x69); data.setUint8 (c++, 0x64); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x68); data.setUint8 (c++, 0x00); // float data.setUint8 (c++, 0x66); data.setUint8 (c++, 0x6c); data.setUint8 (c++, 0x6f); data.setUint8 (c++, 0x61); data.setUint8 (c++, 0x74); data.setUint8 (c++, 0x00); // size data.setUint8 (c++, 0x04); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); // value data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x00); data.setUint8 (c++, 0x80); data.setUint8 (c++, 0x3f); // End of header data.setUint8 (c++, 0x00); } // Scanline table var initc = c + height * 8; for (var scanline = 0 ; scanline < height ; scanline ++) { var jump = initc + scanline * (8 + width * bytesPerComponent * numComponents); data.setUint32 (c, jump, true); c += 4; data.setUint32 (c, 0x00, true); c += 4; } // Scanlines for (var scanline = 0 ; scanline < height ; scanline ++) { // Scanline data.setUint32(c, scanline, true); c += 4; // size 24 var size = width * numComponents * bytesPerComponent; data.setUint32(c, size, true); c += 4; var numComponentsSource = 4; // number of components in the SOURCE image for (var component = 0; component < numComponents ; component ++) { for (var pixel = 0 ; pixel < width ; pixel ++) { // flip vertical, so we read OpenGL buffers without JS image flipping var v = bytes[(height-1-scanline) * width *numComponentsSource + pixel * numComponentsSource + (2-component)]; if (type=="Float") data.setFloat32(c, v, true); else if (type=="Half") data.setUint16(c, v, true); c += bytesPerComponent; } } } return new Blob([buffer], {type: 'application/octet-stream'}); } function piExportToWAV(numSamples, rate, bits, numChannels, words) { let numBytes = numSamples * numChannels * bits/8; let buffer = new ArrayBuffer(44 + numBytes); let data = new DataView(buffer); { data.setUint32( 0, 0x46464952, true ); // RIFF data.setUint32( 4, numBytes + 36, true); { data.setUint32( 8, 0x45564157, true ); // WAV_WAVE data.setUint32( 12, 0x20746D66, true ); // WAV_FMT { data.setUint32( 16, 16, true); data.setUint16( 20, 1, true ); // WAV_FORMAT_PCM data.setUint16( 22, numChannels, true); data.setUint32( 24, rate, true); data.setUint32( 28, rate*numChannels*bits / 8, true); data.setUint16( 32, numChannels*bits / 8, true); data.setUint16( 34, bits, true); } data.setUint32( 36, 0x61746164, true); // WAV_DATA { data.setUint32( 40, numBytes, true); let numWords = numSamples * numChannels; for(let i=0; i