summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/webgl
diff options
context:
space:
mode:
authorDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
committerDenis Bitouzé <dbitouze@wanadoo.fr>2021-02-25 18:23:07 +0000
commitc6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch)
tree1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/utils/asymptote/webgl
parent07ee7222e389b0777456b427a55c22d0e6ffd267 (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.glsl95
-rw-r--r--Build/source/utils/asymptote/webgl/gl.js3135
-rw-r--r--Build/source/utils/asymptote/webgl/license18
-rw-r--r--Build/source/utils/asymptote/webgl/vertex.glsl80
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
-}