summaryrefslogtreecommitdiff
path: root/graphics/asymptote/webgl/gl.js
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/asymptote/webgl/gl.js')
-rw-r--r--graphics/asymptote/webgl/gl.js145
1 files changed, 89 insertions, 56 deletions
diff --git a/graphics/asymptote/webgl/gl.js b/graphics/asymptote/webgl/gl.js
index e2053f3161..a7cf6a5862 100644
--- a/graphics/asymptote/webgl/gl.js
+++ b/graphics/asymptote/webgl/gl.js
@@ -79,11 +79,6 @@ let viewParam = {
zmin:0,zmax:0
};
-let positionBuffer;
-let materialBuffer;
-let colorBuffer;
-let indexBuffer;
-
let remesh=true;
let wireframe=0;
let mouseDownOrTouchActive=false;
@@ -158,15 +153,6 @@ function deleteShaders()
gl.deleteProgram(pixelShader);
}
-// Create buffers for the patch and its subdivisions.
-function setBuffers()
-{
- positionBuffer=gl.createBuffer();
- materialBuffer=gl.createBuffer();
- colorBuffer=gl.createBuffer();
- indexBuffer=gl.createBuffer();
-}
-
function noGL() {
if (!gl)
alert("Could not initialize WebGL");
@@ -241,7 +227,6 @@ function initGL()
initShaders();
}
- setBuffers();
indexExt=gl.getExtension("OES_element_index_uint");
TRIANGLES=gl.TRIANGLES;
@@ -280,6 +265,20 @@ function getShader(gl,shaderScript,type,options=[])
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;
@@ -288,9 +287,9 @@ function drawBuffer(data,shader,indices=data.indices)
setUniforms(data,shader);
- gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);
- gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(data.vertices),
- gl.STATIC_DRAW);
+ 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)
@@ -298,22 +297,22 @@ function drawBuffer(data,shader,indices=data.indices)
else if(pixel)
gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,false,16,12);
- gl.bindBuffer(gl.ARRAY_BUFFER,materialBuffer);
- gl.bufferData(gl.ARRAY_BUFFER,new Int16Array(data.materialIndices),
- gl.STATIC_DRAW);
+ data.materialsBuffer=registerBuffer(new Int16Array(data.materialIndices),
+ data.materialsBuffer,copy);
gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,false,2,0);
+
if(shader == colorShader || shader == transparentShader) {
- gl.bindBuffer(gl.ARRAY_BUFFER,colorBuffer);
- gl.bufferData(gl.ARRAY_BUFFER,new Uint8Array(data.colors),
- gl.STATIC_DRAW);
+ data.colorsBuffer=registerBuffer(new Uint8Array(data.colors),
+ data.colorsBuffer,copy);
gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,true,0,0);
}
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);
- gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
- indexExt ? new Uint32Array(indices) :
- new Uint16Array(indices),gl.STATIC_DRAW);
+ 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,
@@ -325,15 +324,24 @@ 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=[];
}
@@ -422,7 +430,7 @@ function append(a,b)
a[n+i]=b[i];
}
-// efficiently append array b onto array a
+// efficiently append array b onto array a with offset
function appendOffset(a,b,o)
{
let n=a.length;
@@ -488,8 +496,10 @@ class Geometry {
setMaterial(data,draw) {
if(data.materialTable[this.MaterialIndex] == null) {
- if(data.materials.length >= Nmaterials)
+ if(data.materials.length >= Nmaterials) {
+ data.partial=true;
draw();
+ }
data.materialTable[this.MaterialIndex]=data.materials.length;
data.materials.push(Materials[this.MaterialIndex]);
}
@@ -510,6 +520,7 @@ class Geometry {
if(this.offscreen(v)) { // Fully offscreen
this.data.clear();
+ this.notRendered();
return;
}
@@ -517,8 +528,7 @@ class Geometry {
let P;
if(this.CenterIndex == 0) {
- if(!remesh && this.Onscreen) {
- // Fully onscreen; no need to re-render
+ if(!remesh && this.Onscreen) { // Fully onscreen; no need to re-render
this.append();
return;
}
@@ -537,6 +547,7 @@ class Geometry {
this.Epsilon=FillFactor*res;
this.data.clear();
+ this.notRendered();
this.Onscreen=true;
this.process(P);
}
@@ -765,6 +776,15 @@ class BezierPatch extends Geometry {
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
@@ -1683,6 +1703,10 @@ class BezierCurve extends Geometry {
material1Data.append(this.data);
}
+ notRendered() {
+ material1Data.rendered=false;
+ }
+
Render(p,I0,I1) {
let p0=p[0];
let p1=p[1];
@@ -1747,6 +1771,10 @@ class Pixel extends Geometry {
append() {
material0Data.append(this.data);
}
+
+ notRendered() {
+ material0Data.rendered=false;
+ }
}
class Triangles extends Geometry {
@@ -1833,6 +1861,14 @@ class Triangles extends Geometry {
else
triangleData.append(this.data);
}
+
+ notRendered() {
+ if(this.transparent)
+ transparentData.rendered=false;
+ else
+ triangleData.rendered=false;
+ }
+
}
function home()
@@ -2435,6 +2471,7 @@ function drawColor()
function drawTriangle()
{
drawBuffer(triangleData,transparentShader);
+ triangleData.rendered=false; // Force copying of sorted triangles to GPU.
triangleData.clear();
}
@@ -2479,6 +2516,8 @@ function drawTransparent()
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();
@@ -2497,8 +2536,8 @@ function drawBuffers()
function draw()
{
if(embedded) {
- offscreen.width=canvas.width;
- offscreen.height=canvas.height;
+ offscreen.width=canvasWidth;
+ offscreen.height=canvasHeight;
setViewport();
}
@@ -2511,7 +2550,7 @@ function draw()
drawBuffers();
if(embedded) {
- context.clearRect(0,0,canvas.width,canvas.height);
+ context.clearRect(0,0,canvasWidth,canvasHeight);
context.drawImage(offscreen,0,0);
}
@@ -2585,21 +2624,20 @@ function setViewport()
{
gl.viewportWidth=canvasWidth;
gl.viewportHeight=canvasHeight;
- gl.viewport(0,0,gl.viewportWidth,gl.viewportHeight);
- gl.scissor(0,0,gl.viewportWidth,gl.viewportHeight);
+ gl.viewport(0.5*(canvas.width-canvasWidth),0.5*(canvas.height-canvasHeight),
+ canvasWidth,canvasHeight);
+ gl.scissor(0,0,canvas.width,canvas.height);
}
function setCanvas()
{
- canvas.width=canvasWidth;
- canvas.height=canvasHeight;
if(embedded) {
- offscreen.width=canvasWidth;
- offscreen.height=canvasHeight;
+ canvas.width=offscreen.width=canvasWidth;
+ canvas.height=offscreen.height=canvasHeight;
}
size2=Math.hypot(canvasWidth,canvasHeight);
- halfCanvasWidth=0.5*canvasWidth;
- halfCanvasHeight=0.5*canvasHeight;
+ halfCanvasWidth=0.5*canvas.width;
+ halfCanvasHeight=0.5*canvas.height;
}
function setsize(w,h)
@@ -2644,22 +2682,17 @@ function webGLInit()
canvasWidth *= window.devicePixelRatio;
canvasHeight *= window.devicePixelRatio;
} else {
- canvas.width=Math.max(window.innerWidth-windowTrim,windowTrim);
- canvas.height=Math.max(window.innerHeight-windowTrim,windowTrim);
-
let Aspect=canvasWidth/canvasHeight;
- if(canvas.width > canvas.height*Aspect)
- canvas.width=Math.min(canvas.height*Aspect,canvas.width);
- else
- canvas.height=Math.min(canvas.width/Aspect,canvas.height);
-
- if(canvas.width > 0)
- canvasWidth=canvas.width;
+ canvasWidth=Math.max(window.innerWidth-windowTrim,windowTrim);
+ canvasHeight=Math.max(window.innerHeight-windowTrim,windowTrim);
- if(canvas.height > 0)
- canvasHeight=canvas.height;
+ if(!orthographic && canvasWidth < canvasHeight*Aspect)
+ Zoom0 *= canvasWidth/(canvasHeight*Aspect);
}
+ canvas.width=canvasWidth;
+ canvas.height=canvasHeight;
+
setCanvas();
ArcballFactor=1+8*Math.hypot(viewportmargin[0],viewportmargin[1])/size2;