anchor.diff:    uPointSize: new ShaderVarDesc("float", ""),
     uCanvasSize: new ShaderVarDesc("vec2", ""),
     uColor: new ShaderVarDesc("vec3", ""),
  +  uColorAlpha: new ShaderVarDesc("vec4", ""),
   };
   
   void IntroduceNewShaderVar(String name, ShaderVarDesc desc) {
  
positive.code:         gl.drawArrays(WEBGL.TRIANGLES, 0, numItems);
        }
      }
      if (debug) print(gl.getProgramInfoLog(program));
    }
  
    void SetUniform(String canonical, var val) {
      // Note, we could make this smarter and skip
      // overwriting values with the same values;
      assert(_VarsDb.containsKey(canonical));
      ShaderVarDesc desc = _VarsDb[canonical];
      assert(_uniformLocations.containsKey(canonical));
      WEBGL.UniformLocation l = _uniformLocations[canonical];
      _uniformInitialized.add(canonical);
      switch (desc.type) {
        case "float":
          gl.uniform1f(l, val);
          break;
        case "mat4":
          gl.uniformMatrix4fv(l, false, val.array);
          break;
        case "vec3":
          assert(val.array.length == 3);
          gl.uniform3fv(l, val.array);
          break;
        case "vec2":
          assert(val.array.length == 2);
          gl.uniform2fv(l, val.array);
          break;
        case "sampler2D":
          if (canonical == uTextureSampler) {
            int n = 0;
            gl.activeTexture(WEBGL.TEXTURE0 + n);
            gl.bindTexture(WEBGL.TEXTURE_2D, val.GetTexture());
            gl.uniform1i(l, n);
          } else if (canonical == uTexture2Sampler) {
            int n = _uniformLocations.containsKey(uTextureSampler) ? 1 : 0;
            gl.activeTexture(WEBGL.TEXTURE0 + n);
            gl.bindTexture(WEBGL.TEXTURE_2D, val.GetTexture());
            gl.uniform1i(l, n);
          } else {
            assert(false);
          }
          break;
        case "samplerCube":
          assert(canonical == uTextureCubeSampler);
          int n = (_uniformLocations.containsKey(uTextureSampler) ? 1 : 0) +
              (_uniformLocations.containsKey(uTexture2Sampler) ? 1 : 0);
          gl.activeTexture(WEBGL.TEXTURE0 + n);
          gl.bindTexture(WEBGL.TEXTURE_CUBE_MAP, val.GetTexture());
          gl.uniform1i(l, n);
          break;
        default:
          assert(false);
      }
    }
  
    void MaybeSetUniform(String canonical) {
      if (_uniformLocations.containsKey(canonical)) {
        SetUniform(canonical, inputs.GetUniformVal(canonical));
      }
    }
  
    void MaybeSetUniformsBulk(ShaderProgramInputs inputs) {
      for (String canonical in inputs.GetCanonicals()) {
        var val = inputs.GetUniformVal(canonical);
        if (_uniformLocations.containsKey(canonical)) {
          SetUniform(canonical, val);
        }
      }
    }
  
    void draw(PerspectiveParams dynpar, LightParams lightpar, Camera camera,
  
negative.code: const String uTransformationMatrix = "uTransformationMatrix";
  const String uModelViewMatrix = "uModelViewMatrix";
  const String uViewMatrix = "uViewMatrix";
  const String uNormalMatrix = "uNormalMatrix";
  
  const String uPerspectiveMatrix = "uPerpectiveMatrix";
  const String uTextureSampler = "uTextureSampler";
  const String uTextureCubeSampler = "uTextureCubeSampler";
  const String uTexture2Sampler = "uTexture2Sampler";
  const String uTexture3Sampler = "uTexture3Sampler";
  const String uTexture4Sampler = "uTexture4Sampler";
  const String uPointLightLocation = "uPointLightLocation";
  const String uTime = "uTime";
  const String uColor = "uColor";
  const String uColorAlpha = "uColorAlpha";
  const String uCameraNear = "uCameraNear";
  const String uCameraFar = "uCameraFar";
  const String uCanvasSize = "uCanvasSize";
  