Export({ shaders: {
"curve_peel_depth_vertex":'// Vertex shader for rendering curve segments, parameterized by\n// pos1, pos2, radius, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec4 pos;       // pos.w is 0 at the beginning of the segment and 1 at the end; \n                          // pos.xyz are relative to that end in a normal basis with x pointing along the segment and scaled by radius\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectRadius objectData[3].w\n#define objectColor objectData[4].rgb\n\nuniform vec4 segmentData[4];\n#define segmentPosR(i) segmentData[i]\n#define segmentColor(i) segmentData[2+i]\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvec4 start;\nvec4 end;\n   \nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nmat3 getSegmentRotation() {\n  // Construct the segment rotation matrix.\n    vec3 v = end.xyz - start.xyz;\n    float vmax = max( max( abs(v.x), abs(v.y) ), abs(v.z) );\n    vec3 X = normalize(v/vmax);\n    vec3 Z = cross(X,normalize(vec3(0,1,0)));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    \n    // The following code looks very clumsy, but all other more sensible schemes \n    // failed due to what might be bugs in shader compiling or execution.\n    // Specifically, trying to set start.w or end.w inside the if statement fails\n    // if the curve radius is less than about 1e-7. After setting the value\n    // inside the if, it\'s zero upon exit from the if. !!?!\n    float sw = 0.0;\n    if (segmentPosR(0).w < 0.0) { // -1 means use the curve global radius\n        sw = 1.0;\n    }\n    start = vec4(segmentPosR(0).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(0).w);\n    sw = 0.0;\n    if (segmentPosR(1).w < 0.0) {\n        sw = 1.0;\n    }\n    end = vec4(segmentPosR(1).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(1).w);\n    \n    mat3 rotObject = getObjectRotation();\n    start.xyz = rotObject*(objectScale*start.xyz) + objectPos;\n    end.xyz = rotObject*(objectScale*end.xyz) + objectPos;\n\n    // A rotation matrix with x pointed along the segment\n    mat3 rot = getSegmentRotation();\n    \n    // The position and radius of "this" end of the segment in world space\n    vec4 ws_segmentEnd = start * (1.-pos.w) + end * pos.w;\n    \n    // The position of this vertex in world space\n    vec3 ws_pos = ws_segmentEnd.xyz + rot * (ws_segmentEnd.w*pos.xyz);\n    \n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    \n    gl_Position = projMatrix * pos4;\n}',
"curve_pick_vertex":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec4 pos;       // pos.w is 0 at the beginning of the segment and 1 at the end; \n                          // pos.xyz are relative to that end in an normal basis with x pointing along the segment and scaled by radius\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectRadius objectData[3].w\n#define objectColor objectData[4].rgb\n\nuniform vec4 segmentData[4];\n#define segmentPosR(i) segmentData[i]\n#define segmentColor(i) segmentData[2+i]\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec4 vcolor;\n\nvec4 start;\nvec4 end;\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nmat3 getSegmentRotation() {\n    // Construct the object rotation matrix.\n    vec3 v = end.xyz - start.xyz;\n    float vmax = max( max( abs(v.x), abs(v.y) ), abs(v.z) );\n    vec3 X = normalize(v/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    vec4 start_color = segmentColor(0);\n    vec4 end_color = segmentColor(1);\n    if (start_color.r < 0.0) start_color.rgb = objectColor;\n    if (end_color.r < 0.0) end_color.rgb = objectColor.rgb;\n    \n    // The following code looks very clumsy, but all other more sensible schemes \n    // failed due to what might be bugs in shader compiling or execution.\n    // Specifically, trying to set start or end inside the if statement fails\n    // if the curve radius is less than about 1e-7 !!??\n    float sw = 0.0;\n    if (segmentPosR(0).w < 0.0) {\n        sw = 1.0;\n    }\n    start = vec4(segmentPosR(0).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(0).w);\n    sw = 0.0;\n    if (segmentPosR(1).w < 0.0) {\n        sw = 1.0;\n    }\n    end = vec4(segmentPosR(1).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(1).w);\n    \n    mat3 rotObject = getObjectRotation();\n    start.xyz = rotObject*(objectScale*start.xyz) + objectPos;\n    end.xyz = rotObject*(objectScale*end.xyz) + objectPos;\n\n    // A rotation matrix with x pointed along the segment\n    mat3 rot = getSegmentRotation();\n\n    // The position and radius of "this" end of the segment in world space\n    vec4 ws_segmentEnd = start * (1.-pos.w) + end * pos.w;\n\n    // The position of this vertex in world space\n    vec3 ws_pos = ws_segmentEnd.xyz + rot * (ws_segmentEnd.w*pos.xyz);\n\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    vcolor = start_color * (1.-pos.w) + end_color * pos.w;\n    gl_Position = projMatrix * pos4;\n}\n',
"curve_render_vertex":'// Vertex shader for rendering curve segments, parameterized by\n// pos1, pos2, radius, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec4 pos;       // pos.w is 0 at the beginning of the segment and 1 at the end; \n                          // pos.xyz are relative to that end in a normal basis with x pointing along the segment and scaled by radius\nattribute vec3 normal;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectRadius objectData[3].w\n#define objectColor objectData[4].rgb\n\nuniform vec4 segmentData[4];\n#define segmentPosR(i) segmentData[i]\n#define segmentColor(i) segmentData[2+i]\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump, flipx, flipy, turn\n\nvec4 start;\nvec4 end;\n   \nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nmat3 getSegmentRotation() {\n  // Construct the segment rotation matrix.\n    vec3 v = end.xyz - start.xyz;\n    float vmax = max( max( abs(v.x), abs(v.y) ), abs(v.z) );\n    vec3 X = normalize(v/vmax);\n    vec3 Z = cross(X,normalize(vec3(0,1,0)));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    vec4 start_color = segmentColor(0);\n    vec4 end_color = segmentColor(1);\n    if (start_color.r < 0.0) start_color.rgb = objectColor;\n    if (end_color.r < 0.0) end_color.rgb = objectColor.rgb;\n    \n    // The following code looks very clumsy, but all other more sensible schemes \n    // failed due to what might be bugs in shader compiling or execution.\n    // Specifically, trying to set start.w or end.w inside the if statement fails\n    // if the curve radius is less than about 1e-7. After setting the value\n    // inside the if, it\'s zero upon exit from the if. !!?!\n    float sw = 0.0;\n    if (segmentPosR(0).w < 0.0) { // -1 means use the curve global radius\n        sw = 1.0;\n    }\n    start = vec4(segmentPosR(0).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(0).w);\n    sw = 0.0;\n    if (segmentPosR(1).w < 0.0) {\n        sw = 1.0;\n    }\n    end = vec4(segmentPosR(1).xyz, sw*objectRadius + (1.0-sw)*segmentPosR(1).w);\n    \n    mat3 rotObject = getObjectRotation();\n    start.xyz = rotObject*(objectScale*start.xyz) + objectPos;\n    end.xyz = rotObject*(objectScale*end.xyz) + objectPos;\n\n    // A rotation matrix with x pointed along the segment\n    mat3 rot = getSegmentRotation();\n\n    // The position and radius of "this" end of the segment in world space\n    vec4 ws_segmentEnd = start * (1.-pos.w) + end * pos.w;\n\n    // The position of this vertex in world space\n    vec3 ws_pos = ws_segmentEnd.xyz + rot * (ws_segmentEnd.w*pos.xyz);\n\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    es_position = pos4.xyz;\n    es_normal = (viewMatrix * vec4(rot * (normal/objectScale), 0.0)).xyz;\n    \n    // no texture or bump map yet for curve object:\n    parameters = vec4(objectShininess, objectEmissive, 0.0, 0.0);\n    mat_pos = vec2(0.0, 0.0);\n    bumpX = vec3(1.0, 0.0, 0.0);\n    \n    vcolor = start_color * (1.-pos.w) + end_color * pos.w;\n    gl_Position = projMatrix * pos4;\n}',
"extent_vertex":"// Vertex shader for rendering standard 'objects' parameterized by\n// pos, axis, up, scale, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\nattribute vec3 color;\nattribute float opacity;\nattribute vec2 texpos;\nattribute vec3 bumpaxis;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\nuniform vec3 center;\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump, flipx, flipy, turn\n\nvec3 encode_float(float k) { // assumes k is >= 0\n    if (k <= 0.0) return vec3(0.0, 0.0, 0.0);\n    float logk = log(k);\n    if (logk < 0.0) {\n        logk = -logk + 128.0;\n    }\n    return vec3(\n        floor(logk)/255.0,\n        floor(256.0*fract(logk))/255.0,\n        floor(256.0*fract(256.0*logk))/255.0);\n}\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.  A waste to do this per vertex, but GPU >> CPU\n    vec3 X = normalize(objectAxis);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    mat3 rot = getObjectRotation();\n    // The position of this vertex in world space\n    vec3 ws_pos = rot*(objectScale*position) + objectPos;\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    es_position = pos4.xyz;\n    es_normal = (viewMatrix * vec4(rot*(normal/objectScale), 0.0)).xyz;\n    //gl_Position = posp;\n    bumpX = (viewMatrix * vec4(rot*bumpaxis, 0.0)).xyz;\n    mat_pos = texpos;\n    float extent = abs(ws_pos.x-center.x);\n    extent = max(abs(ws_pos.y-center.y), extent);\n    extent = max(abs(ws_pos.z-center.z), extent);\n    mat_color = vec4(encode_float(extent), 1.0);\n    // Setting gl_Position.xy to (-1.0, -1.0) should store into pixel (0, 0), but doesn't work:\n    gl_Position = vec4(-1.0, -1.0, 1e-20*extent, 1.0);\n\n    parameters = vec4(objectShininess, objectEmissive, 0.0, 0.0);\n}\n",
"merge_fragment":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform sampler2D C0; // TEXTURE2 - opaque color map (minormode 4)\nuniform sampler2D C1; // TEXTURE4 - color map for transparency render 1 (minormode 6)\nuniform sampler2D C2; // TEXTURE6 - color map for transparency render 2 (minormode 8)\nuniform sampler2D C3; // TEXTURE8 - color map for transparency render 3 (minormode 10)\nuniform sampler2D C4; // TEXTURE10 - color map for transparency render 4 (minormode 12)\nuniform vec2 canvas_size;\n\nvoid main(void) {\n    // need to combine colors from C0, C1, C2, C3, C4\n    vec2 loc = vec2( gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    vec4 c0 = texture2D(C0, loc);\n    vec4 c1 = texture2D(C1, loc);\n    vec4 c2 = texture2D(C2, loc);\n    vec4 c3 = texture2D(C3, loc);\n    vec4 c4 = texture2D(C4, loc);\n    \n    vec3 mcolor = c1.rgb*c1.a + \n                 (1.0-c1.a)*(c2.rgb*c2.a +\n                 (1.0-c2.a)*(c3.rgb*c3.a +\n                 (1.0-c3.a)*(c4.rgb*c4.a + \n                 (1.0-c4.a)*c0.rgb)));\n    gl_FragColor = vec4 (mcolor, 1.0);\n}\n',
"merge_fragment2":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform sampler2D C0; // TEXTURE2 - opaque color map (minormode 4)\nuniform sampler2D C1; // TEXTURE4 - color map for transparency render 1 (minormode 6)\nuniform vec2 canvas_size;\n\nvoid main(void) {\n    // need to combine colors from C0 and C1\n    // This is used with mobile devices that have few texture image units.\n    vec2 loc = vec2( gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    vec4 c0 = texture2D(C0, loc);\n    vec4 c1 = texture2D(C1, loc);    \n    \n    vec3 mcolor = c1.rgb*c1.a + (1.0-c1.a)*c0.rgb;\n    gl_FragColor = vec4 (mcolor, 1.0);\n}\n',
"merge_vertex":"// Vertex shader for rendering standard 'objects' parameterized by\n// pos, axis, up, size, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\n\nvoid main(void) {\n    gl_Position = vec4(pos, 1.0);\n}\n",
"opaque_render_fragment":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform int light_count;\nuniform vec4 light_pos[8];\nuniform vec3 light_color[8];\nuniform vec3 light_ambient;\n#define LP(i) light_pos[i]\n#define LC(i) light_color[i]\nuniform vec2 canvas_size;\n\nuniform sampler2D texmap;  // TEXTURE0 - user texture\nuniform sampler2D bumpmap; // TEXTURE1 - user bumpmap\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n#define shininess parameters[0]\n#define emissive parameters[1]\n#define hasTexture parameters[2]\n#define hasBump parameters[3]\n\nvec3 normal;\nvec3 pos;\nvec3 diffuse_color;\nvec3 specular_color;\nvec3 color;\n\nvoid calc_color(vec4 lpos, vec3 lcolor)\n{\n    vec3 L = lpos.xyz - pos*lpos.w; // w == 0 for distant_light\n    L = normalize(L);\n    float N = max(dot(normal,L), 0.0);\n    color += (lcolor * N)*diffuse_color;\n    if (shininess > 0.0) {\n        vec3 R = reflect(L,normal);\n        color += specular_color * lcolor * pow(max(dot(R,normalize(pos)),0.0),100.0*shininess);\n    }\n}\n\n// Return lit surface color based on the given surface properties and the lights\n//   specified by the light_* uniforms.\nvoid lightAt()\n{    \n    if (hasTexture != 0.0) {\n        diffuse_color = diffuse_color * texture2D(texmap, mat_pos).xyz;\n    }\n    if (hasBump != 0.0) {\n        vec3 Y = cross(normal, bumpX);\n        vec3 Nb = texture2D(bumpmap, mat_pos).xyz;\n        Nb = 2.0*Nb - 1.0;\n        normal = normalize(Nb.x*bumpX + Nb.y*Y + Nb.z*normal);\n    }\n    if (emissive != 0.0) {\n        // From VPython materials.emissive:\n        float d = dot(normalize(-pos), normal);\n        d = pow(d * 1.5, 0.4) * 1.1;\n        if (d > 1.0) d = 1.0;\n        color = diffuse_color * d;\n        return;\n    }\n    \n    color = light_ambient * diffuse_color;\n    \n    // It was necessary to restructure this shader completely in order to\n    // run on the Samsung Galaxy S3 smartphone. Apparently its compiler\n    // does not handle for loops correctly. An Asus Android tablet was ok.\n    if (light_count == 0) return;\n    calc_color(LP(0), LC(0));\n    if (light_count == 1) return;\n    calc_color(LP(1), LC(1));\n    if (light_count == 2) return;\n    calc_color(LP(2), LC(2));\n    if (light_count == 3) return;\n    calc_color(LP(3), LC(3));\n    if (light_count == 4) return;\n    calc_color(LP(4), LC(4));\n    if (light_count == 5) return;\n    calc_color(LP(5), LC(5));\n    if (light_count == 6) return;\n    calc_color(LP(6), LC(6));\n    if (light_count == 7) return;\n    calc_color(LP(7), LC(7));\n}\n\nvoid main(void) {\n    normal = normalize(es_normal);\n    pos = es_position;\n    diffuse_color = vcolor.rgb;\n    specular_color = vec3(.8,.8,.8);\n    lightAt(); // determine color from lighting\n    gl_FragColor = vec4( color, 1.0 );\n}\n',
"peel_color_fragmentC1":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform int light_count;\nuniform vec4 light_pos[8];\nuniform vec3 light_color[8];\nuniform vec3 light_ambient;\n#define LP(i) light_pos[i]\n#define LC(i) light_color[i]\nuniform vec2 canvas_size;\n\nuniform sampler2D texmap;  // TEXTURE0 - user texture\nuniform sampler2D bumpmap; // TEXTURE1 - user bumpmap\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n#define shininess parameters[0]\n#define emissive parameters[1]\n#define hasTexture parameters[2]\n#define hasBump parameters[3]\n\nvec3 normal;\nvec3 pos;\nvec3 diffuse_color;\nvec3 specular_color;\nvec3 color;\n\nvoid calc_color(vec4 lpos, vec3 lcolor)\n{\n    vec3 L = lpos.xyz - pos*lpos.w; // w == 0 for distant_light\n    L = normalize(L);\n    float N = max(dot(normal,L), 0.0);\n    color += (lcolor * N)*diffuse_color;\n    if (shininess > 0.0) {\n        vec3 R = reflect(L,normal);\n        color += specular_color * LC(0) * pow(max(dot(R,normalize(pos)),0.0),100.0*shininess);\n    }\n}\n\n// Return lit surface color based on the given surface properties and the lights\n//   specified by the light_* uniforms.\nvoid lightAt()\n{    \n    if (hasTexture != 0.0) {\n        diffuse_color = diffuse_color * texture2D(texmap, mat_pos).xyz;\n    }\n    if (hasBump != 0.0) {\n        vec3 Y = cross(normal, bumpX);\n        vec3 Nb = texture2D(bumpmap, mat_pos).xyz;\n        Nb = 2.0*Nb - 1.0;\n        normal = normalize(Nb.x*bumpX + Nb.y*Y + Nb.z*normal);\n    }\n    if (emissive != 0.0) {\n        // From VPython materials.emissive:\n        float d = dot(normalize(-pos), normal);\n        d = pow(d * 1.5, 0.4) * 1.1;\n        if (d > 1.0) d = 1.0;\n        color = diffuse_color * d;\n        return;\n    }\n    \n    color = light_ambient * diffuse_color;\n    \n    // It was necessary to restructure this shader completely in order to\n    // run on the Samsung Galaxy S3 smartphone. Apparently its compiler\n    // does not handle for loops correctly. An Asus Android tablet was ok.\n    if (light_count == 0) return;\n    calc_color(LP(0), LC(0));\n    if (light_count == 1) return;\n    calc_color(LP(1), LC(1));\n    if (light_count == 2) return;\n    calc_color(LP(2), LC(2));\n    if (light_count == 3) return;\n    calc_color(LP(3), LC(3));\n    if (light_count == 4) return;\n    calc_color(LP(4), LC(4));\n    if (light_count == 5) return;\n    calc_color(LP(5), LC(5));\n    if (light_count == 6) return;\n    calc_color(LP(6), LC(6));\n    if (light_count == 7) return;\n    calc_color(LP(7), LC(7));\n}\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create transparency color map - C1 (minormode 6), C2 (8), C3 (19), C4 (12)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n\n    normal = normalize(es_normal);\n    pos = es_position;\n    diffuse_color = vcolor.rgb;\n    specular_color = vec3(.8,.8,.8);\n    lightAt(); // determine color from lighting\n\t\n\tif (zmin < z) {\n        gl_FragColor = vec4( color, vcolor.a );\n    } else {\n    \tdiscard;\n    }\n}\n',
"peel_color_fragmentC2":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform int light_count;\nuniform vec4 light_pos[8];\nuniform vec3 light_color[8];\nuniform vec3 light_ambient;\n#define LP(i) light_pos[i]\n#define LC(i) light_color[i]\nuniform vec2 canvas_size;\n\nuniform sampler2D texmap;  // TEXTURE0 - user texture\nuniform sampler2D bumpmap; // TEXTURE1 - user bumpmap\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\nuniform sampler2D D1; // TEXTURE5 - depth map (minormode 7)\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n#define shininess parameters[0]\n#define emissive parameters[1]\n#define hasTexture parameters[2]\n#define hasBump parameters[3]\n\nvec3 normal;\nvec3 pos;\nvec3 diffuse_color;\nvec3 specular_color;\nvec3 color;\n\n\nvoid calc_color(vec4 lpos, vec3 lcolor)\n{\n    vec3 L = lpos.xyz - pos*lpos.w; // w == 0 for distant_light\n    L = normalize(L);\n    float N = max(dot(normal,L), 0.0);\n    color += (lcolor * N)*diffuse_color;\n    if (shininess > 0.0) {\n        vec3 R = reflect(L,normal);\n        color += specular_color * LC(0) * pow(max(dot(R,normalize(pos)),0.0),100.0*shininess);\n    }\n}\n\n// Return lit surface color based on the given surface properties and the lights\n//   specified by the light_* uniforms.\nvoid lightAt()\n{    \n    if (hasTexture != 0.0) {\n        diffuse_color = diffuse_color * texture2D(texmap, mat_pos).xyz;\n    }\n    if (hasBump != 0.0) {\n        vec3 Y = cross(normal, bumpX);\n        vec3 Nb = texture2D(bumpmap, mat_pos).xyz;\n        Nb = 2.0*Nb - 1.0;\n        normal = normalize(Nb.x*bumpX + Nb.y*Y + Nb.z*normal);\n    }\n    if (emissive != 0.0) {\n        // From VPython materials.emissive:\n        float d = dot(normalize(-pos), normal);\n        d = pow(d * 1.5, 0.4) * 1.1;\n        if (d > 1.0) d = 1.0;\n        color = diffuse_color * d;\n        return;\n    }\n    \n    color = light_ambient * diffuse_color;\n    \n    // It was necessary to restructure this shader completely in order to\n    // run on the Samsung Galaxy S3 smartphone. Apparently its compiler\n    // does not handle for loops correctly. An Asus Android tablet was ok.\n    if (light_count == 0) return;\n    calc_color(LP(0), LC(0));\n    if (light_count == 1) return;\n    calc_color(LP(1), LC(1));\n    if (light_count == 2) return;\n    calc_color(LP(2), LC(2));\n    if (light_count == 3) return;\n    calc_color(LP(3), LC(3));\n    if (light_count == 4) return;\n    calc_color(LP(4), LC(4));\n    if (light_count == 5) return;\n    calc_color(LP(5), LC(5));\n    if (light_count == 6) return;\n    calc_color(LP(6), LC(6));\n    if (light_count == 7) return;\n    calc_color(LP(7), LC(7));\n}\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create transparency color map - C1 (minormode 6), C2 (8), C3 (19), C4 (12)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    int zmax = fdecode(texture2D(D1, loc));\n    \n    normal = normalize(es_normal);\n    pos = es_position;\n    diffuse_color = vcolor.rgb;\n    specular_color = vec3(.8,.8,.8);\n    lightAt(); // determine color from lighting\n    \n    if (zmin < z && z < zmax) {\n        gl_FragColor = vec4( color, vcolor.a );\n    } else {\n        discard;\n    }\n}\n',
"peel_color_fragmentC3":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform int light_count;\nuniform vec4 light_pos[8];\nuniform vec3 light_color[8];\nuniform vec3 light_ambient;\n#define LP(i) light_pos[i]\n#define LC(i) light_color[i]\nuniform vec2 canvas_size;\n\nuniform sampler2D texmap;  // TEXTURE0 - user texture\nuniform sampler2D bumpmap; // TEXTURE1 - user bumpmap\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\nuniform sampler2D D2; // TEXTURE7 - depth map (minormode 9)\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n#define shininess parameters[0]\n#define emissive parameters[1]\n#define hasTexture parameters[2]\n#define hasBump parameters[3]\n\nvec3 normal;\nvec3 pos;\nvec3 diffuse_color;\nvec3 specular_color;\nvec3 color;\n\n\nvoid calc_color(vec4 lpos, vec3 lcolor)\n{\n    vec3 L = lpos.xyz - pos*lpos.w; // w == 0 for distant_light\n    L = normalize(L);\n    float N = max(dot(normal,L), 0.0);\n    color += (lcolor * N)*diffuse_color;\n    if (shininess > 0.0) {\n        vec3 R = reflect(L,normal);\n        color += specular_color * LC(0) * pow(max(dot(R,normalize(pos)),0.0),100.0*shininess);\n    }\n}\n\n// Return lit surface color based on the given surface properties and the lights\n//   specified by the light_* uniforms.\nvoid lightAt()\n{    \n    if (hasTexture != 0.0) {\n        diffuse_color = diffuse_color * texture2D(texmap, mat_pos).xyz;\n    }\n    if (hasBump != 0.0) {\n        vec3 Y = cross(normal, bumpX);\n        vec3 Nb = texture2D(bumpmap, mat_pos).xyz;\n        Nb = 2.0*Nb - 1.0;\n        normal = normalize(Nb.x*bumpX + Nb.y*Y + Nb.z*normal);\n    }\n    if (emissive != 0.0) {\n        // From VPython materials.emissive:\n        float d = dot(normalize(-pos), normal);\n        d = pow(d * 1.5, 0.4) * 1.1;\n        if (d > 1.0) d = 1.0;\n        color = diffuse_color * d;\n        return;\n    }\n    \n    color = light_ambient * diffuse_color;\n    \n    // It was necessary to restructure this shader completely in order to\n    // run on the Samsung Galaxy S3 smartphone. Apparently its compiler\n    // does not handle for loops correctly. An Asus Android tablet was ok.\n    if (light_count == 0) return;\n    calc_color(LP(0), LC(0));\n    if (light_count == 1) return;\n    calc_color(LP(1), LC(1));\n    if (light_count == 2) return;\n    calc_color(LP(2), LC(2));\n    if (light_count == 3) return;\n    calc_color(LP(3), LC(3));\n    if (light_count == 4) return;\n    calc_color(LP(4), LC(4));\n    if (light_count == 5) return;\n    calc_color(LP(5), LC(5));\n    if (light_count == 6) return;\n    calc_color(LP(6), LC(6));\n    if (light_count == 7) return;\n    calc_color(LP(7), LC(7));\n}\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create transparency color map - C1 (minormode 6), C2 (8), C3 (19), C4 (12)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    int zmax = fdecode(texture2D(D2, loc));\n    \n    normal = normalize(es_normal);\n    pos = es_position;\n    diffuse_color = vcolor.rgb;\n    specular_color = vec3(.8,.8,.8);\n    lightAt(); // determine color from lighting\n    \n    if (zmin < z && z < zmax) {\n        gl_FragColor = vec4( color, vcolor.a );\n    } else {\n        discard;\n    }\n}\n',
"peel_color_fragmentC4":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nuniform int light_count;\nuniform vec4 light_pos[8];\nuniform vec3 light_color[8];\nuniform vec3 light_ambient;\n#define LP(i) light_pos[i]\n#define LC(i) light_color[i]\nuniform vec2 canvas_size;\n\nuniform sampler2D texmap;  // TEXTURE0 - user texture\nuniform sampler2D bumpmap; // TEXTURE1 - user bumpmap\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\nuniform sampler2D D3; // TEXTURE9 - depth map (minormode 11)\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n#define shininess parameters[0]\n#define emissive parameters[1]\n#define hasTexture parameters[2]\n#define hasBump parameters[3]\n\nvec3 normal;\nvec3 pos;\nvec3 diffuse_color;\nvec3 specular_color;\nvec3 color;\n\nvoid calc_color(vec4 lpos, vec3 lcolor)\n{\n    vec3 L = lpos.xyz - pos*lpos.w; // w == 0 for distant_light\n    L = normalize(L);\n    float N = max(dot(normal,L), 0.0);\n    color += (lcolor * N)*diffuse_color;\n    if (shininess > 0.0) {\n        vec3 R = reflect(L,normal);\n        color += specular_color * LC(0) * pow(max(dot(R,normalize(pos)),0.0),100.0*shininess);\n    }\n}\n\n// Return lit surface color based on the given surface properties and the lights\n//   specified by the light_* uniforms.\nvoid lightAt()\n{    \n    if (hasTexture != 0.0) {\n        diffuse_color = diffuse_color * texture2D(texmap, mat_pos).xyz;\n    }\n    if (hasBump != 0.0) {\n        vec3 Y = cross(normal, bumpX);\n        vec3 Nb = texture2D(bumpmap, mat_pos).xyz;\n        Nb = 2.0*Nb - 1.0;\n        normal = normalize(Nb.x*bumpX + Nb.y*Y + Nb.z*normal);\n    }\n    if (emissive != 0.0) {\n        // From VPython materials.emissive:\n        float d = dot(normalize(-pos), normal);\n        d = pow(d * 1.5, 0.4) * 1.1;\n        if (d > 1.0) d = 1.0;\n        color = diffuse_color * d;\n        return;\n    }\n    \n    color = light_ambient * diffuse_color;\n    \n    // It was necessary to restructure this shader completely in order to\n    // run on the Samsung Galaxy S3 smartphone. Apparently its compiler\n    // does not handle for loops correctly. An Asus Android tablet was ok.\n    if (light_count == 0) return;\n    calc_color(LP(0), LC(0));\n    if (light_count == 1) return;\n    calc_color(LP(1), LC(1));\n    if (light_count == 2) return;\n    calc_color(LP(2), LC(2));\n    if (light_count == 3) return;\n    calc_color(LP(3), LC(3));\n    if (light_count == 4) return;\n    calc_color(LP(4), LC(4));\n    if (light_count == 5) return;\n    calc_color(LP(5), LC(5));\n    if (light_count == 6) return;\n    calc_color(LP(6), LC(6));\n    if (light_count == 7) return;\n    calc_color(LP(7), LC(7));\n}\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create transparency color map - C1 (minormode 6), C2 (8), C3 (19), C4 (12)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    int zmax = fdecode(texture2D(D3, loc));\n    \n    normal = normalize(es_normal);\n    pos = es_position;\n    diffuse_color = vcolor.rgb;\n    specular_color = vec3(.8,.8,.8);\n    lightAt(); // determine color from lighting\n    \n    if (zmin < z && z < zmax) {\n        gl_FragColor = vec4( color, vcolor.a );\n    } else {\n        discard;\n    }\n}\n',
"peel_depth_fragmentD0":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\n// Construct depth maps for depth peeling handling of opacity\n\n// minormode = 0 render, 1 pick, 2 autoscale, 4 C0, 5 D0, 6 C1, 7 D1, 8 C2, 9 D2, 10 C3, 11 D3, 12 C4\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nvoid main(void) {\n    // create depth map D0 (5)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    gl_FragColor = vec4(float(c.r)/255.0, float(c.g)/255.0, 0, 0);\n}',
"peel_depth_fragmentD1":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\n// Construct depth maps for depth peeling handling of opacity\n\nuniform vec2 canvas_size;\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\n\n// minormode = 0 render, 1 pick, 2 autoscale, 4 C0, 5 D0, 6 C1, 7 D1, 8 C2, 9 D2, 10 C3, 11 D3, 12 C4\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create depth map D1 (6)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    if (zmin < z) {\n        gl_FragColor = vec4(float(c.r)/255.0, float(c.g)/255.0, 0, 0);\n    } else {\n        discard;\n    }\n}\n',
"peel_depth_fragmentD2":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\n// Construct depth maps for depth peeling handling of opacity\n\nuniform vec2 canvas_size;\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\nuniform sampler2D D1; // TEXTURE5 - 1st transparency depth map (minormode 7)\n\n// minormode = 0 render, 1 pick, 2 autoscale, 4 C0, 5 D0, 6 C1, 7 D1, 8 C2, 9 D2, 10 C3, 11 D3, 12 C4\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create depth map D2 (7)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    int zmax = fdecode(texture2D(D1, loc));\n    if (zmin < z && z < zmax) {\n    \tgl_FragColor = vec4(float(c.r)/255.0, float(c.g)/255.0, 0, 0);\n    } else {\n        discard;\n    }\n}',
"peel_depth_fragmentD3":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\n// Construct depth maps for depth peeling handling of opacity\n\nuniform vec2 canvas_size;\nuniform sampler2D D0; // TEXTURE3 - opaque depth map (minormode 5)\nuniform sampler2D D2; // TEXTURE7 - 2nd transparency depth map (minormode 9)\n\n// minormode = 0 render, 1 pick, 2 autoscale, 4 C0, 5 D0, 6 C1, 7 D1, 8 C2, 9 D2, 10 C3, 11 D3, 12 C4\n\nivec4 encode(float k) { // assumes k is >= 0\n    if (k <= 0.0) return ivec4(0, 0, 0, 0);\n    k = 3.0*128.0*k;\n    int b1 = int(k);\n    int b2 = int(256.0*fract(k));\n    return ivec4(\n    \tb1,\n    \tb2,\n    \t0,\n    \t0);\n}\n\nint decode(ivec4 d) {\n    return int(256*d[0] + d[1]);\n}\n\nint fdecode(vec4 d) {\n    return int(255.0*(256.0*d[0] + d[1]));\n}\n\nvoid main(void) {\n    // create depth map D3 (8)\n    ivec4 c = encode(1.0 - gl_FragCoord.z);\n    int z = decode(c);\n    vec2 loc = vec2(gl_FragCoord.x/canvas_size.x, gl_FragCoord.y/canvas_size.y);\n    int zmin = fdecode(texture2D(D0, loc));\n    int zmax = fdecode(texture2D(D2, loc));\n    if (zmin < z && z < zmax) {\n        gl_FragColor = vec4(float(c.r)/255.0, float(c.g)/255.0, 0, 0);\n    } else {\n        discard;\n    }\n}',
"peel_depth_vertex":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    mat3 rot = getObjectRotation();\n    // The position of this vertex in world space\n    vec3 ws_pos = rot*(objectScale*pos) + objectPos;\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    gl_Position = projMatrix * pos4;\n}\n',
"pick_fragment":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nvarying vec4 vcolor;\n\nvoid main(void) {\n    gl_FragColor = vcolor;\n}\n',
"pick_vertex":"// Vertex shader for picking standard 'objects' parameterized by\n// pos, axis, up, size, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectAxis objectData[1].xyz\n#define objectUp objectData[2].xyz\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec4 vcolor;\n\nmat3 getObjectRotation() {\n  // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    mat3 rot = getObjectRotation();\n    // The position of this vertex in world space\n    vec3 ws_pos = rot*(objectScale*pos) + objectPos;\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    gl_Position = projMatrix * pos4;\n    vcolor = objectColor;\n}\n",
"render_vertex":"#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\nattribute vec3 color;\nattribute float opacity;\nattribute float shininess;\nattribute float emissive;\nattribute vec2 texpos;\nattribute vec3 bumpaxis;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump, flipx, flipy, turn\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n    mat3 rot = getObjectRotation();\n    // The position of this vertex in world space\n    vec3 ws_pos = rot*(objectScale*pos) + objectPos;\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    es_position = pos4.xyz;\n    es_normal = (viewMatrix * vec4(rot*(normal/objectScale), 0.0)).xyz;\n    gl_Position = projMatrix * pos4;\n    bumpX = (viewMatrix * vec4(rot*bumpaxis, 0.0)).xyz;\n    mat_pos = texpos;\n    vcolor = vec4(color*objectColor.rgb, opacity*objectColor.a);\n    \n    float f = flags; // turn, flipy, flipx, sides, right, left, bumpmap, texture\n    float turn = floor(f/128.0);\n    f -= 128.0*turn;\n    float flipy = floor(f/64.0);\n    f -= 64.0*flipy;\n    float flipx = floor(f/32.0);\n    f -= 32.0*flipx;\n    float sides = floor(f/16.0);\n    f -= 16.0*sides;\n    float right = floor(f/8.0);\n    f -= 8.0*right;\n    float left = floor(f/4.0);\n    f -= 4.0*left;\n    float B = floor(f/2.0);\n    f -= 2.0*B;\n    float T = f;\n    if (T != 0.0) {\n        if (flipx != 0.0) {\n            mat_pos.x = 1.0 - mat_pos.x;\n        }\n        if (flipy != 0.0) {\n            mat_pos.y = 1.0 - mat_pos.y;\n        }\n        if (turn > 0.0 && turn <= 3.0) {\n            if (turn == 1.0) {\n                mat_pos = vec2(mat_pos.y,1.0 - mat_pos.x);\n            } else if (turn == 2.0) {\n                mat_pos = vec2(1.0 - mat_pos.x,1.0 - mat_pos.y);\n            } else {\n                mat_pos = vec2(1.0 - mat_pos.y,mat_pos.x);\n            }\n        }\n        T = 0.0;\n        bool L = (normal.x == -1.0);\n        bool R = (normal.x == 1.0);\n        bool S = !L && !R;\n        if (L && left == 1.0) T = 1.0;\n        if (R && right == 1.0) T = 1.0;\n        if (S && sides == 1.0) T = 1.0;\n        if (T == 0.0) {\n            B = 0.0;\n        } else if (left == 0.0 || right == 0.0 || sides == 0.0) {\n            // don't mix texture and object color if texture doesn't cover entire object\n            vcolor = vec4(1.0, 1.0, 1.0, 1.0);\n        }\n    }\n    float emit = 0.0;\n    if (objectEmissive != 0.0) emit = 1.0;\n    if (emissive != 0.0) emit = 1.0;\n    parameters = vec4(objectShininess * shininess, emit, T, B);\n}\n",
"ring_peel_depth_vertex":'#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n\tmat3 rot = getObjectRotation();\n\t// See mesh.js for details on mesh; default radius of cross section is 0.05 (default outer radius is 0.5)\n    vec3 r = normal*objectScale;           // from center of ring to outer edge of circular cross section\n    vec3 n = normalize(r/objectScale);     // lies in the plane of the cross section at this location, perpendicular to outer edge\n    vec3 adjpos = r + (objectScale.x/0.1)*(pos.x*vec3(1,0,0) + pos.z*n);    // vertex in world coordinates\n    \n    vec3 ws_pos = rot*(adjpos) + objectPos;  // point in world space\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    gl_Position = projMatrix * pos4;\n}\n',
"ring_pick_vertex":"// Vertex shader for picking standard 'objects' parameterized by\n// pos, axis, up, size, color\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectAxis objectData[1].xyz\n#define objectUp objectData[2].xyz\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec4 vcolor;\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n\tmat3 rot = getObjectRotation();\n\t// See mesh.js for details on mesh; default radius of cross section is 0.05 (default outer radius is 0.5)\n    vec3 r = normal*objectScale;           // from center of ring to outer edge of circular cross section\n    vec3 n = normalize(r/objectScale);     // lies in the plane of the cross section at this location, perpendicular to outer edge\n    vec3 adjpos = r + (objectScale.x/0.1)*(pos.x*vec3(1,0,0) + pos.z*n);    // vertex in world coordinates\n    \n    vec3 ws_pos = rot*(adjpos) + objectPos;  // point in world space\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    gl_Position = projMatrix * pos4;\n    vcolor = objectColor;\n}\n",
"ring_render_vertex":"#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\nattribute vec3 color;\nattribute float opacity;\nattribute float shininess;\nattribute float emissive;\nattribute vec2 texpos;\nattribute vec3 bumpaxis;\n\nuniform vec4 objectData[5];\n#define objectPos objectData[0].xyz\n#define objectShininess objectData[0].w\n#define objectAxis objectData[1].xyz\n#define objectEmissive objectData[1].w\n#define objectUp objectData[2].xyz\n#define flags objectData[2].w\n#define objectScale objectData[3].xyz\n#define objectColor objectData[4].rgba\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump, flipx, flipy, turn\n\nmat3 getObjectRotation() {\n    // Construct the object rotation matrix.\n    float vmax = max( max( abs(objectAxis.x), abs(objectAxis.y) ), abs(objectAxis.z) );\n    vec3 X = normalize(objectAxis/vmax);\n    vec3 Z = cross(X,normalize(objectUp));\n    if ( dot(Z,Z) < 1e-10 ) {\n        Z = cross(X, vec3(1,0,0));\n        if (dot(Z,Z) < 1e-10 ) {\n            Z = cross(X, vec3(0,1,0));\n        }\n    }\n    Z = normalize(Z);\n    return mat3( X, normalize(cross(Z,X)), Z );\n}\n\nvoid main(void) {\n\tmat3 rot = getObjectRotation();\n\t// See mesh.js for details on mesh; default radius of cross section is 0.05 (default outer radius is 0.5)\n    vec3 r = normal*objectScale;  // from center of ring to outer edge of circular cross section\n    vec3 n = normalize(normal);   // lies in the plane of the cross section at this location, perpendicular to outer edge\n    vec3 adjpos = r + (objectScale.x/0.1)*(pos.x*vec3(1,0,0) + pos.z*n);    // vertex in world coordinates\n    vec3 N = adjpos - (r-0.5*objectScale.x*n);                              // normal in world coordinates\n    \n    vec3 ws_pos = rot*(adjpos) + objectPos;  // point in world space\n    vec4 pos4 = viewMatrix * vec4( ws_pos, 1.0);\n    es_position = pos4.xyz;\n    es_normal = (viewMatrix * vec4(rot*N, 0.0)).xyz;\n    gl_Position = projMatrix * pos4;\n    bumpX = (viewMatrix * vec4(rot*bumpaxis, 0.0)).xyz;\n    mat_pos = texpos;\n    vcolor = vec4(color*objectColor.rgb, opacity*objectColor.a);\n    \n    float f = flags; // turn, flipy, flipx, sides, right, left, bumpmap, texture\n    float turn = floor(f/128.0);\n    f -= 128.0*turn;\n    float flipy = floor(f/64.0);\n    f -= 64.0*flipy;\n    float flipx = floor(f/32.0);\n    f -= 32.0*flipx;\n    float sides = floor(f/16.0);\n    f -= 16.0*sides;\n    float right = floor(f/8.0);\n    f -= 8.0*right;\n    float left = floor(f/4.0);\n    f -= 4.0*left;\n    float B = floor(f/2.0);\n    f -= 2.0*B;\n    float T = f;\n    if (T != 0.0) {\n        if (flipx != 0.0) {\n            mat_pos.x = 1.0 - mat_pos.x;\n        }\n        if (flipy != 0.0) {\n            mat_pos.y = 1.0 - mat_pos.y;\n        }\n        if (turn > 0.0 && turn <= 3.0) {\n            if (turn == 1.0) {\n                mat_pos = vec2(mat_pos.y,1.0 - mat_pos.x);\n            } else if (turn == 2.0) {\n                mat_pos = vec2(1.0 - mat_pos.x,1.0 - mat_pos.y);\n            } else {\n                mat_pos = vec2(1.0 - mat_pos.y,mat_pos.x);\n            }\n        }\n        T = 0.0;\n        bool L = (normal.x == -1.0);\n        bool R = (normal.x == 1.0);\n        bool S = !L && !R;\n        if (L && left == 1.0) T = 1.0;\n        if (R && right == 1.0) T = 1.0;\n        if (S && sides == 1.0) T = 1.0;\n        if (T == 0.0) {\n            B = 0.0;\n        } else if (left == 0.0 || right == 0.0 || sides == 0.0) {\n            // don't mix texture and object color if texture doesn't cover entire object\n            vcolor = vec4(1.0, 1.0, 1.0, 1.0);\n        }\n    }\n    float emit = 0.0;\n    if (objectEmissive != 0.0) emit = 1.0;\n    if (emissive != 0.0) emit = 1.0;\n    parameters = vec4(objectShininess * shininess, emit, T, B);\n}\n",
"tri_peel_depth_vertex":'// Vertex shader for rendering triangles\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvoid main(void) {\n    gl_Position = projMatrix * viewMatrix * vec4( pos, 1.0);\n}\n',
"tri_pick_vertex":'// Vertex shader for picking triangles\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec4 color;\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\n\nvarying vec4 vcolor;\n\nvoid main(void) {\n    gl_Position = projMatrix * viewMatrix * vec4( pos, 1.0);\n    vcolor = color;\n}\n',
"tri_render_vertex":'// Vertex shader for rendering triangles\n\n#ifdef GL_ES\n#  ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#  else\nprecision mediump float;\n#  endif\n#endif\n\nattribute vec3 pos;\nattribute vec3 normal;\nattribute vec3 color;\nattribute float opacity;\nattribute float shininess;\nattribute float emissive;\nattribute vec2 texpos;\nattribute vec3 bumpaxis;\n\nuniform mat4 viewMatrix;\nuniform mat4 projMatrix;\nuniform float T; // 1.0 if there is a texture, else 0.0\nuniform float B; // 1.0 if there is a bumpmap, else 0.0\n\nvarying vec3 es_position;     // eye space surface position\nvarying vec3 es_normal;       // eye space surface normal\nvarying vec2 mat_pos;         // surface material position in [0,1]^2\nvarying vec4 vcolor;\nvarying vec3 bumpX;\nvarying vec4 parameters; // shininess, emissive, hasTexture, hasBump\n\nvoid main(void) {\n    vec4 pos4 = viewMatrix * vec4( pos, 1.0);\n    es_position = pos4.xyz;\n    es_normal = (viewMatrix * vec4(normal, 0.0)).xyz;\n    gl_Position = projMatrix * pos4;\n    bumpX = (viewMatrix * vec4(bumpaxis, 0.0)).xyz;\n    mat_pos = texpos;\n    vcolor = vec4(color, opacity);\n    parameters = vec4(shininess, emissive, T, B);\n}\n',
}});