A Sierpinski Gasket With Triangles

Animate

Depth

The HTML file:

<html>
<head>

<script id="vertex-shader" type="x-shader/x-vertex" >
attribute vec4 vStartPosition;
attribute vec4 vEndPosition;
attribute vec4 vColor;
uniform float percent;

varying vec4 f_Color;

void main() {

    float fixedPct;

    fixedPct = clamp(percent, 0.0, 1.0);
    gl_Position = mix(vStartPosition, vEndPosition, fixedPct);
    f_Color = vColor;
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
precision mediump float;
varying vec4 f_Color;

void main() {
    gl_FragColor = f_Color;
}
</script>

    <script type="text/javascript" src="../Common/webgl-utils.js"></script>
    <script type="text/javascript" src="../Common/initShaders.js"></script>
    <script type="text/javascript" src="../Common/MV.js"></script>
    <script type="text/javascript" src="AniSepTriCanvas.js"></script>
    <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js"></script>

<style>
input {
    text-align: right;
}
</style>

</head>

<body>
     <h1>A Sierpinski Gasket With Triangles</h1>
<script>
    var WIDTH = 500;
    var HEIGHT = 500;
    var canvas = new Canvas(WIDTH, HEIGHT);

window.addEventListener("load", function(event){
    document.getElementById('DepthBox').value = canvas.GetDepth();
});

</script>

<p>

<button type="button" onclick=" canvas.AnimationStep()">Animate 1</button>
<p>
Animate
<label class="switch">
  <input type="checkbox" onclick="canvas.ChangeAnimation()">
</label>
<p>
Depth
<input
      type="text"
      name="Depth"
      maxLength = "5"
      size = "5"
      value = "" 
      id="DepthBox", onchange="canvas.ChangeDepth(this.value)">
<p>
</body>
The Javascript File
function MakeCanvas(width, height, locID) {

    if (width == undefined || width < 0) {
       width = 300;
    }

    if (height == undefined || height < 0) {
       height = 300;
    }

    var canvas = document.createElement('canvas')
        canvas.height = height;
        canvas.width = width;

    if(locID == undefined) {
        document.body.appendChild(canvas);
    } else {
        div = document.getElementById(locID);
        if (null == div) {
            document.body.appendChild(canvas);
        } else {
            div.appendChild(canvas);
        }
    }

    document.body.appendChild(canvas);
    return canvas;
}

function Canvas(width, height, locID) {
    var canvas = MakeCanvas(width, height, locID);

    var gl = WebGLUtils.setupWebGL(canvas);
    if (!gl) {
        alert ("WebGL isn't available");
    }

    this.gl = gl;

    gl.viewport(0,0, width, height);

    program = initShaders(gl, "vertex-shader","fragment-shader");
    gl.useProgram(program);

    // somewhat new code, two vertex buffers.
    this.vStartBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vStartBuffer);

    var vPosition = gl.getAttribLocation(program, "vStartPosition");
    gl.vertexAttribPointer(vPosition,2,gl.FLOAT, false,0,0);
    gl.enableVertexAttribArray(vPosition);

    this.vEndBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.vEndBuffer);

    vPosition = gl.getAttribLocation(program, "vEndPosition");
    gl.vertexAttribPointer(vPosition,2,gl.FLOAT, false,0,0);
    gl.enableVertexAttribArray(vPosition);

    // a buffer for the colors
    this.cBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, this.cBuffer);

    var colorAttribute = gl.getAttribLocation(program, "vColor");
    gl.vertexAttribPointer(colorAttribute,3,gl.FLOAT, false,0,0);
    gl.enableVertexAttribArray(colorAttribute);


    // this is new.  Get the location to send pct
    this.pctLoc = gl.getUniformLocation(program, "percent");
    this.pct = 0;
    this.pctStep = 0.01;

    gl.uniform1f(this.pctLoc, this.pct);
    

    this.maxDepth = 1;
    this.Init();

    return this;
}

Canvas.prototype = {

    Init: function() {

        this.animationState = false;
        this.gl.clearColor(1.0, 1.0, 1.0, 1.0);
	this.RestartList();
    },

    RestartList: function() {
        this.currentDepth  = 0;

        var p1 = vec2(-0.8, -0.8);
        var p2 = vec2(0, .8);
        var p3 = vec2(0.8, -0.8);
       
	this.verts= [p1, p2, p3] ;

	var c1 = vec3(Math.random(), Math.random(),Math.random())
	var c2 = vec3(Math.random(), Math.random(),Math.random())
	var c3 = vec3(Math.random(), Math.random(),Math.random())

	this.colors = [c1, c2, c3];

	this.MakePoints();
	this.MakeOld();

        this.UpdateBuffers();
        this.Redisplay();
    },

    UpdateBuffers: function() {
        gl = this.gl;
        // change the vertex data
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vStartBuffer);
	gl.bufferData(gl.ARRAY_BUFFER,flatten(this.startV),gl.DYNAMIC_DRAW);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vEndBuffer);
	gl.bufferData(gl.ARRAY_BUFFER,flatten(this.verts),gl.DYNAMIC_DRAW);

	// change the color data
        gl.bindBuffer(this.gl.ARRAY_BUFFER, this.cBuffer);
	gl.bufferData(gl.ARRAY_BUFFER,flatten(this.colors),gl.DYNAMIC_DRAW);
    },

    GetDepth: function() {
       return this.maxDepth;
    },

    ChangeDepth: function(newDepth) {
        var depth = parseInt(newDepth);

	if (depth < 1 ) {
	   alert("depth must be positive");
	   return;
	} 

	if (depth  > 11) {
	   alert ("Depth has a max value of 11");
	   depth = 10;
	}

	if (depth < this.maxDepth) {
	    this.maxDepth = depth;
	    this.RestartList(); 
	} else {
	    this.maxDepth = depth;
	    this.MakePoints();
	    this.MakeOld();
            var gl = this.gl;
            this.UpdateBuffers();
	}
        this.Redisplay();
    },

    Interp: function(a,b,s) {
        return a*(1-s) + b*s;
    },

    HalfPoint: function(p1,p2) {
	var x = this.Interp(p1[0],p2[0],.5);
	var y = this.Interp(p1[1],p2[1],.5);
	return vec2(x,y);
    },

    AddTri: function(p1, p2, p3, vert, c1, colors) {
        vert.push(p1);
	colors.push(c1);

        vert.push(p2);
	var c2 = vec3(Math.random(), Math.random(),Math.random())
	colors.push(c2);

        vert.push(p3);
	var c3 = vec3(Math.random(), Math.random(),Math.random())
	colors.push(c3);
    },

    MakePoints: function(){
        var newVertex = [];
	var newColors = [];
	var a,b,c;
	var p1, p2, p3;

	if (this.currentDepth < this.maxDepth) {
	   this.currentDepth++;

	   for(i =0; i < this.verts.length;i+=3) {
	       a = this.verts[i];
	       b = this.verts[i+1]
	       c = this.verts[i+2];

	       ap = this.HalfPoint(a,b,.5);
	       bp = this.HalfPoint(b,c,.5);
	       cp = this.HalfPoint(c,a,.5);

               this.AddTri(a,ap,cp, newVertex, this.colors[i], newColors);
               this.AddTri(b,bp,ap, newVertex, this.colors[i+1], newColors);
               this.AddTri(c,cp,bp, newVertex, this.colors[i+2], newColors);
	    }

	    this.verts = newVertex;
	    this.colors = newColors;

	    this.MakePoints();
	}


	return;
    },

    MakeOld: function() {
         
	this.startV = [];
	var mid;
	var tris = this.verts.length/3;

	for(var i =0; i < this.verts.length; i+= 9) {
	   this.startV.push(this.verts[i]);
	   this.startV.push(this.verts[i+2]);
	   this.startV.push(this.verts[i+1]);

	   this.startV.push(this.verts[i+3]);
	   this.startV.push(this.verts[i+5]);
	   this.startV.push(this.verts[i+4]);

	   this.startV.push(this.verts[i+6]);
	   this.startV.push(this.verts[i+8]);
	   this.startV.push(this.verts[i+7]); 
	}

	return;
    },

    Midpoint: function(p1, p2, p3) {
        var x = (p1[0]+p2[0]+p3[0])/3;
        var y = (p1[1]+p2[1]+p3[1])/3;
	return vec2(x,y);
    },

    ChangeAnimation: function() {
       this.animationState = !this.animationState;
       if (this.animationState) {
          setTimeout(canvas.FakeAnimationStep,20,this);
       }
    },

    IsAnimating: function() {
        return this.animationState;
    },

    FakeAnimationStep: function(me) {
        me.AnimationStep();
    },


    AnimationStep: function() {
        this.pct += this.pctStep;
	if (this.pct >= 1.0) {
	   this.pct = 1.0;
	   this.pctStep *= -1;
	}
	if (this.pct <= 0.0) {
	   this.pct = 0.0;
	   this.pctStep *= -1;
	}

        if (this.animationState) {
             setTimeout(canvas.FakeAnimationStep,20,this);
	}

        this.gl.uniform1f(this.pctLoc, this.pct);
	this.Redisplay();
    },

    Redisplay: function() {
        this.gl.clear(this.gl.COLOR_BUFFER_BIT);

	this.gl.drawArrays(this.gl.TRIANGLES, 0, this.verts.length);
        return;
    }
};