diff options
author | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
---|---|---|
committer | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
commit | c6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch) | |
tree | 1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/utils/asymptote/webgl | |
parent | 07ee7222e389b0777456b427a55c22d0e6ffd267 (diff) |
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/webgl')
-rw-r--r-- | Build/source/utils/asymptote/webgl/fragment.glsl | 95 | ||||
-rw-r--r-- | Build/source/utils/asymptote/webgl/gl.js | 3135 | ||||
-rw-r--r-- | Build/source/utils/asymptote/webgl/license | 18 | ||||
-rw-r--r-- | Build/source/utils/asymptote/webgl/vertex.glsl | 80 |
4 files changed, 0 insertions, 3328 deletions
diff --git a/Build/source/utils/asymptote/webgl/fragment.glsl b/Build/source/utils/asymptote/webgl/fragment.glsl deleted file mode 100644 index de9ab75dac5..00000000000 --- a/Build/source/utils/asymptote/webgl/fragment.glsl +++ /dev/null @@ -1,95 +0,0 @@ -#ifdef NORMAL -#ifndef ORTHOGRAPHIC -varying vec3 ViewPosition; -#endif -varying vec3 Normal; -varying vec4 diffuse; -varying vec3 specular; -varying float roughness,metallic,fresnel0; - -float Roughness2; -vec3 normal; - -struct Light { - vec3 direction; - vec3 color; -}; - -uniform Light Lights[Nlights]; - -float NDF_TRG(vec3 h) -{ - float ndoth=max(dot(normal,h),0.0); - float alpha2=Roughness2*Roughness2; - float denom=ndoth*ndoth*(alpha2-1.0)+1.0; - return denom != 0.0 ? alpha2/(denom*denom) : 0.0; -} - -float GGX_Geom(vec3 v) -{ - float ndotv=max(dot(v,normal),0.0); - float ap=1.0+Roughness2; - float k=0.125*ap*ap; - return ndotv/((ndotv*(1.0-k))+k); -} - -float Geom(vec3 v, vec3 l) -{ - return GGX_Geom(v)*GGX_Geom(l); -} - -float Fresnel(vec3 h, vec3 v, float fresnel0) -{ - float a=1.0-max(dot(h,v),0.0); - float b=a*a; - return fresnel0+(1.0-fresnel0)*b*b*a; -} - -// physical based shading using UE4 model. -vec3 BRDF(vec3 viewDirection, vec3 lightDirection) -{ - vec3 lambertian=diffuse.rgb; - vec3 h=normalize(lightDirection+viewDirection); - - float omegain=max(dot(viewDirection,normal),0.0); - float omegali=max(dot(lightDirection,normal),0.0); - - float D=NDF_TRG(h); - float G=Geom(viewDirection,lightDirection); - float F=Fresnel(h,viewDirection,fresnel0); - - float denom=4.0*omegain*omegali; - float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0; - - vec3 dielectric=mix(lambertian,rawReflectance*specular,F); - vec3 metal=rawReflectance*diffuse.rgb; - - return mix(dielectric,metal,metallic); -} -#endif -varying vec4 emissive; - -void main(void) -{ -#if defined(NORMAL) && nlights > 0 - normal=normalize(Normal); - normal=gl_FrontFacing ? normal : -normal; -#ifdef ORTHOGRAPHIC - vec3 viewDir=vec3(0.0,0.0,1.0); -#else - vec3 viewDir=-normalize(ViewPosition); -#endif - Roughness2=roughness*roughness; - vec3 color=emissive.rgb; - for(int i=0; i < nlights; ++i) { - Light Li=Lights[i]; - vec3 L=Li.direction; - float cosTheta=max(dot(normal,L),0.0); - vec3 radiance=cosTheta*Li.color; - color += BRDF(viewDir,L)*radiance; - } - gl_FragColor=vec4(color,diffuse.a); -#else - gl_FragColor=emissive; -#endif -} diff --git a/Build/source/utils/asymptote/webgl/gl.js b/Build/source/utils/asymptote/webgl/gl.js deleted file mode 100644 index f05312dec54..00000000000 --- a/Build/source/utils/asymptote/webgl/gl.js +++ /dev/null @@ -1,3135 +0,0 @@ -let P=[]; // Array of Bezier patches, triangles, curves, and pixels -let Materials=[]; // Array of materials -let Lights=[]; // Array of lights -let Centers=[]; // Array of billboard centers -let Background=[1,1,1,1]; // Background color - -let canvasWidth,canvasHeight; -let canvasWidth0,canvasHeight0; // Initial values - -let absolute=false; - -let b,B; // Scene min,max bounding box corners (3-tuples) -let angle; // Field of view angle -let Zoom0; // Initial zoom -let zoom0; // Adjusted initial zoom -let viewportmargin; // Margin around viewport (2-tuple) -let viewportshift=[0,0]; // Viewport shift (for perspective projection) - -let zoomFactor; -let zoomPinchFactor; -let zoomPinchCap; -let zoomStep; - -let shiftHoldDistance; -let shiftWaitTime; -let vibrateTime; - -let embedded; // Is image embedded within another window? - -let canvas; // Rendering canvas -let gl; // WebGL rendering context -let alpha; // Is background opaque? - -let offscreen; // Offscreen rendering canvas for embedded images -let context; // 2D context for copying embedded offscreen images - -let nlights=0; // Number of lights compiled in shader -let Nmaterials=2; // Maximum number of materials compiled in shader - -let materials=[]; // Subset of Materials passed as uniforms -let maxMaterials; // Limit on number of materials allowed in shader - -let halfCanvasWidth,halfCanvasHeight; - -let pixel=0.75; // Adaptive rendering constant. -let zoomRemeshFactor=1.5; // Zoom factor before remeshing -let FillFactor=0.1; -let Zoom; - -let maxViewportWidth; -let maxViewportHeight; - -const windowTrim=10; - -let lastZoom; -let H; // maximum camera view half-height - -let third=1/3; - -let rotMat=mat4.create(); -let projMat=mat4.create(); // projection matrix -let viewMat=mat4.create(); // view matrix - -let projViewMat=mat4.create(); // projection view matrix -let normMat=mat3.create(); -let viewMat3=mat3.create(); // 3x3 view matrix -let cjMatInv=mat4.create(); -let T=mat4.create(); // Temporary matrix - -let zmin,zmax; -let center={x:0,y:0,z:0}; -let size2; -let ArcballFactor; -let shift={ - x:0,y:0 -}; - -let viewParam = { - xmin:0,xmax:0, - ymin:0,ymax:0, - zmin:0,zmax:0 -}; - -let remesh=true; -let wireframe=0; -let mouseDownOrTouchActive=false; -let lastMouseX=null; -let lastMouseY=null; -let touchID=null; - -// Indexed triangles: -let Positions=[]; -let Normals=[]; -let Colors=[]; -let Indices=[]; - -class Material { - constructor(diffuse,emissive,specular,shininess,metallic,fresnel0) { - this.diffuse=diffuse; - this.emissive=emissive; - this.specular=specular; - this.shininess=shininess; - this.metallic=metallic; - this.fresnel0=fresnel0; - } - - setUniform(program,index) { - let getLoc= - param => gl.getUniformLocation(program,"Materials["+index+"]."+param); - - gl.uniform4fv(getLoc("diffuse"),new Float32Array(this.diffuse)); - gl.uniform4fv(getLoc("emissive"),new Float32Array(this.emissive)); - gl.uniform4fv(getLoc("specular"),new Float32Array(this.specular)); - - gl.uniform4f(getLoc("parameters"),this.shininess,this.metallic, - this.fresnel0,0); - } -} - -let enumPointLight=1; -let enumDirectionalLight=2; - -class Light { - constructor(direction,color) { - this.direction=direction; - this.color=color; - } - - setUniform(program,index) { - let getLoc= - param => gl.getUniformLocation(program,"Lights["+index+"]."+param); - - gl.uniform3fv(getLoc("direction"),new Float32Array(this.direction)); - gl.uniform3fv(getLoc("color"),new Float32Array(this.color)); - } -} - -function initShaders() -{ - let maxUniforms=gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS); - maxMaterials=Math.floor((maxUniforms-14)/4); - Nmaterials=Math.min(Math.max(Nmaterials,Materials.length),maxMaterials); - - pixelShader=initShader(["WIDTH"]); - materialShader=initShader(["NORMAL"]); - colorShader=initShader(["NORMAL","COLOR"]); - transparentShader=initShader(["NORMAL","COLOR","TRANSPARENT"]); -} - -function deleteShaders() -{ - gl.deleteProgram(transparentShader); - gl.deleteProgram(colorShader); - gl.deleteProgram(materialShader); - gl.deleteProgram(pixelShader); -} - -function noGL() { - if (!gl) - alert("Could not initialize WebGL"); -} - -function saveAttributes() -{ - let a=window.top.document.asygl[alpha]; - - a.gl=gl; - a.nlights=Lights.length; - a.Nmaterials=Nmaterials; - a.maxMaterials=maxMaterials; - - a.pixelShader=pixelShader; - a.materialShader=materialShader; - a.colorShader=colorShader; - a.transparentShader=transparentShader; -} - -function restoreAttributes() -{ - let a=window.top.document.asygl[alpha]; - - gl=a.gl; - nlights=a.nlights; - Nmaterials=a.Nmaterials; - maxMaterials=a.maxMaterials; - - pixelShader=a.pixelShader; - materialShader=a.materialShader; - colorShader=a.colorShader; - transparentShader=a.transparentShader; -} - -let indexExt; - -function initGL() -{ - alpha=Background[3] < 1; - - if(embedded) { - let p=window.top.document; - - if(p.asygl == null) - p.asygl=Array(2); - - context=canvas.getContext("2d"); - offscreen=p.offscreen; - if(!offscreen) { - offscreen=p.createElement("canvas"); - p.offscreen=offscreen; - } - - if(!p.asygl[alpha] || !p.asygl[alpha].gl) { - gl=offscreen.getContext("webgl",{alpha:alpha}); - if(!gl) noGL(); - initShaders(); - p.asygl[alpha]={}; - saveAttributes(); - } else { - restoreAttributes(); - if((Lights.length != nlights) || - Math.min(Materials.length,maxMaterials) > Nmaterials) { - initShaders(); - saveAttributes(); - } - } - } else { - gl=canvas.getContext("webgl",{alpha:alpha}); - if(!gl) noGL(); - initShaders(); - } - - indexExt=gl.getExtension("OES_element_index_uint"); - - TRIANGLES=gl.TRIANGLES; - material0Data=new vertexBuffer(gl.POINTS); - material1Data=new vertexBuffer(gl.LINES); - materialData=new vertexBuffer(); - colorData=new vertexBuffer(); - transparentData=new vertexBuffer(); - triangleData=new vertexBuffer(); -} - -function getShader(gl,shaderScript,type,options=[]) -{ - let str=`#version 100 -#ifdef GL_FRAGMENT_PRECISION_HIGH - precision highp float; -#else - precision mediump float; -#endif - #define nlights ${wireframe == 0 ? Lights.length : 0}\n - const int Nlights=${Math.max(Lights.length,1)};\n - #define Nmaterials ${Nmaterials}\n`; - - if(orthographic) - str += `#define ORTHOGRAPHIC\n`; - - options.forEach(s => str += `#define `+s+`\n`); - - let shader=gl.createShader(type); - gl.shaderSource(shader,str+shaderScript); - gl.compileShader(shader); - if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)) { - alert(gl.getShaderInfoLog(shader)); - return null; - } - return shader; -} - -function registerBuffer(buffervector,bufferIndex,copy,type=gl.ARRAY_BUFFER) -{ - if(buffervector.length > 0) { - if(bufferIndex == 0) { - bufferIndex=gl.createBuffer(); - copy=true; - } - gl.bindBuffer(type,bufferIndex); - if(copy) - gl.bufferData(type,buffervector,gl.STATIC_DRAW); - } - return bufferIndex; -} - -function drawBuffer(data,shader,indices=data.indices) -{ - if(data.indices.length == 0) return; - - let normal=shader != pixelShader; - - setUniforms(data,shader); - - let copy=remesh || data.partial || !data.rendered; - data.verticesBuffer=registerBuffer(new Float32Array(data.vertices), - data.verticesBuffer,copy); - gl.vertexAttribPointer(positionAttribute,3,gl.FLOAT,false, - normal ? 24 : 16,0); - if(normal && Lights.length > 0) - gl.vertexAttribPointer(normalAttribute,3,gl.FLOAT,false,24,12); - else if(pixel) - gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,false,16,12); - - data.materialsBuffer=registerBuffer(new Int16Array(data.materialIndices), - data.materialsBuffer,copy); - gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,false,2,0); - - - if(shader == colorShader || shader == transparentShader) { - data.colorsBuffer=registerBuffer(new Uint8Array(data.colors), - data.colorsBuffer,copy); - gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,true,0,0); - } - - data.indicesBuffer=registerBuffer(indexExt ? new Uint32Array(indices) : - new Uint16Array(indices), - data.indicesBuffer,copy, - gl.ELEMENT_ARRAY_BUFFER); - data.rendered=true; - - gl.drawElements(normal ? (wireframe ? gl.LINES : data.type) : gl.POINTS, - indices.length, - indexExt ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT,0); -} - -let TRIANGLES; - -class vertexBuffer { - constructor(type) { - this.type=type ? type : TRIANGLES; - - this.verticesBuffer=0; - this.materialsBuffer=0; - this.colorsBuffer=0; - this.indicesBuffer=0; - - this.rendered=false; // Are all patches in this buffer fully rendered? - this.partial=false; // Does buffer contain incomplete data? - - this.clear(); - } - - clear() { - this.vertices=[]; - this.materialIndices=[]; - this.colors=[]; - this.indices=[]; - this.nvertices=0; - this.materials=[]; - this.materialTable=[]; - } - - // material vertex - vertex(v,n) { - this.vertices.push(v[0]); - this.vertices.push(v[1]); - this.vertices.push(v[2]); - this.vertices.push(n[0]); - this.vertices.push(n[1]); - this.vertices.push(n[2]); - this.materialIndices.push(materialIndex); - return this.nvertices++; - } - - // colored vertex - Vertex(v,n,c=[0,0,0,0]) { - this.vertices.push(v[0]); - this.vertices.push(v[1]); - this.vertices.push(v[2]); - this.vertices.push(n[0]); - this.vertices.push(n[1]); - this.vertices.push(n[2]); - this.materialIndices.push(materialIndex); - this.colors.push(c[0]); - this.colors.push(c[1]); - this.colors.push(c[2]); - this.colors.push(c[3]); - return this.nvertices++; - } - - // material vertex with width and without normal - vertex0(v,width) { - this.vertices.push(v[0]); - this.vertices.push(v[1]); - this.vertices.push(v[2]); - this.vertices.push(width); - this.materialIndices.push(materialIndex); - return this.nvertices++; - } - - // indexed colored vertex - iVertex(i,v,n,c=[0,0,0,0]) { - let i6=6*i; - this.vertices[i6]=v[0]; - this.vertices[i6+1]=v[1]; - this.vertices[i6+2]=v[2]; - this.vertices[i6+3]=n[0]; - this.vertices[i6+4]=n[1]; - this.vertices[i6+5]=n[2]; - this.materialIndices[i]=materialIndex; - let i4=4*i; - this.colors[i4]=c[0]; - this.colors[i4+1]=c[1]; - this.colors[i4+2]=c[2]; - this.colors[i4+3]=c[3]; - this.indices.push(i); - } - - append(data) { - append(this.vertices,data.vertices); - append(this.materialIndices,data.materialIndices); - append(this.colors,data.colors); - appendOffset(this.indices,data.indices,this.nvertices); - this.nvertices += data.nvertices; - } -} - -let material0Data; // pixels -let material1Data; // material Bezier curves -let materialData; // material Bezier patches & triangles -let colorData; // colored Bezier patches & triangles -let transparentData; // transparent patches & triangles -let triangleData; // opaque indexed triangles - -let materialIndex; - -// efficiently append array b onto array a -function append(a,b) -{ - let n=a.length; - let m=b.length; - a.length += m; - for(let i=0; i < m; ++i) - a[n+i]=b[i]; -} - -// efficiently append array b onto array a with offset -function appendOffset(a,b,o) -{ - let n=a.length; - let m=b.length; - a.length += b.length; - for(let i=0; i < m; ++i) - a[n+i]=b[i]+o; -} - -class Geometry { - constructor() { - this.data=new vertexBuffer(); - this.Onscreen=false; - this.m=[]; - } - - // Is 2D bounding box formed by projecting 3d points in vector v offscreen? - offscreen(v) { - let m=projViewMat; - let v0=v[0]; - let x=v0[0], y=v0[1], z=v0[2]; - let f=1/(m[3]*x+m[7]*y+m[11]*z+m[15]); - this.x=this.X=(m[0]*x+m[4]*y+m[8]*z+m[12])*f; - this.y=this.Y=(m[1]*x+m[5]*y+m[9]*z+m[13])*f; - for(let i=1, n=v.length; i < n; ++i) { - let vi=v[i]; - let x=vi[0], y=vi[1], z=vi[2]; - let f=1/(m[3]*x+m[7]*y+m[11]*z+m[15]); - let X=(m[0]*x+m[4]*y+m[8]*z+m[12])*f; - let Y=(m[1]*x+m[5]*y+m[9]*z+m[13])*f; - if(X < this.x) this.x=X; - else if(X > this.X) this.X=X; - if(Y < this.y) this.y=Y; - else if(Y > this.Y) this.Y=Y; - } - let eps=1e-2; - let min=-1-eps; - let max=1+eps; - if(this.X < min || this.x > max || this.Y < min || this.y > max) { - this.Onscreen=false; - return true; - } - return false; - } - - T(v) { - let c0=this.c[0]; - let c1=this.c[1]; - let c2=this.c[2]; - let x=v[0]-c0; - let y=v[1]-c1; - let z=v[2]-c2; - return [x*normMat[0]+y*normMat[3]+z*normMat[6]+c0, - x*normMat[1]+y*normMat[4]+z*normMat[7]+c1, - x*normMat[2]+y*normMat[5]+z*normMat[8]+c2]; - } - - Tcorners(m,M) { - return [this.T(m),this.T([m[0],m[1],M[2]]),this.T([m[0],M[1],m[2]]), - this.T([m[0],M[1],M[2]]),this.T([M[0],m[1],m[2]]), - this.T([M[0],m[1],M[2]]),this.T([M[0],M[1],m[2]]),this.T(M)]; - } - - setMaterial(data,draw) { - if(data.materialTable[this.MaterialIndex] == null) { - if(data.materials.length >= Nmaterials) { - data.partial=true; - draw(); - } - data.materialTable[this.MaterialIndex]=data.materials.length; - data.materials.push(Materials[this.MaterialIndex]); - } - materialIndex=data.materialTable[this.MaterialIndex]; - } - - render() { - this.setMaterialIndex(); - - // First check if re-rendering is required - let v; - if(this.CenterIndex == 0) - v=corners(this.Min,this.Max); - else { - this.c=Centers[this.CenterIndex-1]; - v=this.Tcorners(this.Min,this.Max); - } - - if(this.offscreen(v)) { // Fully offscreen - this.data.clear(); - this.notRendered(); - return; - } - - let p=this.controlpoints; - let P; - - if(this.CenterIndex == 0) { - if(!remesh && this.Onscreen) { // Fully onscreen; no need to re-render - this.append(); - return; - } - P=p; - } else { // Transform billboard labels - let n=p.length; - P=Array(n); - for(let i=0; i < n; ++i) - P[i]=this.T(p[i]); - } - - let s=orthographic ? 1 : this.Min[2]/B[2]; - let res=pixel*Math.hypot(s*(viewParam.xmax-viewParam.xmin), - s*(viewParam.ymax-viewParam.ymin))/size2; - this.res2=res*res; - this.Epsilon=FillFactor*res; - - this.data.clear(); - this.notRendered(); - this.Onscreen=true; - this.process(P); - } -} - -class BezierPatch extends Geometry { - /** - * Constructor for Bezier Patch - * @param {*} controlpoints array of 16 control points - * @param {*} CenterIndex center index of billboard labels (or 0) - * @param {*} MaterialIndex material index (>= 0) - * @param {*} Min bounding box corner - * @param {*} Max bounding box corner - * @param {*} colors array of 4 RGBA color arrays - */ - constructor(controlpoints,CenterIndex,MaterialIndex,Min,Max,color) { - super(); - this.controlpoints=controlpoints; - this.Min=Min; - this.Max=Max; - this.color=color; - this.CenterIndex=CenterIndex; - let n=controlpoints.length; - if(color) { - let sum=color[0][3]+color[1][3]+color[2][3]; - this.transparent=(n == 16 || n == 4) ? - sum+color[3][3] < 1020 : sum < 765; - } else - this.transparent=Materials[MaterialIndex].diffuse[3] < 1; - this.MaterialIndex=MaterialIndex; - - this.vertex=this.transparent ? this.data.Vertex.bind(this.data) : - this.data.vertex.bind(this.data); - this.L2norm(this.controlpoints); - } - - setMaterialIndex() { - if(this.transparent) - this.setMaterial(transparentData,drawTransparent); - else { - if(this.color) - this.setMaterial(colorData,drawColor); - else - this.setMaterial(materialData,drawMaterial); - } - } - -// Render a Bezier patch via subdivision. - L2norm(p) { - let p0=p[0]; - this.epsilon=0; - let n=p.length; - for(let i=1; i < n; ++i) - this.epsilon=Math.max(this.epsilon, - abs2([p[i][0]-p0[0],p[i][1]-p0[1],p[i][2]-p0[2]])); - this.epsilon *= Number.EPSILON - } - - processTriangle(p) { - let p0=p[0]; - let p1=p[1]; - let p2=p[2]; - let n=unit(cross([p1[0]-p0[0],p1[1]-p0[1],p1[2]-p0[2]], - [p2[0]-p0[0],p2[1]-p0[1],p2[2]-p0[2]])); - if(!this.offscreen([p0,p1,p2])) { - let i0,i1,i2; - if(this.color) { - i0=this.data.Vertex(p0,n,this.color[0]); - i1=this.data.Vertex(p1,n,this.color[1]); - i2=this.data.Vertex(p2,n,this.color[2]); - } else { - i0=this.vertex(p0,n); - i1=this.vertex(p1,n); - i2=this.vertex(p2,n); - } - - if(wireframe == 0) { - this.data.indices.push(i0); - this.data.indices.push(i1); - this.data.indices.push(i2); - } else { - this.data.indices.push(i0); - this.data.indices.push(i1); - this.data.indices.push(i1); - this.data.indices.push(i2); - this.data.indices.push(i2); - this.data.indices.push(i0); - } - - this.append(); - } - } - - processQuad(p) { - let p0=p[0]; - let p1=p[1]; - let p2=p[2]; - let p3=p[3]; - let n1=cross([p1[0]-p0[0],p1[1]-p0[1],p1[2]-p0[2]], - [p2[0]-p1[0],p2[1]-p1[1],p2[2]-p1[2]]); - let n2=cross([p2[0]-p3[0],p2[1]-p3[1],p2[2]-p3[2]], - [p3[0]-p0[0],p3[1]-p0[1],p3[2]-p0[2]]); - let n=unit([n1[0]+n2[0],n1[1]+n2[1],n1[2]+n2[2]]); - if(!this.offscreen([p0,p1,p2,p3])) { - let i0,i1,i2,i3; - if(this.color) { - i0=this.data.Vertex(p0,n,this.color[0]); - i1=this.data.Vertex(p1,n,this.color[1]); - i2=this.data.Vertex(p2,n,this.color[2]); - i3=this.data.Vertex(p3,n,this.color[3]); - } else { - i0=this.vertex(p0,n); - i1=this.vertex(p1,n); - i2=this.vertex(p2,n); - i3=this.vertex(p3,n); - } - - if(wireframe == 0) { - this.data.indices.push(i0); - this.data.indices.push(i1); - this.data.indices.push(i2); - - this.data.indices.push(i0); - this.data.indices.push(i2); - this.data.indices.push(i3); - } else { - this.data.indices.push(i0); - this.data.indices.push(i1); - this.data.indices.push(i1); - this.data.indices.push(i2); - this.data.indices.push(i2); - this.data.indices.push(i3); - this.data.indices.push(i3); - this.data.indices.push(i0); - } - - this.append(); - } - } - - curve(p,a,b,c,d) { - new BezierCurve([p[a],p[b],p[c],p[d]],0,materialIndex, - this.Min,this.Max).render(); - } - - process(p) { - if(this.transparent && wireframe != 1) - // Override materialIndex to encode color vs material - materialIndex=this.color ? -1-materialIndex : 1+materialIndex; - - if(p.length == 10) return this.process3(p); - if(p.length == 3) return this.processTriangle(p); - if(p.length == 4) return this.processQuad(p); - - if(wireframe == 1) { - this.curve(p,0,4,8,12); - this.curve(p,12,13,14,15); - this.curve(p,15,11,7,3); - this.curve(p,3,2,1,0); - return; - } - - let p0=p[0]; - let p3=p[3]; - let p12=p[12]; - let p15=p[15]; - - let n0=this.normal(p3,p[2],p[1],p0,p[4],p[8],p12); - if(abs2(n0) < this.epsilon) { - n0=this.normal(p3,p[2],p[1],p0,p[13],p[14],p15); - if(abs2(n0) < this.epsilon) - n0=this.normal(p15,p[11],p[7],p3,p[4],p[8],p12); - } - - let n1=this.normal(p0,p[4],p[8],p12,p[13],p[14],p15); - if(abs2(n1) < this.epsilon) { - n1=this.normal(p0,p[4],p[8],p12,p[11],p[7],p3); - if(abs2(n1) < this.epsilon) - n1=this.normal(p3,p[2],p[1],p0,p[13],p[14],p15); - } - - let n2=this.normal(p12,p[13],p[14],p15,p[11],p[7],p3); - if(abs2(n2) < this.epsilon) { - n2=this.normal(p12,p[13],p[14],p15,p[2],p[1],p0); - if(abs2(n2) < this.epsilon) - n2=this.normal(p0,p[4],p[8],p12,p[11],p[7],p3); - } - - let n3=this.normal(p15,p[11],p[7],p3,p[2],p[1],p0); - if(abs2(n3) < this.epsilon) { - n3=this.normal(p15,p[11],p[7],p3,p[4],p[8],p12); - if(abs2(n3) < this.epsilon) - n3=this.normal(p12,p[13],p[14],p15,p[2],p[1],p0); - } - - if(this.color) { - let c0=this.color[0]; - let c1=this.color[1]; - let c2=this.color[2]; - let c3=this.color[3]; - - let i0=this.data.Vertex(p0,n0,c0); - let i1=this.data.Vertex(p12,n1,c1); - let i2=this.data.Vertex(p15,n2,c2); - let i3=this.data.Vertex(p3,n3,c3); - - this.Render(p,i0,i1,i2,i3,p0,p12,p15,p3,false,false,false,false, - c0,c1,c2,c3); - } else { - let i0=this.vertex(p0,n0); - let i1=this.vertex(p12,n1); - let i2=this.vertex(p15,n2); - let i3=this.vertex(p3,n3); - - this.Render(p,i0,i1,i2,i3,p0,p12,p15,p3,false,false,false,false); - } - if(this.data.indices.length > 0) this.append(); - } - - append() { - if(this.transparent) - transparentData.append(this.data); - else if(this.color) - colorData.append(this.data); - else - materialData.append(this.data); - } - - notRendered() { - if(this.transparent) - transparentData.rendered=false; - else if(this.color) - colorData.rendered=false; - else - materialData.rendered=false; - } - - Render(p,I0,I1,I2,I3,P0,P1,P2,P3,flat0,flat1,flat2,flat3,C0,C1,C2,C3) { - let d=this.Distance(p); - if(d[0] < this.res2 && d[1] < this.res2) { // Bezier patch is flat - if(!this.offscreen([P0,P1,P2])) { - if(wireframe == 0) { - this.data.indices.push(I0); - this.data.indices.push(I1); - this.data.indices.push(I2); - } else { - this.data.indices.push(I0); - this.data.indices.push(I1); - this.data.indices.push(I1); - this.data.indices.push(I2); - } - } - if(!this.offscreen([P0,P2,P3])) { - if(wireframe == 0) { - this.data.indices.push(I0); - this.data.indices.push(I2); - this.data.indices.push(I3); - } else { - this.data.indices.push(I2); - this.data.indices.push(I3); - this.data.indices.push(I3); - this.data.indices.push(I0); - } - } - } else { - // Approximate bounds by bounding box of control polyhedron. - if(this.offscreen(p)) return; - - /* Control points are indexed as follows: - - Coordinate - +----- - Index - - 03 13 23 33 - +-----+-----+-----+ - |3 |7 |11 |15 - | | | | - |02 |12 |22 |32 - +-----+-----+-----+ - |2 |6 |10 |14 - | | | | - |01 |11 |21 |31 - +-----+-----+-----+ - |1 |5 |9 |13 - | | | | - |00 |10 |20 |30 - +-----+-----+-----+ - 0 4 8 12 - - */ - - let p0=p[0]; - let p3=p[3]; - let p12=p[12]; - let p15=p[15]; - - if(d[0] < this.res2) { // flat in horizontal direction; split vertically - /* - P refers to a corner - m refers to a midpoint - s refers to a subpatch - - +--------+--------+ - |P3 P2| - | | - | s1 | - | | - | | - m1 +-----------------+ m0 - | | - | | - | s0 | - | | - |P0 P1| - +-----------------+ - - */ - - let c0=new Split3(p0,p[1],p[2],p3); - let c1=new Split3(p[4],p[5],p[6],p[7]); - let c2=new Split3(p[8],p[9],p[10],p[11]); - let c3=new Split3(p12,p[13],p[14],p15); - - let s0=[p0 ,c0.m0,c0.m3,c0.m5, - p[4],c1.m0,c1.m3,c1.m5, - p[8],c2.m0,c2.m3,c2.m5, - p12 ,c3.m0,c3.m3,c3.m5]; - - let s1=[c0.m5,c0.m4,c0.m2,p3, - c1.m5,c1.m4,c1.m2,p[7], - c2.m5,c2.m4,c2.m2,p[11], - c3.m5,c3.m4,c3.m2,p15]; - - let n0=this.normal(s0[12],s0[13],s0[14],s0[15],s0[11],s0[7],s0[3]); - if(abs2(n0) <= this.epsilon) { - n0=this.normal(s0[12],s0[13],s0[14],s0[15],s0[2],s0[1],s0[0]); - if(abs2(n0) <= this.epsilon) - n0=this.normal(s0[0],s0[4],s0[8],s0[12],s0[11],s0[7],s0[3]); - } - - let n1=this.normal(s1[3],s1[2],s1[1],s1[0],s1[4],s1[8],s1[12]); - if(abs2(n1) <= this.epsilon) { - n1=this.normal(s1[3],s1[2],s1[1],s1[0],s1[13],s1[14],s1[15]); - if(abs2(n1) <= this.epsilon) - n1=this.normal(s1[15],s1[11],s1[7],s1[3],s1[4],s1[8],s1[12]); - } - - let e=this.Epsilon; - - // A kludge to remove subdivision cracks, only applied the first time - // an edge is found to be flat before the rest of the subpatch is. - - let m0=[0.5*(P1[0]+P2[0]), - 0.5*(P1[1]+P2[1]), - 0.5*(P1[2]+P2[2])]; - if(!flat1) { - if((flat1=Straightness(p12,p[13],p[14],p15) < this.res2)) { - let r=unit(this.differential(s1[12],s1[8],s1[4],s1[0])); - m0=[m0[0]-e*r[0],m0[1]-e*r[1],m0[2]-e*r[2]]; - } - else m0=s0[15]; - } - - let m1=[0.5*(P3[0]+P0[0]), - 0.5*(P3[1]+P0[1]), - 0.5*(P3[2]+P0[2])]; - if(!flat3) { - if((flat3=Straightness(p0,p[1],p[2],p3) < this.res2)) { - let r=unit(this.differential(s0[3],s0[7],s0[11],s0[15])); - m1=[m1[0]-e*r[0],m1[1]-e*r[1],m1[2]-e*r[2]]; - } - else m1=s1[0]; - } - - if(C0) { - let c0=Array(4); - let c1=Array(4); - for(let i=0; i < 4; ++i) { - c0[i]=0.5*(C1[i]+C2[i]); - c1[i]=0.5*(C3[i]+C0[i]); - } - - let i0=this.data.Vertex(m0,n0,c0); - let i1=this.data.Vertex(m1,n1,c1); - - this.Render(s0,I0,I1,i0,i1,P0,P1,m0,m1,flat0,flat1,false,flat3, - C0,C1,c0,c1); - this.Render(s1,i1,i0,I2,I3,m1,m0,P2,P3,false,flat1,flat2,flat3, - c1,c0,C2,C3); - } else { - let i0=this.vertex(m0,n0); - let i1=this.vertex(m1,n1); - - this.Render(s0,I0,I1,i0,i1,P0,P1,m0,m1,flat0,flat1,false,flat3); - this.Render(s1,i1,i0,I2,I3,m1,m0,P2,P3,false,flat1,flat2,flat3); - } - return; - } - - if(d[1] < this.res2) { // flat in vertical direction; split horizontally - /* - P refers to a corner - m refers to a midpoint - s refers to a subpatch - - m1 - +--------+--------+ - |P3 | P2| - | | | - | | | - | | | - | | | - | s0 | s1 | - | | | - | | | - | | | - | | | - |P0 | P1| - +--------+--------+ - m0 - - */ - - let c0=new Split3(p0,p[4],p[8],p12); - let c1=new Split3(p[1],p[5],p[9],p[13]); - let c2=new Split3(p[2],p[6],p[10],p[14]); - let c3=new Split3(p3,p[7],p[11],p15); - - let s0=[p0,p[1],p[2],p3, - c0.m0,c1.m0,c2.m0,c3.m0, - c0.m3,c1.m3,c2.m3,c3.m3, - c0.m5,c1.m5,c2.m5,c3.m5]; - - let s1=[c0.m5,c1.m5,c2.m5,c3.m5, - c0.m4,c1.m4,c2.m4,c3.m4, - c0.m2,c1.m2,c2.m2,c3.m2, - p12,p[13],p[14],p15]; - - let n0=this.normal(s0[0],s0[4],s0[8],s0[12],s0[13],s0[14],s0[15]); - if(abs2(n0) <= this.epsilon) { - n0=this.normal(s0[0],s0[4],s0[8],s0[12],s0[11],s0[7],s0[3]); - if(abs2(n0) <= this.epsilon) - n0=this.normal(s0[3],s0[2],s0[1],s0[0],s0[13],s0[14],s0[15]); - } - - let n1=this.normal(s1[15],s1[11],s1[7],s1[3],s1[2],s1[1],s1[0]); - if(abs2(n1) <= this.epsilon) { - n1=this.normal(s1[15],s1[11],s1[7],s1[3],s1[4],s1[8],s1[12]); - if(abs2(n1) <= this.epsilon) - n1=this.normal(s1[12],s1[13],s1[14],s1[15],s1[2],s1[1],s1[0]); - } - - let e=this.Epsilon; - - // A kludge to remove subdivision cracks, only applied the first time - // an edge is found to be flat before the rest of the subpatch is. - - let m0=[0.5*(P0[0]+P1[0]), - 0.5*(P0[1]+P1[1]), - 0.5*(P0[2]+P1[2])]; - if(!flat0) { - if((flat0=Straightness(p0,p[4],p[8],p12) < this.res2)) { - let r=unit(this.differential(s1[0],s1[1],s1[2],s1[3])); - m0=[m0[0]-e*r[0],m0[1]-e*r[1],m0[2]-e*r[2]]; - } - else m0=s0[12]; - } - - let m1=[0.5*(P2[0]+P3[0]), - 0.5*(P2[1]+P3[1]), - 0.5*(P2[2]+P3[2])]; - if(!flat2) { - if((flat2=Straightness(p15,p[11],p[7],p3) < this.res2)) { - let r=unit(this.differential(s0[15],s0[14],s0[13],s0[12])); - m1=[m1[0]-e*r[0],m1[1]-e*r[1],m1[2]-e*r[2]]; - } - else m1=s1[3]; - } - - if(C0) { - let c0=Array(4); - let c1=Array(4); - for(let i=0; i < 4; ++i) { - c0[i]=0.5*(C0[i]+C1[i]); - c1[i]=0.5*(C2[i]+C3[i]); - } - - let i0=this.data.Vertex(m0,n0,c0); - let i1=this.data.Vertex(m1,n1,c1); - - this.Render(s0,I0,i0,i1,I3,P0,m0,m1,P3,flat0,false,flat2,flat3, - C0,c0,c1,C3); - this.Render(s1,i0,I1,I2,i1,m0,P1,P2,m1,flat0,flat1,flat2,false, - c0,C1,C2,c1); - } else { - let i0=this.vertex(m0,n0); - let i1=this.vertex(m1,n1); - - this.Render(s0,I0,i0,i1,I3,P0,m0,m1,P3,flat0,false,flat2,flat3); - this.Render(s1,i0,I1,I2,i1,m0,P1,P2,m1,flat0,flat1,flat2,false); - } - return; - } - - /* - Horizontal and vertical subdivision: - P refers to a corner - m refers to a midpoint - s refers to a subpatch - - m2 - +--------+--------+ - |P3 | P2| - | | | - | s3 | s2 | - | | | - | | m4 | - m3 +--------+--------+ m1 - | | | - | | | - | s0 | s1 | - | | | - |P0 | P1| - +--------+--------+ - m0 - */ - - // Subdivide patch: - - let c0=new Split3(p0,p[1],p[2],p3); - let c1=new Split3(p[4],p[5],p[6],p[7]); - let c2=new Split3(p[8],p[9],p[10],p[11]); - let c3=new Split3(p12,p[13],p[14],p15); - - let c4=new Split3(p0,p[4],p[8],p12); - let c5=new Split3(c0.m0,c1.m0,c2.m0,c3.m0); - let c6=new Split3(c0.m3,c1.m3,c2.m3,c3.m3); - let c7=new Split3(c0.m5,c1.m5,c2.m5,c3.m5); - let c8=new Split3(c0.m4,c1.m4,c2.m4,c3.m4); - let c9=new Split3(c0.m2,c1.m2,c2.m2,c3.m2); - let c10=new Split3(p3,p[7],p[11],p15); - - let s0=[p0,c0.m0,c0.m3,c0.m5,c4.m0,c5.m0,c6.m0,c7.m0, - c4.m3,c5.m3,c6.m3,c7.m3,c4.m5,c5.m5,c6.m5,c7.m5]; - let s1=[c4.m5,c5.m5,c6.m5,c7.m5,c4.m4,c5.m4,c6.m4,c7.m4, - c4.m2,c5.m2,c6.m2,c7.m2,p12,c3.m0,c3.m3,c3.m5]; - let s2=[c7.m5,c8.m5,c9.m5,c10.m5,c7.m4,c8.m4,c9.m4,c10.m4, - c7.m2,c8.m2,c9.m2,c10.m2,c3.m5,c3.m4,c3.m2,p15]; - let s3=[c0.m5,c0.m4,c0.m2,p3,c7.m0,c8.m0,c9.m0,c10.m0, - c7.m3,c8.m3,c9.m3,c10.m3,c7.m5,c8.m5,c9.m5,c10.m5]; - - let m4=s0[15]; - - let n0=this.normal(s0[0],s0[4],s0[8],s0[12],s0[13],s0[14],s0[15]); - if(abs2(n0) < this.epsilon) { - n0=this.normal(s0[0],s0[4],s0[8],s0[12],s0[11],s0[7],s0[3]); - if(abs2(n0) < this.epsilon) - n0=this.normal(s0[3],s0[2],s0[1],s0[0],s0[13],s0[14],s0[15]); - } - - let n1=this.normal(s1[12],s1[13],s1[14],s1[15],s1[11],s1[7],s1[3]); - if(abs2(n1) < this.epsilon) { - n1=this.normal(s1[12],s1[13],s1[14],s1[15],s1[2],s1[1],s1[0]); - if(abs2(n1) < this.epsilon) - n1=this.normal(s1[0],s1[4],s1[8],s1[12],s1[11],s1[7],s1[3]); - } - - let n2=this.normal(s2[15],s2[11],s2[7],s2[3],s2[2],s2[1],s2[0]); - if(abs2(n2) < this.epsilon) { - n2=this.normal(s2[15],s2[11],s2[7],s2[3],s2[4],s2[8],s2[12]); - if(abs2(n2) < this.epsilon) - n2=this.normal(s2[12],s2[13],s2[14],s2[15],s2[2],s2[1],s2[0]); - } - - let n3=this.normal(s3[3],s3[2],s3[1],s3[0],s3[4],s3[8],s3[12]); - if(abs2(n3) < this.epsilon) { - n3=this.normal(s3[3],s3[2],s3[1],s3[0],s3[13],s3[14],s3[15]); - if(abs2(n3) < this.epsilon) - n3=this.normal(s3[15],s3[11],s3[7],s3[3],s3[4],s3[8],s3[12]); - } - - let n4=this.normal(s2[3],s2[2],s2[1],m4,s2[4],s2[8],s2[12]); - - let e=this.Epsilon; - - // A kludge to remove subdivision cracks, only applied the first time - // an edge is found to be flat before the rest of the subpatch is. - let m0=[0.5*(P0[0]+P1[0]), - 0.5*(P0[1]+P1[1]), - 0.5*(P0[2]+P1[2])]; - if(!flat0) { - if((flat0=Straightness(p0,p[4],p[8],p12) < this.res2)) { - let r=unit(this.differential(s1[0],s1[1],s1[2],s1[3])); - m0=[m0[0]-e*r[0],m0[1]-e*r[1],m0[2]-e*r[2]]; - } - else m0=s0[12]; - } - - let m1=[0.5*(P1[0]+P2[0]), - 0.5*(P1[1]+P2[1]), - 0.5*(P1[2]+P2[2])]; - if(!flat1) { - if((flat1=Straightness(p12,p[13],p[14],p15) < this.res2)) { - let r=unit(this.differential(s2[12],s2[8],s2[4],s2[0])); - m1=[m1[0]-e*r[0],m1[1]-e*r[1],m1[2]-e*r[2]]; - } - else m1=s1[15]; - } - - let m2=[0.5*(P2[0]+P3[0]), - 0.5*(P2[1]+P3[1]), - 0.5*(P2[2]+P3[2])]; - if(!flat2) { - if((flat2=Straightness(p15,p[11],p[7],p3) < this.res2)) { - let r=unit(this.differential(s3[15],s3[14],s3[13],s3[12])); - m2=[m2[0]-e*r[0],m2[1]-e*r[1],m2[2]-e*r[2]]; - } - else m2=s2[3]; - } - - let m3=[0.5*(P3[0]+P0[0]), - 0.5*(P3[1]+P0[1]), - 0.5*(P3[2]+P0[2])]; - if(!flat3) { - if((flat3=Straightness(p0,p[1],p[2],p3) < this.res2)) { - let r=unit(this.differential(s0[3],s0[7],s0[11],s0[15])); - m3=[m3[0]-e*r[0],m3[1]-e*r[1],m3[2]-e*r[2]]; - } - else m3=s3[0]; - } - - if(C0) { - let c0=Array(4); - let c1=Array(4); - let c2=Array(4); - let c3=Array(4); - let c4=Array(4); - for(let i=0; i < 4; ++i) { - c0[i]=0.5*(C0[i]+C1[i]); - c1[i]=0.5*(C1[i]+C2[i]); - c2[i]=0.5*(C2[i]+C3[i]); - c3[i]=0.5*(C3[i]+C0[i]); - c4[i]=0.5*(c0[i]+c2[i]); - } - - let i0=this.data.Vertex(m0,n0,c0); - let i1=this.data.Vertex(m1,n1,c1); - let i2=this.data.Vertex(m2,n2,c2); - let i3=this.data.Vertex(m3,n3,c3); - let i4=this.data.Vertex(m4,n4,c4); - - this.Render(s0,I0,i0,i4,i3,P0,m0,m4,m3,flat0,false,false,flat3, - C0,c0,c4,c3); - this.Render(s1,i0,I1,i1,i4,m0,P1,m1,m4,flat0,flat1,false,false, - c0,C1,c1,c4); - this.Render(s2,i4,i1,I2,i2,m4,m1,P2,m2,false,flat1,flat2,false, - c4,c1,C2,c2); - this.Render(s3,i3,i4,i2,I3,m3,m4,m2,P3,false,false,flat2,flat3, - c3,c4,c2,C3); - } else { - let i0=this.vertex(m0,n0); - let i1=this.vertex(m1,n1); - let i2=this.vertex(m2,n2); - let i3=this.vertex(m3,n3); - let i4=this.vertex(m4,n4); - - this.Render(s0,I0,i0,i4,i3,P0,m0,m4,m3,flat0,false,false,flat3); - this.Render(s1,i0,I1,i1,i4,m0,P1,m1,m4,flat0,flat1,false,false); - this.Render(s2,i4,i1,I2,i2,m4,m1,P2,m2,false,flat1,flat2,false); - this.Render(s3,i3,i4,i2,I3,m3,m4,m2,P3,false,false,flat2,flat3); - } - } - } - -// Render a Bezier triangle via subdivision. - process3(p) { - if(wireframe == 1) { - this.curve(p,0,1,3,6); - this.curve(p,6,7,8,9); - this.curve(p,9,5,2,0); - return; - } - - let p0=p[0]; - let p6=p[6]; - let p9=p[9]; - - let n0=this.normal(p9,p[5],p[2],p0,p[1],p[3],p6); - let n1=this.normal(p0,p[1],p[3],p6,p[7],p[8],p9); - let n2=this.normal(p6,p[7],p[8],p9,p[5],p[2],p0); - - if(this.color) { - let c0=this.color[0]; - let c1=this.color[1]; - let c2=this.color[2]; - - let i0=this.data.Vertex(p0,n0,c0); - let i1=this.data.Vertex(p6,n1,c1); - let i2=this.data.Vertex(p9,n2,c2); - - this.Render3(p,i0,i1,i2,p0,p6,p9,false,false,false,c0,c1,c2); - - } else { - let i0=this.vertex(p0,n0); - let i1=this.vertex(p6,n1); - let i2=this.vertex(p9,n2); - - this.Render3(p,i0,i1,i2,p0,p6,p9,false,false,false); - } - if(this.data.indices.length > 0) this.append(); - } - - Render3(p,I0,I1,I2,P0,P1,P2,flat0,flat1,flat2,C0,C1,C2) { - if(this.Distance3(p) < this.res2) { // Bezier triangle is flat - if(!this.offscreen([P0,P1,P2])) { - if(wireframe == 0) { - this.data.indices.push(I0); - this.data.indices.push(I1); - this.data.indices.push(I2); - } else { - this.data.indices.push(I0); - this.data.indices.push(I1); - this.data.indices.push(I1); - this.data.indices.push(I2); - this.data.indices.push(I2); - this.data.indices.push(I0); - } - } - } else { - // Approximate bounds by bounding box of control polyhedron. - if(this.offscreen(p)) return; - - /* Control points are indexed as follows: - - Coordinate - Index - - 030 - 9 - /\ - / \ - / \ - / \ - / \ - 021 + + 120 - 5 / \ 8 - / \ - / \ - / \ - / \ - 012 + + + 210 - 2 / 111 \ 7 - / 4 \ - / \ - / \ - / \ - /__________________________________\ - 003 102 201 300 - 0 1 3 6 - - - Subdivision: - P2 - 030 - /\ - / \ - / \ - / \ - / \ - / up \ - / \ - / \ - p1 /________________\ p0 - /\ / \ - / \ / \ - / \ / \ - / \ center / \ - / \ / \ - / \ / \ - / left \ / right \ - / \ / \ - /________________V_________________\ - 003 p2 300 - P0 P1 - */ - - // Subdivide triangle: - - let l003=p[0]; - let p102=p[1]; - let p012=p[2]; - let p201=p[3]; - let p111=p[4]; - let p021=p[5]; - let r300=p[6]; - let p210=p[7]; - let p120=p[8]; - let u030=p[9]; - - let u021=[0.5*(u030[0]+p021[0]), - 0.5*(u030[1]+p021[1]), - 0.5*(u030[2]+p021[2])]; - let u120=[0.5*(u030[0]+p120[0]), - 0.5*(u030[1]+p120[1]), - 0.5*(u030[2]+p120[2])]; - - let p033=[0.5*(p021[0]+p012[0]), - 0.5*(p021[1]+p012[1]), - 0.5*(p021[2]+p012[2])]; - let p231=[0.5*(p120[0]+p111[0]), - 0.5*(p120[1]+p111[1]), - 0.5*(p120[2]+p111[2])]; - let p330=[0.5*(p120[0]+p210[0]), - 0.5*(p120[1]+p210[1]), - 0.5*(p120[2]+p210[2])]; - - let p123=[0.5*(p012[0]+p111[0]), - 0.5*(p012[1]+p111[1]), - 0.5*(p012[2]+p111[2])]; - - let l012=[0.5*(p012[0]+l003[0]), - 0.5*(p012[1]+l003[1]), - 0.5*(p012[2]+l003[2])]; - let p312=[0.5*(p111[0]+p201[0]), - 0.5*(p111[1]+p201[1]), - 0.5*(p111[2]+p201[2])]; - let r210=[0.5*(p210[0]+r300[0]), - 0.5*(p210[1]+r300[1]), - 0.5*(p210[2]+r300[2])]; - - let l102=[0.5*(l003[0]+p102[0]), - 0.5*(l003[1]+p102[1]), - 0.5*(l003[2]+p102[2])]; - let p303=[0.5*(p102[0]+p201[0]), - 0.5*(p102[1]+p201[1]), - 0.5*(p102[2]+p201[2])]; - let r201=[0.5*(p201[0]+r300[0]), - 0.5*(p201[1]+r300[1]), - 0.5*(p201[2]+r300[2])]; - - let u012=[0.5*(u021[0]+p033[0]), - 0.5*(u021[1]+p033[1]), - 0.5*(u021[2]+p033[2])]; - let u210=[0.5*(u120[0]+p330[0]), - 0.5*(u120[1]+p330[1]), - 0.5*(u120[2]+p330[2])]; - let l021=[0.5*(p033[0]+l012[0]), - 0.5*(p033[1]+l012[1]), - 0.5*(p033[2]+l012[2])]; - let p4xx=[0.5*p231[0]+0.25*(p111[0]+p102[0]), - 0.5*p231[1]+0.25*(p111[1]+p102[1]), - 0.5*p231[2]+0.25*(p111[2]+p102[2])]; - let r120=[0.5*(p330[0]+r210[0]), - 0.5*(p330[1]+r210[1]), - 0.5*(p330[2]+r210[2])]; - let px4x=[0.5*p123[0]+0.25*(p111[0]+p210[0]), - 0.5*p123[1]+0.25*(p111[1]+p210[1]), - 0.5*p123[2]+0.25*(p111[2]+p210[2])]; - let pxx4=[0.25*(p021[0]+p111[0])+0.5*p312[0], - 0.25*(p021[1]+p111[1])+0.5*p312[1], - 0.25*(p021[2]+p111[2])+0.5*p312[2]]; - let l201=[0.5*(l102[0]+p303[0]), - 0.5*(l102[1]+p303[1]), - 0.5*(l102[2]+p303[2])]; - let r102=[0.5*(p303[0]+r201[0]), - 0.5*(p303[1]+r201[1]), - 0.5*(p303[2]+r201[2])]; - - let l210=[0.5*(px4x[0]+l201[0]), - 0.5*(px4x[1]+l201[1]), - 0.5*(px4x[2]+l201[2])]; // =c120 - let r012=[0.5*(px4x[0]+r102[0]), - 0.5*(px4x[1]+r102[1]), - 0.5*(px4x[2]+r102[2])]; // =c021 - let l300=[0.5*(l201[0]+r102[0]), - 0.5*(l201[1]+r102[1]), - 0.5*(l201[2]+r102[2])]; // =r003=c030 - - let r021=[0.5*(pxx4[0]+r120[0]), - 0.5*(pxx4[1]+r120[1]), - 0.5*(pxx4[2]+r120[2])]; // =c012 - let u201=[0.5*(u210[0]+pxx4[0]), - 0.5*(u210[1]+pxx4[1]), - 0.5*(u210[2]+pxx4[2])]; // =c102 - let r030=[0.5*(u210[0]+r120[0]), - 0.5*(u210[1]+r120[1]), - 0.5*(u210[2]+r120[2])]; // =u300=c003 - - let u102=[0.5*(u012[0]+p4xx[0]), - 0.5*(u012[1]+p4xx[1]), - 0.5*(u012[2]+p4xx[2])]; // =c201 - let l120=[0.5*(l021[0]+p4xx[0]), - 0.5*(l021[1]+p4xx[1]), - 0.5*(l021[2]+p4xx[2])]; // =c210 - let l030=[0.5*(u012[0]+l021[0]), - 0.5*(u012[1]+l021[1]), - 0.5*(u012[2]+l021[2])]; // =u003=c300 - - let l111=[0.5*(p123[0]+l102[0]), - 0.5*(p123[1]+l102[1]), - 0.5*(p123[2]+l102[2])]; - let r111=[0.5*(p312[0]+r210[0]), - 0.5*(p312[1]+r210[1]), - 0.5*(p312[2]+r210[2])]; - let u111=[0.5*(u021[0]+p231[0]), - 0.5*(u021[1]+p231[1]), - 0.5*(u021[2]+p231[2])]; - let c111=[0.25*(p033[0]+p330[0]+p303[0]+p111[0]), - 0.25*(p033[1]+p330[1]+p303[1]+p111[1]), - 0.25*(p033[2]+p330[2]+p303[2]+p111[2])]; - - let l=[l003,l102,l012,l201,l111,l021,l300,l210,l120,l030]; // left - let r=[l300,r102,r012,r201,r111,r021,r300,r210,r120,r030]; // right - let u=[l030,u102,u012,u201,u111,u021,r030,u210,u120,u030]; // up - let c=[r030,u201,r021,u102,c111,r012,l030,l120,l210,l300]; // center - - let n0=this.normal(l300,r012,r021,r030,u201,u102,l030); - let n1=this.normal(r030,u201,u102,l030,l120,l210,l300); - let n2=this.normal(l030,l120,l210,l300,r012,r021,r030); - - let e=this.Epsilon; - - // A kludge to remove subdivision cracks, only applied the first time - // an edge is found to be flat before the rest of the subpatch is. - - let m0=[0.5*(P1[0]+P2[0]), - 0.5*(P1[1]+P2[1]), - 0.5*(P1[2]+P2[2])]; - if(!flat0) { - if((flat0=Straightness(r300,p210,p120,u030) < this.res2)) { - let r=unit(this.sumdifferential(c[0],c[2],c[5],c[9],c[1],c[3],c[6])); - m0=[m0[0]-e*r[0],m0[1]-e*r[1],m0[2]-e*r[2]]; - } - else m0=r030; - } - - - let m1=[0.5*(P2[0]+P0[0]), - 0.5*(P2[1]+P0[1]), - 0.5*(P2[2]+P0[2])]; - if(!flat1) { - if((flat1=Straightness(l003,p012,p021,u030) < this.res2)) { - let r=unit(this.sumdifferential(c[6],c[3],c[1],c[0],c[7],c[8],c[9])); - m1=[m1[0]-e*r[0],m1[1]-e*r[1],m1[2]-e*r[2]]; - } - else m1=l030; - } - - let m2=[0.5*(P0[0]+P1[0]), - 0.5*(P0[1]+P1[1]), - 0.5*(P0[2]+P1[2])]; - if(!flat2) { - if((flat2=Straightness(l003,p102,p201,r300) < this.res2)) { - let r=unit(this.sumdifferential(c[9],c[8],c[7],c[6],c[5],c[2],c[0])); - m2=[m2[0]-e*r[0],m2[1]-e*r[1],m2[2]-e*r[2]]; - } - else m2=l300; - } - - if(C0) { - let c0=Array(4); - let c1=Array(4); - let c2=Array(4); - for(let i=0; i < 4; ++i) { - c0[i]=0.5*(C1[i]+C2[i]); - c1[i]=0.5*(C2[i]+C0[i]); - c2[i]=0.5*(C0[i]+C1[i]); - } - - let i0=this.data.Vertex(m0,n0,c0); - let i1=this.data.Vertex(m1,n1,c1); - let i2=this.data.Vertex(m2,n2,c2); - - this.Render3(l,I0,i2,i1,P0,m2,m1,false,flat1,flat2,C0,c2,c1); - this.Render3(r,i2,I1,i0,m2,P1,m0,flat0,false,flat2,c2,C1,c0); - this.Render3(u,i1,i0,I2,m1,m0,P2,flat0,flat1,false,c1,c0,C2); - this.Render3(c,i0,i1,i2,m0,m1,m2,false,false,false,c0,c1,c2); - } else { - let i0=this.vertex(m0,n0); - let i1=this.vertex(m1,n1); - let i2=this.vertex(m2,n2); - - this.Render3(l,I0,i2,i1,P0,m2,m1,false,flat1,flat2); - this.Render3(r,i2,I1,i0,m2,P1,m0,flat0,false,flat2); - this.Render3(u,i1,i0,I2,m1,m0,P2,flat0,flat1,false); - this.Render3(c,i0,i1,i2,m0,m1,m2,false,false,false); - } - } - } - - // Check the flatness of a Bezier patch - Distance(p) { - let p0=p[0]; - let p3=p[3]; - let p12=p[12]; - let p15=p[15]; - - // Check the horizontal flatness. - let h=Flatness(p0,p12,p3,p15); - // Check straightness of the horizontal edges and interior control curves. - h=Math.max(Straightness(p0,p[4],p[8],p12)); - h=Math.max(h,Straightness(p[1],p[5],p[9],p[13])); - h=Math.max(h,Straightness(p3,p[7],p[11],p15)); - h=Math.max(h,Straightness(p[2],p[6],p[10],p[14])); - - // Check the vertical flatness. - let v=Flatness(p0,p3,p12,p15); - // Check straightness of the vertical edges and interior control curves. - v=Math.max(v,Straightness(p0,p[1],p[2],p3)); - v=Math.max(v,Straightness(p[4],p[5],p[6],p[7])); - v=Math.max(v,Straightness(p[8],p[9],p[10],p[11])); - v=Math.max(v,Straightness(p12,p[13],p[14],p15)); - - return [h,v]; - } - - // Check the flatness of a Bezier triangle - Distance3(p) { - let p0=p[0]; - let p4=p[4]; - let p6=p[6]; - let p9=p[9]; - - // Check how far the internal point is from the centroid of the vertices. - let d=abs2([(p0[0]+p6[0]+p9[0])*third-p4[0], - (p0[1]+p6[1]+p9[1])*third-p4[1], - (p0[2]+p6[2]+p9[2])*third-p4[2]]); - - // Determine how straight the edges are. - d=Math.max(d,Straightness(p0,p[1],p[3],p6)); - d=Math.max(d,Straightness(p0,p[2],p[5],p9)); - return Math.max(d,Straightness(p6,p[7],p[8],p9)); - } - - // Return the differential of the Bezier curve p0,p1,p2,p3 at 0. - differential(p0,p1,p2,p3) { - let p=[3*(p1[0]-p0[0]),3*(p1[1]-p0[1]),3*(p1[2]-p0[2])]; - if(abs2(p) > this.epsilon) - return p; - - p=bezierPP(p0,p1,p2); - if(abs2(p) > this.epsilon) - return p; - - return bezierPPP(p0,p1,p2,p3); - } - - sumdifferential(p0,p1,p2,p3,p4,p5,p6) { - let d0=this.differential(p0,p1,p2,p3); - let d1=this.differential(p0,p4,p5,p6); - return [d0[0]+d1[0],d0[1]+d1[1],d0[2]+d1[2]]; - } - - normal(left3,left2,left1,middle,right1,right2,right3) { - let ux=3*(right1[0]-middle[0]); - let uy=3*(right1[1]-middle[1]); - let uz=3*(right1[2]-middle[2]); - let vx=3*(left1[0]-middle[0]); - let vy=3*(left1[1]-middle[1]); - let vz=3*(left1[2]-middle[2]); - - let n=[uy*vz-uz*vy, - uz*vx-ux*vz, - ux*vy-uy*vx]; - if(abs2(n) > this.epsilon) - return n; - - let lp=[vx,vy,vz]; - let rp=[ux,uy,uz]; - - let lpp=bezierPP(middle,left1,left2); - let rpp=bezierPP(middle,right1,right2); - - let a=cross(rpp,lp); - let b=cross(rp,lpp); - n=[a[0]+b[0], - a[1]+b[1], - a[2]+b[2]]; - if(abs2(n) > this.epsilon) - return n; - - let lppp=bezierPPP(middle,left1,left2,left3); - let rppp=bezierPPP(middle,right1,right2,right3); - - a=cross(rp,lppp); - b=cross(rppp,lp); - let c=cross(rpp,lpp); - - n=[a[0]+b[0]+c[0], - a[1]+b[1]+c[1], - a[2]+b[2]+c[2]]; - if(abs2(n) > this.epsilon) - return n; - - a=cross(rppp,lpp); - b=cross(rpp,lppp); - - n=[a[0]+b[0], - a[1]+b[1], - a[2]+b[2]]; - if(abs2(n) > this.epsilon) - return n; - - return cross(rppp,lppp); - } -} - -class BezierCurve extends Geometry { - constructor(controlpoints,CenterIndex,MaterialIndex,Min,Max) { - super(); - this.controlpoints=controlpoints; - this.Min=Min; - this.Max=Max; - this.CenterIndex=CenterIndex; - this.MaterialIndex=MaterialIndex; - } - - setMaterialIndex() { - this.setMaterial(material1Data,drawMaterial1); - } - - processLine(p) { - let p0=p[0]; - let p1=p[1]; - if(!this.offscreen([p0,p1])) { - let n=[0,0,1]; - this.data.indices.push(this.data.vertex(p0,n)); - this.data.indices.push(this.data.vertex(p1,n)); - this.append(); - } - } - - process(p) { - if(p.length == 2) return this.processLine(p); - - let p0=p[0]; - let p1=p[1]; - let p2=p[2]; - let p3=p[3]; - - let n0=this.normal(bezierP(p0,p1),bezierPP(p0,p1,p2)); - let n1=this.normal(bezierP(p2,p3),bezierPP(p3,p2,p1)); - - let i0=this.data.vertex(p0,n0); - let i3=this.data.vertex(p3,n1); - - this.Render(p,i0,i3); - if(this.data.indices.length > 0) this.append(); - } - - append() { - material1Data.append(this.data); - } - - notRendered() { - material1Data.rendered=false; - } - - Render(p,I0,I1) { - let p0=p[0]; - let p1=p[1]; - let p2=p[2]; - let p3=p[3]; - - if(Straightness(p0,p1,p2,p3) < this.res2) { // Segment is flat - if(!this.offscreen([p0,p3])) { - this.data.indices.push(I0); - this.data.indices.push(I1); - } - } else { // Segment is not flat - if(this.offscreen(p)) return; - - let m0=[0.5*(p0[0]+p1[0]),0.5*(p0[1]+p1[1]),0.5*(p0[2]+p1[2])]; - let m1=[0.5*(p1[0]+p2[0]),0.5*(p1[1]+p2[1]),0.5*(p1[2]+p2[2])]; - let m2=[0.5*(p2[0]+p3[0]),0.5*(p2[1]+p3[1]),0.5*(p2[2]+p3[2])]; - let m3=[0.5*(m0[0]+m1[0]),0.5*(m0[1]+m1[1]),0.5*(m0[2]+m1[2])]; - let m4=[0.5*(m1[0]+m2[0]),0.5*(m1[1]+m2[1]),0.5*(m1[2]+m2[2])]; - let m5=[0.5*(m3[0]+m4[0]),0.5*(m3[1]+m4[1]),0.5*(m3[2]+m4[2])]; - - let s0=[p0,m0,m3,m5]; - let s1=[m5,m4,m2,p3]; - - let n0=this.normal(bezierPh(p0,p1,p2,p3),bezierPPh(p0,p1,p2,p3)); - let i0=this.data.vertex(m5,n0); - - this.Render(s0,I0,i0); - this.Render(s1,i0,I1); - } - } - - normal(bP,bPP) { - let bPbP=dot(bP,bP); - let bPbPP=dot(bP,bPP); - return [bPbP*bPP[0]-bPbPP*bP[0], - bPbP*bPP[1]-bPbPP*bP[1], - bPbP*bPP[2]-bPbPP*bP[2]]; - } -} - -class Pixel extends Geometry { - constructor(controlpoint,width,MaterialIndex,Min,Max) { - super(); - this.controlpoint=controlpoint; - this.width=width; - this.CenterIndex=0; - this.MaterialIndex=MaterialIndex; - this.Min=Min; - this.Max=Max; - } - - setMaterialIndex() { - this.setMaterial(material0Data,drawMaterial0); - } - - process(p) { - this.data.indices.push(this.data.vertex0(this.controlpoint,this.width)); - this.append(); - } - - append() { - material0Data.append(this.data); - } - - notRendered() { - material0Data.rendered=false; - } -} - -class Triangles extends Geometry { - constructor(MaterialIndex,Min,Max) { - super(); - this.CenterIndex=0; - this.MaterialIndex=MaterialIndex; - this.Min=Min; - this.Max=Max; - this.Positions=Positions; - this.Normals=Normals; - this.Colors=Colors; - this.Indices=Indices; - Positions=[]; - Normals=[]; - Colors=[]; - Indices=[]; - this.transparent=Materials[MaterialIndex].diffuse[3] < 1; - } - - setMaterialIndex() { - if(this.transparent) - this.setMaterial(transparentData,drawTransparent); - else - this.setMaterial(triangleData,drawTriangle); - } - - process(p) { - // Override materialIndex to encode color vs material - materialIndex=this.Colors.length > 0 ? - -1-materialIndex : 1+materialIndex; - - for(let i=0, n=this.Indices.length; i < n; ++i) { - let index=this.Indices[i]; - let PI=index[0]; - let P0=this.Positions[PI[0]]; - let P1=this.Positions[PI[1]]; - let P2=this.Positions[PI[2]]; - if(!this.offscreen([P0,P1,P2])) { - let NI=index.length > 1 ? index[1] : PI; - if(!NI || NI.length == 0) NI=PI; - if(this.Colors.length > 0) { - let CI=index.length > 2 ? index[2] : PI; - if(!CI || CI.length == 0) CI=PI; - let C0=this.Colors[CI[0]]; - let C1=this.Colors[CI[1]]; - let C2=this.Colors[CI[2]]; - this.transparent |= C0[3]+C1[3]+C2[3] < 765; - if(wireframe == 0) { - this.data.iVertex(PI[0],P0,this.Normals[NI[0]],C0); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]],C1); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]],C2); - } else { - this.data.iVertex(PI[0],P0,this.Normals[NI[0]],C0); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]],C1); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]],C1); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]],C2); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]],C2); - this.data.iVertex(PI[0],P0,this.Normals[NI[0]],C0); - } - } else { - if(wireframe == 0) { - this.data.iVertex(PI[0],P0,this.Normals[NI[0]]); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]]); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]]); - } else { - this.data.iVertex(PI[0],P0,this.Normals[NI[0]]); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]]); - this.data.iVertex(PI[1],P1,this.Normals[NI[1]]); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]]); - this.data.iVertex(PI[2],P2,this.Normals[NI[2]]); - this.data.iVertex(PI[0],P0,this.Normals[NI[0]]); - } - } - } - } - this.data.nvertices=this.Positions.length; - if(this.data.indices.length > 0) this.append(); - } - - append() { - if(this.transparent) - transparentData.append(this.data); - else - triangleData.append(this.data); - } - - notRendered() { - if(this.transparent) - transparentData.rendered=false; - else - triangleData.rendered=false; - } - -} - -function redraw() -{ - initProjection(); - setProjection(); - remesh=true; - draw(); -} - -function home() -{ - mat4.identity(rotMat); - redraw(); -} - -let positionAttribute=0; -let normalAttribute=1; -let materialAttribute=2; -let colorAttribute=3; -let widthAttribute=4; - -function initShader(options=[]) -{ - let vertexShader=getShader(gl,vertex,gl.VERTEX_SHADER,options); - let fragmentShader=getShader(gl,fragment,gl.FRAGMENT_SHADER,options); - let shader=gl.createProgram(); - - gl.attachShader(shader,vertexShader); - gl.attachShader(shader,fragmentShader); - gl.bindAttribLocation(shader,positionAttribute,"position"); - gl.bindAttribLocation(shader,normalAttribute,"normal"); - gl.bindAttribLocation(shader,materialAttribute,"materialIndex"); - gl.bindAttribLocation(shader,colorAttribute,"color"); - gl.bindAttribLocation(shader,widthAttribute,"width"); - gl.linkProgram(shader); - if (!gl.getProgramParameter(shader,gl.LINK_STATUS)) { - alert("Could not initialize shaders"); - } - - return shader; -} - -class Split3 { - constructor(z0,c0,c1,z1) { - this.m0=[0.5*(z0[0]+c0[0]),0.5*(z0[1]+c0[1]),0.5*(z0[2]+c0[2])]; - let m1_0=0.5*(c0[0]+c1[0]); - let m1_1=0.5*(c0[1]+c1[1]); - let m1_2=0.5*(c0[2]+c1[2]); - this.m2=[0.5*(c1[0]+z1[0]),0.5*(c1[1]+z1[1]),0.5*(c1[2]+z1[2])]; - this.m3=[0.5*(this.m0[0]+m1_0),0.5*(this.m0[1]+m1_1), - 0.5*(this.m0[2]+m1_2)]; - this.m4=[0.5*(m1_0+this.m2[0]),0.5*(m1_1+this.m2[1]), - 0.5*(m1_2+this.m2[2])]; - this.m5=[0.5*(this.m3[0]+this.m4[0]),0.5*(this.m3[1]+this.m4[1]), - 0.5*(this.m3[2]+this.m4[2])]; - } -} - -function unit(v) -{ - let norm=1/(Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]) || 1); - return [v[0]*norm,v[1]*norm,v[2]*norm]; -} - -function abs2(v) -{ - return v[0]*v[0]+v[1]*v[1]+v[2]*v[2]; -} - -function dot(u,v) -{ - return u[0]*v[0]+u[1]*v[1]+u[2]*v[2]; -} - -function cross(u,v) -{ - return [u[1]*v[2]-u[2]*v[1], - u[2]*v[0]-u[0]*v[2], - u[0]*v[1]-u[1]*v[0]]; -} - -// Return one-third of the first derivative of the Bezier curve defined -// by a,b,c,d at t=0. -function bezierP(a,b) -{ - return [b[0]-a[0], - b[1]-a[1], - b[2]-a[2]]; -} - -// Return one-half of the second derivative of the Bezier curve defined -// by a,b,c,d at t=0. -function bezierPP(a,b,c) -{ - return [3*(a[0]+c[0])-6*b[0], - 3*(a[1]+c[1])-6*b[1], - 3*(a[2]+c[2])-6*b[2]]; -} - -// Return one-sixth of the third derivative of the Bezier curve defined by -// a,b,c,d at t=0. -function bezierPPP(a,b,c,d) -{ - return [d[0]-a[0]+3*(b[0]-c[0]), - d[1]-a[1]+3*(b[1]-c[1]), - d[2]-a[2]+3*(b[2]-c[2])]; -} - -// Return four-thirds of the first derivative of the Bezier curve defined by -// a,b,c,d at t=1/2. -function bezierPh(a,b,c,d) -{ - return [c[0]+d[0]-a[0]-b[0], - c[1]+d[1]-a[1]-b[1], - c[2]+d[2]-a[2]-b[2]]; -} - -// Return two-thirds of the second derivative of the Bezier curve defined by -// a,b,c,d at t=1/2. -function bezierPPh(a,b,c,d) -{ - return [3*a[0]-5*b[0]+c[0]+d[0], - 3*a[1]-5*b[1]+c[1]+d[1], - 3*a[2]-5*b[2]+c[2]+d[2]]; -} - -/** - * Return the maximum distance squared of points c0 and c1 from - * the respective internal control points of z0--z1. -*/ -function Straightness(z0,c0,c1,z1) -{ - let v=[third*(z1[0]-z0[0]),third*(z1[1]-z0[1]),third*(z1[2]-z0[2])]; - return Math.max(abs2([c0[0]-v[0]-z0[0],c0[1]-v[1]-z0[1],c0[2]-v[2]-z0[2]]), - abs2([z1[0]-v[0]-c1[0],z1[1]-v[1]-c1[1],z1[2]-v[2]-c1[2]])); -} - -// Return one ninth of the relative flatness squared of a--b and c--d. -function Flatness(a,b,c,d) -{ - let u=[b[0]-a[0],b[1]-a[1],b[2]-a[2]]; - let v=[d[0]-c[0],d[1]-c[1],d[2]-c[2]]; - return Math.max(abs2(cross(u,unit(v))),abs2(cross(v,unit(u))))/9; -} - -// Return the vertices of the box containing 3d points m and M. -function corners(m,M) -{ - return [m,[m[0],m[1],M[2]],[m[0],M[1],m[2]],[m[0],M[1],M[2]], - [M[0],m[1],m[2]],[M[0],m[1],M[2]],[M[0],M[1],m[2]],M]; -} - -function minbound(v) { - return [ - Math.min(v[0][0],v[1][0],v[2][0],v[3][0],v[4][0],v[5][0],v[6][0],v[7][0]), - Math.min(v[0][1],v[1][1],v[2][1],v[3][1],v[4][1],v[5][1],v[6][1],v[7][1]), - Math.min(v[0][2],v[1][2],v[2][2],v[3][2],v[4][2],v[5][2],v[6][2],v[7][2]) - ]; -} - -function maxbound(v) { - return [ - Math.max(v[0][0],v[1][0],v[2][0],v[3][0],v[4][0],v[5][0],v[6][0],v[7][0]), - Math.max(v[0][1],v[1][1],v[2][1],v[3][1],v[4][1],v[5][1],v[6][1],v[7][1]), - Math.max(v[0][2],v[1][2],v[2][2],v[3][2],v[4][2],v[5][2],v[6][2],v[7][2]) - ]; -} - -/** - * Perform a change of basis - * @param {*} out Out Matrix - * @param {*} mat Matrix - * - * Compute the matrix (translMatrix) * mat * (translMatrix)^{-1} - */ - -function COBTarget(out,mat) -{ - mat4.fromTranslation(T,[center.x,center.y,center.z]) - mat4.invert(cjMatInv,T); - mat4.multiply(out,mat,cjMatInv); - mat4.multiply(out,T,out); -} - -function setUniforms(data,shader) -{ - let pixel=shader == pixelShader; - - gl.useProgram(shader); - - gl.enableVertexAttribArray(positionAttribute); - - if(pixel) - gl.enableVertexAttribArray(widthAttribute); - - let normals=!pixel && Lights.length > 0; - if(normals) - gl.enableVertexAttribArray(normalAttribute); - - gl.enableVertexAttribArray(materialAttribute); - - shader.projViewMatUniform=gl.getUniformLocation(shader,"projViewMat"); - shader.viewMatUniform=gl.getUniformLocation(shader,"viewMat"); - shader.normMatUniform=gl.getUniformLocation(shader,"normMat"); - - if(shader == colorShader || shader == transparentShader) - gl.enableVertexAttribArray(colorAttribute); - - if(normals) { - for(let i=0; i < Lights.length; ++i) - Lights[i].setUniform(shader,i); - } - - for(let i=0; i < data.materials.length; ++i) - data.materials[i].setUniform(shader,i); - - gl.uniformMatrix4fv(shader.projViewMatUniform,false,projViewMat); - gl.uniformMatrix4fv(shader.viewMatUniform,false,viewMat); - gl.uniformMatrix3fv(shader.normMatUniform,false,normMat); -} - -function handleMouseDown(event) -{ - if(!zoomEnabled) - enableZoom(); - mouseDownOrTouchActive=true; - lastMouseX=event.clientX; - lastMouseY=event.clientY; -} - -let pinch=false; -let pinchStart; - -function pinchDistance(touches) -{ - return Math.hypot( - touches[0].pageX-touches[1].pageX, - touches[0].pageY-touches[1].pageY); -} - - -let touchStartTime; - -function handleTouchStart(event) -{ - event.preventDefault(); - if(!zoomEnabled) - enableZoom(); - let touches=event.targetTouches; - swipe=rotate=pinch=false; - if(zooming) return; - - if(touches.length == 1 && !mouseDownOrTouchActive) { - touchStartTime=new Date().getTime(); - touchId=touches[0].identifier; - lastMouseX=touches[0].pageX, - lastMouseY=touches[0].pageY; - } - - if(touches.length == 2 && !mouseDownOrTouchActive) { - touchId=touches[0].identifier; - pinchStart=pinchDistance(touches); - pinch=true; - } -} - -function handleMouseUpOrTouchEnd(event) -{ - mouseDownOrTouchActive=false; -} - -function rotateScene(lastX,lastY,rawX,rawY,factor) -{ - if(lastX == rawX && lastY == rawY) return; - let [angle,axis]=arcball([lastX,-lastY],[rawX,-rawY]); - - mat4.fromRotation(T,2*factor*ArcballFactor*angle/Zoom,axis); - mat4.multiply(rotMat,T,rotMat); -} - -function shiftScene(lastX,lastY,rawX,rawY) -{ - let zoominv=1/Zoom; - shift.x += (rawX-lastX)*zoominv*halfCanvasWidth; - shift.y -= (rawY-lastY)*zoominv*halfCanvasHeight; -} - -function panScene(lastX,lastY,rawX,rawY) -{ - if (orthographic) { - shiftScene(lastX,lastY,rawX,rawY); - } else { - center.x += (rawX-lastX)*(viewParam.xmax-viewParam.xmin); - center.y -= (rawY-lastY)*(viewParam.ymax-viewParam.ymin); - } -} - -function updateViewMatrix() -{ - COBTarget(viewMat,rotMat); - mat4.translate(viewMat,viewMat,[center.x,center.y,0]); - mat3.fromMat4(viewMat3,viewMat); - mat3.invert(normMat,viewMat3); - mat4.multiply(projViewMat,projMat,viewMat); -} - -function capzoom() -{ - let maxzoom=Math.sqrt(Number.MAX_VALUE); - let minzoom=1/maxzoom; - if(Zoom <= minzoom) Zoom=minzoom; - if(Zoom >= maxzoom) Zoom=maxzoom; - - if(zoomRemeshFactor*Zoom < lastZoom || Zoom > zoomRemeshFactor*lastZoom) { - remesh=true; - lastZoom=Zoom; - } -} - -function zoomImage(diff) -{ - let stepPower=zoomStep*halfCanvasHeight*diff; - const limit=Math.log(0.1*Number.MAX_VALUE)/Math.log(zoomFactor); - - if(Math.abs(stepPower) < limit) { - Zoom *= zoomFactor**stepPower; - capzoom(); - } -} - -function normMouse(v) -{ - let v0=v[0]; - let v1=v[1]; - let norm=Math.hypot(v0,v1); - if(norm > 1) { - denom=1/norm; - v0 *= denom; - v1 *= denom; - } - return [v0,v1,Math.sqrt(Math.max(1-v1*v1-v0*v0,0))]; -} - -function arcball(oldmouse,newmouse) -{ - let oldMouse=normMouse(oldmouse); - let newMouse=normMouse(newmouse); - let Dot=dot(oldMouse,newMouse); - let angle=Dot > 1 ? 0 : Dot < -1 ? pi : Math.acos(Dot); - return [angle,unit(cross(oldMouse,newMouse))] -} - -/** - * Mouse Drag Zoom - * @param {*} lastX unused - * @param {*} lastY - * @param {*} rawX unused - * @param {*} rawY - */ -function zoomScene(lastX,lastY,rawX,rawY) -{ - zoomImage(lastY-rawY); -} - -// mode: -const DRAGMODE_ROTATE=1; -const DRAGMODE_SHIFT=2; -const DRAGMODE_ZOOM=3; -const DRAGMODE_PAN=4 -function processDrag(newX,newY,mode,factor=1) -{ - let dragFunc; - switch (mode) { - case DRAGMODE_ROTATE: - dragFunc=rotateScene; - break; - case DRAGMODE_SHIFT: - dragFunc=shiftScene; - break; - case DRAGMODE_ZOOM: - dragFunc=zoomScene; - break; - case DRAGMODE_PAN: - dragFunc=panScene; - break; - default: - dragFunc=(_a,_b,_c,_d) => {}; - break; - } - - let lastX=(lastMouseX-halfCanvasWidth)/halfCanvasWidth; - let lastY=(lastMouseY-halfCanvasHeight)/halfCanvasHeight; - let rawX=(newX-halfCanvasWidth)/halfCanvasWidth; - let rawY=(newY-halfCanvasHeight)/halfCanvasHeight; - - dragFunc(lastX,lastY,rawX,rawY,factor); - - lastMouseX=newX; - lastMouseY=newY; - - setProjection(); - draw(); -} - -let zoomEnabled=0; - -function enableZoom() -{ - zoomEnabled=1; - canvas.addEventListener("wheel",handleMouseWheel,false); -} - -function disableZoom() -{ - zoomEnabled=0; - canvas.removeEventListener("wheel",handleMouseWheel,false); -} - -function handleKey(event) -{ - let ESC=27; - - if(!zoomEnabled) - enableZoom(); - - if(embedded && zoomEnabled && event.keyCode == ESC) { - disableZoom(); - return; - } - - let keycode=event.key; - let axis=[]; - - switch(keycode) { - case 'x': - axis=[1,0,0]; - break; - case 'y': - axis=[0,1,0]; - break; - case 'z': - axis=[0,0,1]; - break; - case 'h': - home(); - break; - case 'm': - ++wireframe; - if(wireframe == 3) wireframe=0; - if(wireframe != 2) { - if(!embedded) - deleteShaders(); - initShaders(); - } - remesh=true; - draw(); - break; - case '+': - case '=': - case '>': - expand(); - break; - case '-': - case '_': - case '<': - shrink(); - break; - default: - break; - } - - if(axis.length > 0) { - mat4.rotate(rotMat,rotMat,0.1,axis); - updateViewMatrix(); - draw(); - } -} - -function setZoom() -{ - capzoom(); - setProjection(); - draw(); -} - -function handleMouseWheel(event) -{ - event.preventDefault(); - - if (event.deltaY < 0) { - Zoom *= zoomFactor; - } else { - Zoom /= zoomFactor; - } - - setZoom(); -} - -function handleMouseMove(event) -{ - if(!mouseDownOrTouchActive) { - return; - } - - let newX=event.clientX; - let newY=event.clientY; - - let mode; - if(event.getModifierState("Control")) { - mode=DRAGMODE_SHIFT; - } else if(event.getModifierState("Shift")) { - mode=DRAGMODE_ZOOM; - } else if(event.getModifierState("Alt")) { - mode=DRAGMODE_PAN; - } else { - mode=DRAGMODE_ROTATE; - } - - processDrag(newX,newY,mode); -} - -let zooming=false; -let swipe=false; -let rotate=false; - -function handleTouchMove(event) -{ - event.preventDefault(); - if(zooming) return; - let touches=event.targetTouches; - - if(!pinch && touches.length == 1 && touchId == touches[0].identifier) { - let newX=touches[0].pageX; - let newY=touches[0].pageY; - let dx=newX-lastMouseX; - let dy=newY-lastMouseY; - let stationary=dx*dx+dy*dy <= shiftHoldDistance*shiftHoldDistance; - if(stationary) { - if(!swipe && !rotate && - new Date().getTime()-touchStartTime > shiftWaitTime) { - if(navigator.vibrate) - window.navigator.vibrate(vibrateTime); - swipe=true; - } - } - if(swipe) - processDrag(newX,newY,DRAGMODE_SHIFT); - else if(!stationary) { - rotate=true; - let newX=touches[0].pageX; - let newY=touches[0].pageY; - processDrag(newX,newY,DRAGMODE_ROTATE,0.5); - } - } - - if(pinch && !swipe && - touches.length == 2 && touchId == touches[0].identifier) { - let distance=pinchDistance(touches); - let diff=distance-pinchStart; - zooming=true; - diff *= zoomPinchFactor; - if(diff > zoomPinchCap) diff=zoomPinchCap; - if(diff < -zoomPinchCap) diff=-zoomPinchCap; - zoomImage(diff/size2); - pinchStart=distance; - swipe=rotate=zooming=false; - setProjection(); - draw(); - } -} - -let zbuffer=[]; - -function transformVertices(vertices) -{ - let Tz0=viewMat[2]; - let Tz1=viewMat[6]; - let Tz2=viewMat[10]; - zbuffer.length=vertices.length; - for(let i=0; i < vertices.length; ++i) { - let i6=6*i; - zbuffer[i]=Tz0*vertices[i6]+Tz1*vertices[i6+1]+Tz2*vertices[i6+2]; - } -} - -function drawMaterial0() -{ - drawBuffer(material0Data,pixelShader); - material0Data.clear(); -} - -function drawMaterial1() -{ - drawBuffer(material1Data,materialShader); - material1Data.clear(); -} - -function drawMaterial() -{ - drawBuffer(materialData,materialShader); - materialData.clear(); -} - -function drawColor() -{ - drawBuffer(colorData,colorShader); - colorData.clear(); -} - -function drawTriangle() -{ - drawBuffer(triangleData,transparentShader); - triangleData.rendered=false; // Force copying of sorted triangles to GPU. - triangleData.clear(); -} - -function drawTransparent() -{ - let indices=transparentData.indices; - if(wireframe > 0) { - drawBuffer(transparentData,transparentShader,indices); - transparentData.clear(); - return; - } - if(indices.length > 0) { - transformVertices(transparentData.vertices); - - let n=indices.length/3; - let triangles=Array(n).fill().map((_,i)=>i); - - triangles.sort(function(a,b) { - let a3=3*a; - Ia=indices[a3]; - Ib=indices[a3+1]; - Ic=indices[a3+2]; - - let b3=3*b; - IA=indices[b3]; - IB=indices[b3+1]; - IC=indices[b3+2]; - - return zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic] < - zbuffer[IA]+zbuffer[IB]+zbuffer[IC] ? -1 : 1; - }); - - let Indices=Array(indices.length); - - for(let i=0; i < n; ++i) { - let i3=3*i; - let t=3*triangles[i]; - Indices[3*i]=indices[t]; - Indices[3*i+1]=indices[t+1]; - Indices[3*i+2]=indices[t+2]; - } - - gl.depthMask(false); // Enable transparency - drawBuffer(transparentData,transparentShader,Indices); - // Force copying of sorted triangles to GPU. - transparentData.rendered=false; - gl.depthMask(true); // Disable transparency - } - transparentData.clear(); -} - -function drawBuffers() -{ - drawMaterial0(); - drawMaterial1(); - drawMaterial(); - drawColor(); - drawTriangle(); - drawTransparent(); -} - -function draw() -{ - if(embedded) { - offscreen.width=canvasWidth; - offscreen.height=canvasHeight; - setViewport(); - } - - gl.clearColor(Background[0],Background[1],Background[2],Background[3]); - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - for(let i=0; i < P.length; ++i) - P[i].render(); - - drawBuffers(); - - if(embedded) { - context.clearRect(0,0,canvasWidth,canvasHeight); - context.drawImage(offscreen,0,0); - } - - if(wireframe == 0) remesh=false; -} - -function setDimensions(width,height,X,Y) -{ - let Aspect=width/height; - let zoominv=1/Zoom; - let xshift=(X/width+viewportshift[0])*Zoom; - let yshift=(Y/height+viewportshift[1])*Zoom; - - if (orthographic) { - let xsize=B[0]-b[0]; - let ysize=B[1]-b[1]; - if (xsize < ysize*Aspect) { - let r=0.5*ysize*Aspect*zoominv; - let X0=2*r*xshift; - let Y0=ysize*zoominv*yshift; - viewParam.xmin=-r-X0; - viewParam.xmax=r-X0; - viewParam.ymin=b[1]*zoominv-Y0; - viewParam.ymax=B[1]*zoominv-Y0; - } else { - let r=0.5*xsize/(Aspect*Zoom); - let X0=xsize*zoominv*xshift; - let Y0=2*r*yshift; - viewParam.xmin=b[0]*zoominv-X0; - viewParam.xmax=B[0]*zoominv-X0; - viewParam.ymin=-r-Y0; - viewParam.ymax=r-Y0; - } - } else { - let r=H*zoominv; - let rAspect=r*Aspect; - let X0=2*rAspect*xshift; - let Y0=2*r*yshift; - viewParam.xmin=-rAspect-X0; - viewParam.xmax=rAspect-X0; - viewParam.ymin=-r-Y0; - viewParam.ymax=r-Y0; - } -} - -function setProjection() -{ - setDimensions(canvasWidth,canvasHeight,shift.x,shift.y); - let f=orthographic ? mat4.ortho : mat4.frustum; - f(projMat,viewParam.xmin,viewParam.xmax, - viewParam.ymin,viewParam.ymax, - -viewParam.zmax,-viewParam.zmin); - updateViewMatrix(); -} - -function initProjection() -{ - H=-Math.tan(0.5*angle)*B[2]; - - center.x=center.y=0; - center.z=0.5*(b[2]+B[2]); - lastZoom=Zoom=zoom0; - - viewParam.zmin=b[2]; - viewParam.zmax=B[2]; - - shift.x=shift.y=0; -} - -function setViewport() -{ - gl.viewportWidth=canvasWidth; - gl.viewportHeight=canvasHeight; - gl.viewport(0.5*(canvas.width-canvasWidth),0.5*(canvas.height-canvasHeight), - canvasWidth,canvasHeight); - gl.scissor(0,0,canvas.width,canvas.height); -} - -function setCanvas() -{ - if(embedded) { - canvas.width=offscreen.width=canvasWidth; - canvas.height=offscreen.height=canvasHeight; - } - size2=Math.hypot(canvasWidth,canvasHeight); - halfCanvasWidth=0.5*canvas.width; - halfCanvasHeight=0.5*canvas.height; - ArcballFactor=1+8*Math.hypot(viewportmargin[0],viewportmargin[1])/size2; -} - -function setsize(w,h) -{ - if(w > maxViewportWidth) - w=maxViewportWidth; - - if(h > maxViewportHeight) - h=maxViewportHeight; - - shift.x *= w/canvasWidth; - shift.y *= h/canvasHeight; - - canvasWidth=w; - canvasHeight=h; - setCanvas(); - setViewport(); - - setProjection(); - remesh=true; -} - -function resize() -{ - zoom0=Zoom0; - - if(absolute && !embedded) { - canvasWidth=canvasWidth0*window.devicePixelRatio; - canvasHeight=canvasHeight0*window.devicePixelRatio; - } else { - let Aspect=canvasWidth0/canvasHeight0; - canvasWidth=Math.max(window.innerWidth-windowTrim,windowTrim); - canvasHeight=Math.max(window.innerHeight-windowTrim,windowTrim); - - if(!orthographic && canvasWidth < canvasHeight*Aspect) - zoom0 *= canvasWidth/(canvasHeight*Aspect); - } - - canvas.width=canvasWidth; - canvas.height=canvasHeight; - - let maxViewportWidth=window.innerWidth; - let maxViewportHeight=window.innerHeight; - - viewportshift[0] /= zoom0; - viewportshift[1] /= zoom0; - - setsize(canvasWidth,canvasHeight); - redraw(); -} - -function expand() -{ - Zoom *= zoomFactor; - setZoom(); -} - -function shrink() -{ - Zoom /= zoomFactor; - setZoom(); -} - -let pixelShader,materialShader,colorShader,transparentShader; - -class Align { - constructor(center,dir) { - this.center=center; - if(dir) { - let theta=dir[0]; - let phi=dir[1]; - - this.ct=Math.cos(theta); - this.st=Math.sin(theta); - this.cp=Math.cos(phi); - this.sp=Math.sin(phi); - } - } - - T0(v) { - return [v[0]+this.center[0],v[1]+this.center[1],v[2]+this.center[2]]; - } - - T(v) { - let x=v[0]; - let Y=v[1]; - let z=v[2]; - let X=x*this.ct+z*this.st; - return [X*this.cp-Y*this.sp+this.center[0], - X*this.sp+Y*this.cp+this.center[1], - -x*this.st+z*this.ct+this.center[2]]; - }; -} - -function Tcorners(T,m,M) { - let v=[T(m),T([m[0],m[1],M[2]]),T([m[0],M[1],m[2]]), - T([m[0],M[1],M[2]]),T([M[0],m[1],m[2]]), - T([M[0],m[1],M[2]]),T([M[0],M[1],m[2]]),T(M)]; - return [minbound(v),maxbound(v)]; -} - -// draw a sphere of radius r about center -// (or optionally a hemisphere symmetric about direction dir) -function sphere(center,r,CenterIndex,MaterialIndex,dir) -{ - let b=0.524670512339254; - let c=0.595936986722291; - let d=0.954967051233925; - let e=0.0820155480083437; - let f=0.996685028842544; - let g=0.0549670512339254; - let h=0.998880711874577; - let i=0.0405017186586849; - - let octant=[[ - [1,0,0], - [1,0,b], - [c,0,d], - [e,0,f], - - [1,a,0], - [1,a,b], - [c,a*c,d], - [e,a*e,f], - - [a,1,0], - [a,1,b], - [a*c,c,d], - [a*e,e,f], - - [0,1,0], - [0,1,b], - [0,c,d], - [0,e,f] - ],[ - [e,0,f], - [e,a*e,f], - [g,0,h], - [a*e,e,f], - [i,i,1], - [0.05*a,0,1], - [0,e,f], - [0,g,h], - [0,0.05*a,1], - [0,0,1] - ]]; - - let rx,ry,rz; - let A=new Align(center,dir); - let s,t,z; - - if(dir) { - s=1; - z=0; - t=A.T.bind(A); - } else { - s=-1; - z=-r; - t=A.T0.bind(A); - } - - function T(V) { - let p=Array(V.length); - for(let i=0; i < V.length; ++i) { - let v=V[i]; - p[i]=t([rx*v[0],ry*v[1],rz*v[2]]); - } - return p; - } - - let v=Tcorners(t,[-r,-r,z],[r,r,r]); - let Min=v[0], Max=v[1]; - for(let i=-1; i <= 1; i += 2) { - rx=i*r; - for(let j=-1; j <= 1; j += 2) { - ry=j*r; - for(let k=s; k <= 1; k += 2) { - rz=k*r; - for(let m=0; m < 2; ++m) - P.push(new BezierPatch(T(octant[m]),CenterIndex,MaterialIndex, - Min,Max)); - } - } - } -} - -let a=4/3*(Math.sqrt(2)-1); - -// draw a disk of radius r aligned in direction dir -function disk(center,r,CenterIndex,MaterialIndex,dir) -{ - let b=1-2*a/3; - - let unitdisk=[ - [1,0,0], - [1,-a,0], - [a,-1,0], - [0,-1,0], - - [1,a,0], - [b,0,0], - [0,-b,0], - [-a,-1,0], - - [a,1,0], - [0,b,0], - [-b,0,0], - [-1,-a,0], - - [0,1,0], - [-a,1,0], - [-1,a,0], - [-1,0,0] - ]; - - let A=new Align(center,dir); - - function T(V) { - let p=Array(V.length); - for(let i=0; i < V.length; ++i) { - let v=V[i]; - p[i]=A.T([r*v[0],r*v[1],0]); - } - return p; - } - - let v=Tcorners(A.T.bind(A),[-r,-r,0],[r,r,0]); - P.push(new BezierPatch(T(unitdisk),CenterIndex,MaterialIndex,v[0],v[1])); -} - -// draw a cylinder with circular base of radius r about center and height h -// aligned in direction dir -function cylinder(center,r,h,CenterIndex,MaterialIndex,dir,core) -{ - let unitcylinder=[ - [1,0,0], - [1,0,1/3], - [1,0,2/3], - [1,0,1], - - [1,a,0], - [1,a,1/3], - [1,a,2/3], - [1,a,1], - - [a,1,0], - [a,1,1/3], - [a,1,2/3], - [a,1,1], - - [0,1,0], - [0,1,1/3], - [0,1,2/3], - [0,1,1] - ]; - - let rx,ry,rz; - let A=new Align(center,dir); - - function T(V) { - let p=Array(V.length); - for(let i=0; i < V.length; ++i) { - let v=V[i]; - p[i]=A.T([rx*v[0],ry*v[1],h*v[2]]); - } - return p; - } - - let v=Tcorners(A.T.bind(A),[-r,-r,0],[r,r,h]); - let Min=v[0], Max=v[1]; - - for(let i=-1; i <= 1; i += 2) { - rx=i*r; - for(let j=-1; j <= 1; j += 2) { - ry=j*r; - P.push(new BezierPatch(T(unitcylinder),CenterIndex,MaterialIndex, - Min,Max)); - } - } - - if(core) { - let Center=A.T([0,0,h]); - P.push(new BezierCurve([center,Center],CenterIndex,MaterialIndex, - center,Center)); - } -} - -function rmf(z0,c0,c1,z1,t) -{ - class Rmf { - constructor(p,r,t) { - this.p=p; - this.r=r; - this.t=t; - this.s=cross(t,r); - } - } - - // Return a unit vector perpendicular to a given unit vector v. - function perp(v) - { - let u=cross(v,[0,1,0]); - let norm=Number.EPSILON*abs2(v); - if(abs2(u) > norm) return unit(u); - u=cross(v,[0,0,1]); - return (abs2(u) > norm) ? unit(u) : [1,0,0]; - } - - let norm=Number.EPSILON*Math.max(abs2(z0),abs2(c0),abs2(c1), - abs2(z1)); - -// Special case of dir for t in (0,1]. - function dir(t) { - if(t == 1) { - let dir=[z1[0]-c1[0], - z1[1]-c1[1], - z1[2]-c1[2]]; - if(abs2(dir) > norm) return unit(dir); - dir=[2*c1[0]-c0[0]-z1[0], - 2*c1[1]-c0[1]-z1[1], - 2*c1[2]-c0[2]-z1[2]]; - if(abs2(dir) > norm) return unit(dir); - return [z1[0]-z0[0]+3*(c0[0]-c1[0]), - z1[1]-z0[1]+3*(c0[1]-c1[1]), - z1[2]-z0[2]+3*(c0[2]-c1[2])]; - } - let a=[z1[0]-z0[0]+3*(c0[0]-c1[0]), - z1[1]-z0[1]+3*(c0[1]-c1[1]), - z1[2]-z0[2]+3*(c0[2]-c1[2])]; - let b=[2*(z0[0]+c1[0])-4*c0[0], - 2*(z0[1]+c1[1])-4*c0[1], - 2*(z0[2]+c1[2])-4*c0[2]]; - let c=[c0[0]-z0[0],c0[1]-z0[1],c0[2]-z0[2]]; - let t2=t*t; - let dir=[a[0]*t2+b[0]*t+c[0], - a[1]*t2+b[1]*t+c[1], - a[2]*t2+b[2]*t+c[2]]; - if(abs2(dir) > norm) return unit(dir); - t2=2*t; - dir=[a[0]*t2+b[0], - a[1]*t2+b[1], - a[2]*t2+b[2]]; - if(abs2(dir) > norm) return unit(dir); - return unit(a); - } - - let R=Array(t.length); - let T=[c0[0]-z0[0], - c0[1]-z0[1], - c0[2]-z0[2]]; - if(abs2(T) < norm) { - T=[z0[0]-2*c0[0]+c1[0], - z0[1]-2*c0[1]+c1[1], - z0[2]-2*c0[2]+c1[2]]; - if(abs2(T) < norm) - T=[z1[0]-z0[0]+3*(c0[0]-c1[0]), - z1[1]-z0[1]+3*(c0[1]-c1[1]), - z1[2]-z0[2]+3*(c0[2]-c1[2])]; - } - T=unit(T); - let Tp=perp(T); - R[0]=new Rmf(z0,Tp,T); - for(let i=1; i < t.length; ++i) { - let Ri=R[i-1]; - let s=t[i]; - let onemt=1-s; - let onemt2=onemt*onemt; - let onemt3=onemt2*onemt; - let s3=3*s; - onemt2 *= s3; - onemt *= s3*s; - let t3=s*s*s; - let p=[ - onemt3*z0[0]+onemt2*c0[0]+onemt*c1[0]+t3*z1[0], - onemt3*z0[1]+onemt2*c0[1]+onemt*c1[1]+t3*z1[1], - onemt3*z0[2]+onemt2*c0[2]+onemt*c1[2]+t3*z1[2]]; - let v1=[p[0]-Ri.p[0],p[1]-Ri.p[1],p[2]-Ri.p[2]]; - if(v1[0] != 0 || v1[1] != 0 || v1[2] != 0) { - let r=Ri.r; - let u1=unit(v1); - let ti=Ri.t; - let dotu1ti=dot(u1,ti) - let tp=[ti[0]-2*dotu1ti*u1[0], - ti[1]-2*dotu1ti*u1[1], - ti[2]-2*dotu1ti*u1[2]]; - ti=dir(s); - let dotu1r2=2*dot(u1,r); - let rp=[r[0]-dotu1r2*u1[0],r[1]-dotu1r2*u1[1],r[2]-dotu1r2*u1[2]]; - let u2=unit([ti[0]-tp[0],ti[1]-tp[1],ti[2]-tp[2]]); - let dotu2rp2=2*dot(u2,rp); - rp=[rp[0]-dotu2rp2*u2[0],rp[1]-dotu2rp2*u2[1],rp[2]-dotu2rp2*u2[2]]; - R[i]=new Rmf(p,unit(rp),unit(ti)); - } else - R[i]=R[i-1]; - } - return R; -} - -// draw a tube of width w using control points v -function tube(v,w,CenterIndex,MaterialIndex,Min,Max,core) -{ - let Rmf=rmf(v[0],v[1],v[2],v[3],[0,1/3,2/3,1]); - - let aw=a*w; - let arc=[[w,0],[w,aw],[aw,w],[0,w]]; - - function f(a,b,c,d) { - let s=Array(16); - for(let i=0; i < 4; ++i) { - let R=Rmf[i]; - - let R0=R.r[0], R1=R.s[0]; - let T0=R0*a+R1*b; - let T1=R0*c+R1*d; - - R0=R.r[1]; R1=R.s[1]; - let T4=R0*a+R1*b; - let T5=R0*c+R1*d; - - R0=R.r[2]; R1=R.s[2]; - let T8=R0*a+R1*b; - let T9=R0*c+R1*d; - - let w=v[i]; - let w0=w[0]; w1=w[1]; w2=w[2]; - for(let j=0; j < 4; ++j) { - let u=arc[j]; - let x=u[0], y=u[1]; - s[4*i+j]=[T0*x+T1*y+w0, - T4*x+T5*y+w1, - T8*x+T9*y+w2]; - } - } - P.push(new BezierPatch(s,CenterIndex,MaterialIndex,Min,Max)); - } - - f(1,0,0,1); - f(0,-1,1,0); - f(-1,0,0,-1); - f(0,1,-1,0); - - if(core) - P.push(new BezierCurve(v,CenterIndex,MaterialIndex,Min,Max)); -} - -function webGLStart() -{ - canvas=document.getElementById("Asymptote"); - embedded=window.top.document != document; - - initGL(); - - gl.enable(gl.BLEND); - gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA); - gl.enable(gl.DEPTH_TEST); - gl.enable(gl.SCISSOR_TEST); - - canvas.onmousedown=handleMouseDown; - document.onmouseup=handleMouseUpOrTouchEnd; - document.onmousemove=handleMouseMove; - canvas.onkeydown=handleKey; - - if(!embedded) - enableZoom(); - canvas.addEventListener("touchstart",handleTouchStart,false); - canvas.addEventListener("touchend",handleMouseUpOrTouchEnd,false); - canvas.addEventListener("touchcancel",handleMouseUpOrTouchEnd,false); - canvas.addEventListener("touchleave",handleMouseUpOrTouchEnd,false); - canvas.addEventListener("touchmove",handleTouchMove,false); - document.addEventListener("keydown",handleKey,false); - - canvasWidth0=canvasWidth; - canvasHeight0=canvasHeight; - - mat4.identity(rotMat); - - if(window.innerWidth != 0 && window.innerHeight != 0) - resize(); - - window.addEventListener("resize",resize,false); -} diff --git a/Build/source/utils/asymptote/webgl/license b/Build/source/utils/asymptote/webgl/license deleted file mode 100644 index f1169e9d3fe..00000000000 --- a/Build/source/utils/asymptote/webgl/license +++ /dev/null @@ -1,18 +0,0 @@ -/*@license - AsyGL: Render Bezier patches and triangles via subdivision with WebGL. - Copyright 2019-2020: John C. Bowman and Supakorn "Jamie" Rassameemasmuang - University of Alberta - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with this program. If not, see <http://www.gnu.org/licenses/>. -*/ diff --git a/Build/source/utils/asymptote/webgl/vertex.glsl b/Build/source/utils/asymptote/webgl/vertex.glsl deleted file mode 100644 index bf55fc0042e..00000000000 --- a/Build/source/utils/asymptote/webgl/vertex.glsl +++ /dev/null @@ -1,80 +0,0 @@ -attribute vec3 position; -#ifdef WIDTH -attribute float width; -#endif -#ifdef NORMAL -attribute vec3 normal; -#endif -attribute float materialIndex; -#ifdef COLOR -attribute vec4 color; -#endif - -uniform mat3 normMat; -uniform mat4 viewMat; -uniform mat4 projViewMat; - -#ifdef NORMAL -#ifndef ORTHOGRAPHIC -varying vec3 ViewPosition; -#endif -varying vec3 Normal; -#endif -varying vec4 diffuse; -varying vec3 specular; -varying float roughness,metallic,fresnel0; -varying vec4 emissive; - -struct Material { - vec4 diffuse,emissive,specular; - vec4 parameters; -}; - -uniform Material Materials[Nmaterials]; - -void main(void) -{ - vec4 v=vec4(position,1.0); - gl_Position=projViewMat*v; -#ifdef NORMAL -#ifndef ORTHOGRAPHIC - ViewPosition=(viewMat*v).xyz; -#endif - Normal=normalize(normal*normMat); - - Material m; -#ifdef TRANSPARENT - m=Materials[int(abs(materialIndex))-1]; - emissive=m.emissive; - if(materialIndex >= 0.0) { - diffuse=m.diffuse; - } else { - diffuse=color; -#if nlights == 0 - emissive += color; -#endif - } -#else - m=Materials[int(materialIndex)]; - emissive=m.emissive; -#ifdef COLOR - diffuse=color; -#if nlights == 0 - emissive += color; -#endif -#else - diffuse=m.diffuse; -#endif -#endif - specular=m.specular.rgb; - vec4 parameters=m.parameters; - roughness=1.0-parameters[0]; - metallic=parameters[1]; - fresnel0=parameters[2]; -#else - emissive=Materials[int(materialIndex)].emissive; -#endif -#ifdef WIDTH - gl_PointSize=width; -#endif -} |