Care for Tea?

BACK FRONT FRONT_AND_BACK none
Press x,y,z to rotate.

The HTML file:

<html>
<head>

<script id="vertex-shader" type="x-shader/x-vertex" >
attribute vec4 vPosition;
attribute vec3 vBC;
attribute vec4 vColor;

uniform mat4 Transform;
uniform float vFillType;

varying vec3 f_BC;
varying vec4 f_Color;
varying float f_FillType;

void main() {

    gl_Position = Transform * vPosition;
    f_BC = vBC;
    f_Color = vec4(1.0, 0.0, 0.0, 1.0);
    f_FillType = vFillType;
}
</script>

<script id="fragment-shader" type="x-shader/x-fragment">
#extension GL_OES_standard_derivatives : enable

precision mediump float;
varying vec4 f_Color;
varying vec3 f_BC;
varying float f_FillType;

    float edgeFactor(){
        vec3 d = fwidth(f_BC);
        vec3 a3 = smoothstep(vec3(0.0), d*1.5, f_BC);
        return min(min(a3.x, a3.y), a3.z);
    }

    void main(){

        if (f_FillType >= 1.0) {
             // alpha by edge
             if(gl_FrontFacing){
                 gl_FragColor = vec4(0,0.0,0.0, (1.0-edgeFactor())*0.95);
             } else {
                 gl_FragColor = vec4(0.0, 0.0, 0.0, (1.0-edgeFactor())*0.7);
             }
	     
	 } else {
	     if (gl_FrontFacing) {
	  	gl_FragColor = f_Color;
	     } else {
	  	gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
	     }
	 }
}
</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="../offs/oldTeapot.js"></script>
<!-- <script type="text/javascript" src="../offs/oldLizard.js"></script>  --!>
<!-- <script type="text/javascript" src="../offs/oldTank.js"></script>   --!>
<!-- <script type="text/javascript" src="../offs/oldDragon.js"></script> --!>
<script type="text/javascript" src="offTeapot.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>Care for Tea?</h1>
<script>
    var canvas = new Canvas(500, 500);
</script>

<p>

<button type="button" onclick="canvas.FlipDir(),canvas.Redisplay()">
   Triangle Dir
</button>

<button type="button" onclick="canvas.ChangeShader(),canvas.Redisplay()">
   Change Shader
</button>

 <form >
      <input type="radio" name="face" value="0" checked
             onchange="canvas.ChangeFace(this.value), canvas.Redisplay()">
             BACK 
     </input>
      <input type="radio" name="face" value="1" 
             onchange="canvas.ChangeFace(this.value), canvas.Redisplay()">
             FRONT 
     </input>
      <input type="radio" name="face" value="2" 
             onchange="canvas.ChangeFace(this.value), canvas.Redisplay()">
             FRONT_AND_BACK 
     </input>
      <input type="radio" name="face" value="3" 
             onchange="canvas.ChangeFace(this.value), canvas.Redisplay()">
             none 
     </input>
   </form>
Press x,y,z to rotate.


</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.tabIndex = 0;
        canvas.height = height;
        canvas.width = width;
	canvas.style.border = "1px solid #0000FF";

    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 InitGL(canvas) {
    var gl =  WebGLUtils.setupWebGL(canvas,'OES_standard_derivatives');
    if (!gl) {
        alert ("WebGL isn't available");
    }

    // required to turn on fwidth and such.
    gl.getExtension('OES_standard_derivatives');
    return gl;
}

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

    var gl = InitGL(canvas);
    this.gl = gl;

    var tmpCanvas = this;
    this.x = canvas.offsetLeft;
    this.y = canvas.offsetTop;

    canvas.addEventListener("keypress",
         function(evnt) {
            tmpCanvas.KeyFunc(tmpCanvas, evnt);
         }
    );

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

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

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

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

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

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

    this.shaderLoc = gl.getUniformLocation(program, "vFillType");
    gl.uniform1f(this.shaderLoc, 0.0);

    this.transformLoc = gl.getUniformLocation(program, "Transform");

    this.Init();

    return this;
}

Canvas.prototype = {

    Init: function() {
        this.gl.clearColor(1.0, 1.0, 1.0, 1.0);

        this.gl.enable(this.gl.BLEND);
	this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);

        this.gl.enable(this.gl.DEPTH_TEST);
	this.gl.depthFunc(this.gl.LESS);
	this.gl.depthMask(this.gl.TRUE);

	this.RestartList();

        this.shaderChoice = false;
        this.gl.uniform1f(this.shaderLoc, 0.0);

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

    Reset: function() {
	this.xr = 0;
	this.yr = 0;
	this.zr = 0;

         // make these switchable


        this.gl.enable(this.gl.CULL_FACE);
        this.direction = this.gl.CCW;
        this.gl.frontFace(this.direction);
	this.gl.cullFace(this.gl.BACK);
    },

    FlipDir: function() {
        if (this.direction == this.gl.CCW) {
	    this.direction = this.gl.CW;
	} else {
	    this.direction = this.gl.CCW;
	}
        this.gl.frontFace(this.direction);
    },

    RestartList: function() {

	this.verts= teapotTriangles ;
	this.bc = teapotBC 

        this.UpdateBuffers();
    },

    UpdateBuffers: function() {
        var gl = this.gl;

        // change the vertex data
        gl.bindBuffer(gl.ARRAY_BUFFER, this.vBC);
	gl.bufferData(gl.ARRAY_BUFFER,flatten(this.bc),gl.STATIC_DRAW);

        gl.bindBuffer(gl.ARRAY_BUFFER, this.vPos);
	gl.bufferData(gl.ARRAY_BUFFER,flatten(this.verts),gl.STATIC_DRAW);

    },

    ChangeShader: function() { 
        this.shaderChoice = ! this.shaderChoice;
	var shader = 0.0;

	if (this.shaderChoice) {
	    shader = 1.0
	}
        this.gl.uniform1f(this.shaderLoc, shader);
    },

    ChangeFace: function(value) {
       switch(value) {
          default:
          case '0':
              this.gl.enable(this.gl.CULL_FACE);
	      this.gl.cullFace(this.gl.BACK);
	      break;
	  case '1':
              this.gl.enable(this.gl.CULL_FACE);
	      this.gl.cullFace(this.gl.FRONT);
	      break;
	  case '2':
              this.gl.enable(this.gl.CULL_FACE);
	      this.gl.cullFace(this.gl.FRONT_AND_BACK);
	      break;
	  case '3':
              this.gl.disable(this.gl.CULL_FACE);
	      break;
       }
    },

    KeyFunc: function(me, evnt) {
       switch(evnt.key) {
           case 'X':  me.xr += -5; break;
	   case 'Y':  me.yr += -5; break;
	   case 'Z':  me.zr += -5; break;
           case 'x':  me.xr += 5; break;
	   case 'y':  me.yr += 5; break;
	   case 'z':  me.zr += 5; break;
	   case 'r':  me.Reset(); break;

       }
       me.Redisplay();
    },

    Redisplay: function() {
	var transform = mat4(1);

        // this probably doesn't belong here
	transform = mult(transform, rotate(this.xr, [1,0,0]));
	transform = mult(transform, rotate(this.yr, [0,1,0]));
	transform = mult(transform, rotate(this.zr, [0,0,1]));
        this.gl.uniformMatrix4fv(this.transformLoc,false, flatten(transform ));

        this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);

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