{"action":"created","comment":{"url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/comments/42256890","id":42256890,"diff_hunk":"@@ -0,0 +1,792 @@\n+/*global define*/\n+define([\n+    '../Core/defaultValue',\n+    '../Core/defined',\n+    '../Renderer/WebGLConstants'\n+], function(\n+    defaultValue,\n+    defined,\n+    WebGLConstants) {\n+    \"use strict\";\n+\n+    function webGLConstantToGlslType(webGLValue) {\n+        switch(webGLValue) {\n+            case WebGLConstants.FLOAT:\n+                return 'float';\n+            case WebGLConstants.FLOAT_VEC2:\n+                return 'vec2';\n+            case WebGLConstants.FLOAT_VEC3:\n+                return 'vec3';\n+            case WebGLConstants.FLOAT_VEC4:\n+                return 'vec4';\n+            case WebGLConstants.FLOAT_MAT2:\n+                return 'mat2';\n+            case WebGLConstants.FLOAT_MAT3:\n+                return 'mat3';\n+            case WebGLConstants.FLOAT_MAT4:\n+                return 'mat4';\n+            case WebGLConstants.SAMPLER_2D:\n+                return 'sampler2D';\n+        }\n+    }\n+\n+    function generateLightParameters(gltf) {\n+        var result = {};\n+\n+        var lights;\n+        if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {\n+            lights = gltf.extensions.KHR_materials_common.lights;\n+        }\n+\n+        if (defined(lights)) {\n+            // Figure out which node references the light\n+            var nodes = gltf.nodes;\n+            for (var nodeName in nodes) {\n+                if (nodes.hasOwnProperty(nodeName)) {\n+                    var node = nodes[nodeName];\n+                    if (defined(node.extensions) && defined(node.extensions.KHR_materials_common)) {\n+                        var nodeLightId = node.extensions.KHR_materials_common.light;\n+                        if (defined(nodeLightId) && defined(lights[nodeLightId])) {\n+                            lights[nodeLightId].node = nodeName;\n+                        }\n+                        delete node.extensions.KHR_materials_common;\n+                    }\n+                }\n+            }\n+\n+            // Add light parameters to result\n+            var lightCount = 0;\n+            for(var lightName in lights) {\n+                if (lights.hasOwnProperty(lightName)) {\n+                    var light = lights[lightName];\n+                    var lightBaseName = 'light' + lightCount.toString();\n+                    light.baseName = lightBaseName;\n+                    switch(light.type) {\n+                        case \"ambient\":\n+                        {\n+                            var ambient = light.ambient;\n+                            result[lightBaseName + 'Color'] =\n+                            {\n+                                type: WebGLConstants.FLOAT_VEC3,\n+                                value: ambient.color\n+                            };\n+                        }\n+                            break;\n+                        case \"directional\":\n+                        {\n+                            var directional = light.directional;\n+                            result[lightBaseName + 'Color'] =\n+                            {\n+                                type: WebGLConstants.FLOAT_VEC3,\n+                                value: directional.color\n+                            };\n+                            if (defined(light.node)) {\n+                                result[lightBaseName + 'Transform'] =\n+                                {\n+                                    node: light.node,\n+                                    semantic: 'MODELVIEW',\n+                                    type: WebGLConstants.FLOAT_MAT4\n+                                };\n+                            }\n+                        }\n+                            break;\n+                        case \"point\":\n+                        {\n+                            var point = light.point;\n+                            result[lightBaseName + 'Color'] =\n+                            {\n+                                type: WebGLConstants.FLOAT_VEC3,\n+                                value: point.color\n+                            };\n+                            if (defined(light.node)) {\n+                                result[lightBaseName + 'Transform'] =\n+                                {\n+                                    node: light.node,\n+                                    semantic: 'MODELVIEW',\n+                                    type: WebGLConstants.FLOAT_MAT4\n+                                };\n+                            }\n+                            result[lightBaseName + 'ConstantAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: point.constantAttenuation\n+                            };\n+                            result[lightBaseName + 'LinearAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: point.linearAttenuation\n+                            };\n+                            result[lightBaseName + 'QuadraticAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: point.quadraticAttenuation\n+                            };\n+                        }\n+                            break;\n+                        case \"spot\":\n+                        {\n+                            var spot = light.spot;\n+                            result[lightBaseName + 'Color'] =\n+                            {\n+                                type: WebGLConstants.FLOAT_VEC3,\n+                                value: spot.color\n+                            };\n+                            if (defined(light.node)) {\n+                                result[lightBaseName + 'Transform'] =\n+                                {\n+                                    node: light.node,\n+                                    semantic: 'MODELVIEW',\n+                                    type: WebGLConstants.FLOAT_MAT4\n+                                };\n+                                result[lightBaseName + 'InverseTransform'] = {\n+                                    node: light.node,\n+                                    semantic: 'MODELVIEWINVERSE',\n+                                    type: WebGLConstants.FLOAT_MAT4\n+                                };\n+                            }\n+                            result[lightBaseName + 'ConstantAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: spot.constantAttenuation\n+                            };\n+                            result[lightBaseName + 'LinearAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: spot.linearAttenuation\n+                            };\n+                            result[lightBaseName + 'QuadraticAttenuation'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: spot.quadraticAttenuation\n+                            };\n+\n+                            result[lightBaseName + 'FallOffAngle'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: spot.fallOffAngle\n+                            };\n+                            result[lightBaseName + 'FallOffExponent'] =\n+                            {\n+                                type: WebGLConstants.FLOAT,\n+                                value: spot.fallOffExponent\n+                            };\n+                        }\n+                            break;\n+                    }\n+                    ++lightCount;\n+                }\n+            }\n+        }\n+\n+        return result;\n+    }\n+\n+    var techniqueCount = 0;\n+    var shaderCount = 0;\n+    var programCount = 0;\n+    function generateTechnique(gltf, khrMaterialsCommon, attributes, lightParameters, jointCount) {\n+        var techniques = gltf.techniques;\n+        var shaders = gltf.shaders;\n+        var programs = gltf.programs;\n+        attributes = defaultValue(attributes, []);\n+        var attributesCount = attributes.length;\n+        var lightingModel = khrMaterialsCommon.technique.toUpperCase();\n+        var lights;\n+        if (defined(gltf.extensions) && defined(gltf.extensions.KHR_materials_common)) {\n+            lights = gltf.extensions.KHR_materials_common.lights;\n+        }\n+        var hasSkinning = (jointCount > 0);\n+        var values = khrMaterialsCommon.values;\n+        var isDoubleSided = values.doubleSided;\n+        delete values.doubleSided;\n+\n+        var vertexShader = 'precision highp float;\\n';\n+        var fragmentShader = 'precision highp float;\\n';\n+\n+        // Generate IDs for our new objects\n+        var techniqueId;\n+        do {\n+            techniqueId = 'technique' + (techniqueCount++).toString();\n+        } while(defined(techniques[techniqueId]));\n+\n+        var shaderId;\n+        var vertexShaderId;\n+        var fragmentShaderId;\n+        do {\n+            shaderId = 'shader' + (shaderCount++).toString();\n+            vertexShaderId = shaderId + 'VS';\n+            fragmentShaderId = shaderId + 'FS';\n+        } while(defined(shaders[vertexShaderId]) || defined(shaders[fragmentShaderId]));\n+\n+        var programId;\n+        do {\n+            programId = 'program' + (programCount++).toString();\n+        } while(defined(programs[programId]));\n+\n+        // Add techniques\n+        // TODO: Handle skinning\n+        var lowerCase;\n+        var techniqueAttributes = {};\n+        for (var i=0;i<attributesCount;++i) {\n+            lowerCase = attributes[i].toLowerCase();\n+            techniqueAttributes['a_' + lowerCase] = lowerCase;\n+        }\n+\n+        var techniqueParameters = {\n+            // Add matrices\n+            modelViewMatrix: {\n+                semantic: 'MODELVIEW',\n+                type: WebGLConstants.FLOAT_MAT4\n+            },\n+            normalMatrix: {\n+                semantic: 'MODELVIEWINVERSETRANSPOSE',\n+                type: WebGLConstants.FLOAT_MAT3\n+            },\n+            projectionMatrix: {\n+                semantic: 'PROJECTION',\n+                type: WebGLConstants.FLOAT_MAT4\n+            }\n+        };\n+\n+        if (hasSkinning) {\n+            techniqueParameters.jointMatrix = {\n+                count: jointCount,\n+                semantic: 'JOINTMATRIX',\n+                type: WebGLConstants.FLOAT_MAT4\n+            };\n+        }\n+\n+        // Add material parameters\n+        var hasAlpha = false;\n+        var typeValue;\n+        for(var name in values) {\n+            if (values.hasOwnProperty(name)) {\n+                var value = values[name];\n+                var type = typeof value;\n+                typeValue = -1;\n+                switch (type) {\n+                    case 'string':\n+                        typeValue = WebGLConstants.SAMPLER_2D;\n+                        break;\n+                    case 'number':\n+                        typeValue = WebGLConstants.FLOAT;\n+                        if (!hasAlpha && name === 'transparency') {\n+                            hasAlpha = (value !== 1.0);\n+                        }\n+                        break;\n+                    default:\n+                        if (Array.isArray(value)) {\n+                            // 35664 (vec2), 35665 (vec3), 35666 (vec4)\n+                            typeValue = 35662 + value.length;\n+                            if (!hasAlpha && typeValue === WebGLConstants.FLOAT_VEC4 && name === 'diffuse') {\n+                                hasAlpha = (value[3] !== 1.0);\n+                            }\n+                        }\n+                        break;\n+                }\n+                if (typeValue > 0) {\n+                    lowerCase = name.toLowerCase();\n+                    techniqueParameters[lowerCase] = {\n+                        type: typeValue\n+                    };\n+                }\n+            }\n+        }\n+\n+        // Copy light parameters into technique parameters\n+        if (defined(lightParameters)) {\n+            for (var lightParamName in lightParameters) {\n+                if (lightParameters.hasOwnProperty(lightParamName)) {\n+                    techniqueParameters[lightParamName] = lightParameters[lightParamName];\n+                }\n+            }\n+        }\n+\n+        // Generate uniforms object before attributes are added\n+        var techniqueUniforms = {};\n+        for (var paramName in techniqueParameters) {\n+            if (techniqueParameters.hasOwnProperty(paramName)) {\n+                var param = techniqueParameters[paramName];\n+                techniqueUniforms['u_' + paramName] = paramName;\n+                var arraySize = defined(param.count) ? '['+param.count+']' : '';\n+                if (param.type !== WebGLConstants.FLOAT_MAT3 && param.type !== WebGLConstants.FLOAT_MAT4) {\n+                    fragmentShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\\n';\n+                }\n+                else {\n+                    vertexShader += 'uniform ' + webGLConstantToGlslType(param.type) + ' u_' + paramName + arraySize + ';\\n';\n+                }\n+            }\n+        }\n+\n+        // Add attributes with semantics\n+        var vertexShaderMain = '';\n+        if (hasSkinning) {\n+            vertexShaderMain += '  mat4 skinMat = a_weight.x * u_jointMatrix[int(a_joint.x)];\\n';\n+            vertexShaderMain += '  skinMat += a_weight.y * u_jointMatrix[int(a_joint.y)];\\n';\n+            vertexShaderMain += '  skinMat += a_weight.z * u_jointMatrix[int(a_joint.z)];\\n';\n+            vertexShaderMain += '  skinMat += a_weight.w * u_jointMatrix[int(a_joint.w)];\\n';\n+        }\n+\n+        // TODO: Handle multiple texture coordinates for now we just use 1\n+        var v_texcoord;\n+        for (i=0;i<attributesCount;++i) {\n+            var attribute = attributes[i];\n+            typeValue = -1;\n+            if (attribute === 'POSITION') {\n+                typeValue = WebGLConstants.FLOAT_VEC3;\n+                vertexShader += 'attribute vec3 a_position;\\n';\n+                vertexShader += 'varying vec3 v_positionEC;\\n';\n+                if (hasSkinning) {\n+                    vertexShaderMain += '  vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);\\n';\n+                }\n+                else {\n+                    vertexShaderMain += '  vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);\\n';\n+                }\n+                vertexShaderMain += '  v_positionEC = pos.xyz;\\n';\n+                vertexShaderMain += '  gl_Position = u_projectionMatrix * pos;\\n';\n+                fragmentShader += 'varying vec3 v_positionEC;\\n';\n+            }\n+            else if (attribute === 'NORMAL') {\n+                typeValue = WebGLConstants.FLOAT_VEC3;\n+                vertexShader += 'attribute vec3 a_normal;\\n';\n+                vertexShader += 'varying vec3 v_normal;\\n';\n+                if (hasSkinning) {\n+                    vertexShaderMain += '  v_normal = u_normalMatrix * mat3(skinMat) * a_normal;\\n';\n+                }\n+                else {\n+                    vertexShaderMain += '  v_normal = u_normalMatrix * a_normal;\\n';\n+                }\n+\n+                fragmentShader += 'varying vec3 v_normal;\\n';\n+            }\n+            else if (attribute.indexOf('TEXCOORD') === 0) {\n+                typeValue = WebGLConstants.FLOAT_VEC2;\n+                lowerCase = attribute.toLowerCase();\n+                var a_texcoord = 'a_' + lowerCase;\n+                v_texcoord = 'v_' + lowerCase;\n+                vertexShader += 'attribute vec2 ' + a_texcoord + ';\\n';\n+                vertexShader += 'varying vec2 ' + v_texcoord + ';\\n';\n+                vertexShaderMain += '  ' + v_texcoord + ' = ' + a_texcoord + ';\\n';\n+\n+                fragmentShader += 'varying vec2 ' + v_texcoord + ';\\n';\n+            }\n+            else if (attribute === 'JOINT') {\n+                typeValue = WebGLConstants.FLOAT_VEC4;\n+                vertexShader += 'attribute vec4 a_joint;\\n';\n+            }\n+            else if (attribute === 'WEIGHT') {\n+                typeValue = WebGLConstants.FLOAT_VEC4;\n+                vertexShader += 'attribute vec4 a_weight;\\n';\n+            }\n+\n+            if (typeValue > 0) {\n+                lowerCase = attribute.toLowerCase();\n+                techniqueParameters[lowerCase] = {\n+                    semantic: attribute,\n+                    type: typeValue\n+                };\n+            }\n+        }\n+\n+        var hasNormals = defined(techniqueParameters.normal);\n+        var hasSpecular = hasNormals && (lightingModel === 'BLINN' || lightingModel === 'PHONG') &&\n+                          defined(techniqueParameters.specular) && defined(techniqueParameters.shininess);\n+\n+        // Generate lighting code blocks\n+        var hasNonAmbientLights = false;\n+        var hasAmbientLights = false;\n+        var fragmentLightingBlock = '';\n+        for (var lightName in lights) {\n+            if (lights.hasOwnProperty(lightName)) {\n+                var light = lights[lightName];\n+                var lightType = light.type.toLowerCase();\n+                var lightBaseName = light.baseName;\n+                fragmentLightingBlock += '  {\\n';\n+                var lightColorName = 'u_' + lightBaseName + 'Color';\n+                var varyingName;\n+                if(lightType === 'ambient') {\n+                    hasAmbientLights = true;\n+                    fragmentLightingBlock += '    ambientLight += ' + lightColorName + ';\\n';\n+                }\n+                else if (hasNormals && lightingModel !== 'CONSTANT') {\n+                    hasNonAmbientLights = true;\n+                    varyingName = 'v_' + lightBaseName + 'Direction';\n+                    vertexShader += 'varying vec3 ' + varyingName + ';\\n';\n+                    fragmentShader += 'varying vec3 ' + varyingName + ';\\n';\n+\n+                    if (lightType === 'spot') {\n+                        vertexShader += 'varying vec3 v_position;\\n';\n+                        vertexShaderMain += 'v_position = pos.xyz;\\n';\n+                        fragmentShader += 'varying vec3 v_position;\\n';\n+                    }\n+\n+                    if (lightType === 'directional') {\n+                        vertexShaderMain += '  ' + varyingName + ' = mat3(u_' + lightBaseName + 'Transform) * vec3(0.,0.,1.);\\n';\n+                        fragmentLightingBlock += '    float attenuation = 1.0;\\n';\n+                    }\n+                    else {\n+                        vertexShaderMain += '  ' + varyingName + ' = u_' + lightBaseName + 'Transform[3].xyz - pos.xyz;\\n';\n+                        fragmentLightingBlock += '    float range = length(v_light0Direction);\\n';\n+                        fragmentLightingBlock += '    float attenuation = 1.0 / (u_' + lightBaseName + 'ConstantAttenuation + ';\n+                        fragmentLightingBlock += '(u_' + lightBaseName + 'LinearAttenuation * range) + ';\n+                        fragmentLightingBlock += '(u_' + lightBaseName + 'QuadraticAttenuation * range * range));\\n';\n+                    }\n+\n+                    fragmentLightingBlock += '    vec3 l = normalize(' + varyingName + ');\\n';\n+\n+                    if (lightType === 'spot') {\n+                        fragmentLightingBlock += '    vec4 spotPosition = u_' + lightBaseName + 'InverseTransform * vec4(v_position, 1.);\\n';\n+                        fragmentLightingBlock += '    float cosAngle = dot(vec3(0.0,0.0,-1.0), normalize(spotPosition.xyz));\\n';\n+                        fragmentLightingBlock += '    if (cosAngle > cos(radians(u_' + lightBaseName + 'FallOffAngle * 0.5)))\\n;';\n+                        fragmentLightingBlock += '    {\\n';\n+                        fragmentLightingBlock += '        attenuation *= max(0.0, pow(cosAngle, u_' + lightBaseName + 'FallOffExponent));\\n';\n+                    }\n+\n+                    fragmentLightingBlock += '    diffuseLight += ' + lightColorName + '* max(dot(normal,l), 0.) * attenuation;\\n';\n+\n+                    if (hasSpecular) {\n+                        if (lightingModel === 'BLINN') {\n+                            fragmentLightingBlock += '    vec3 h = normalize(l + viewDir);\\n';\n+                            fragmentLightingBlock += '    float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess)) * attenuation;\\n';\n+                        }\n+                        else { // PHONG\n+                            fragmentLightingBlock += '    vec3 reflectDir = reflect(-l, normal);\\n';\n+                            fragmentLightingBlock += '    float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)) * attenuation;\\n';\n+                        }\n+                        fragmentLightingBlock += '    specularLight += ' + lightColorName + ' * specularIntensity;\\n';\n+                    }\n+\n+                    if (lightType === 'spot') {\n+                        fragmentLightingBlock += '    }\\n';\n+                    }\n+                }\n+                fragmentLightingBlock += '  }\\n';\n+            }\n+        }\n+\n+        if (!hasAmbientLights) {\n+            // Add an ambient light if we don't have one\n+            fragmentLightingBlock += '  ambientLight += vec3(0.1, 0.1, 0.1);\\n';\n+        }\n+\n+        if (!hasNonAmbientLights) {\n+            fragmentLightingBlock += '  vec3 l = normalize(czm_sunDirectionEC);\\n';\n+            fragmentLightingBlock += '  diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal,l), 0.);\\n';\n+\n+            if (hasSpecular) {\n+                if (lightingModel === 'BLINN') {\n+                    fragmentLightingBlock += '  vec3 h = normalize(l + viewDir);\\n';\n+                    fragmentLightingBlock += '  float specularIntensity = max(0., pow(max(dot(normal, h), 0.), u_shininess));\\n';\n+                }\n+                else { // PHONG\n+                    fragmentLightingBlock += '  vec3 reflectDir = reflect(-l, normal);\\n';\n+                    fragmentLightingBlock += '  float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess));\\n';\n+                }\n+\n+                fragmentLightingBlock += '  specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity;\\n';\n+            }\n+        }\n+\n+        vertexShader += 'void main(void) {\\n';\n+        vertexShader += vertexShaderMain;\n+        vertexShader += '}\\n';\n+\n+        fragmentShader += 'void main(void) {\\n';\n+        var colorCreationBlock = '  vec3 color = vec3(0.0, 0.0, 0.0);\\n';\n+        if (hasNormals) {\n+            fragmentShader += '  vec3 normal = normalize(v_normal);\\n';\n+            if (isDoubleSided) {\n+                fragmentShader += '  if (gl_FrontFacing == false)\\n';\n+                fragmentShader += '  {\\n';\n+                fragmentShader += '    normal = -normal;\\n';\n+                fragmentShader += '  }\\n';\n+            }\n+        }\n+\n+        var finalColorComputation;\n+        if (lightingModel !== 'CONSTANT') {\n+            if (defined(techniqueParameters.diffuse)) {\n+                if (techniqueParameters.diffuse.type === WebGLConstants.SAMPLER_2D) {\n+                    fragmentShader += '  vec4 diffuse = texture2D(u_diffuse, ' + v_texcoord + ');\\n';\n+                }\n+                else {\n+                    fragmentShader += '  vec4 diffuse = u_diffuse;\\n';\n+                }\n+                fragmentShader += '  vec3 diffuseLight = vec3(0.0, 0.0, 0.0);\\n';\n+                colorCreationBlock += '  color += diffuse.rgb * diffuseLight;\\n';\n+            }\n+\n+            if (hasSpecular) {\n+                if (techniqueParameters.specular.type === WebGLConstants.SAMPLER_2D) {\n+                    fragmentShader += '  vec3 specular = texture2D(u_specular, ' + v_texcoord + ');\\n';\n+                }\n+                else {\n+                    fragmentShader += '  vec3 specular = u_specular.rgb;\\n';\n+                }\n+                fragmentShader += '  vec3 specularLight = vec3(0.0, 0.0, 0.0);\\n';\n+                colorCreationBlock += '  color += specular * specularLight;\\n';\n+            }\n+\n+            if (defined(techniqueParameters.transparency)) {\n+                finalColorComputation = '  gl_FragColor = vec4(color * diffuse.a, diffuse.a * u_transparency);\\n';\n+            }\n+            else {\n+                finalColorComputation = '  gl_FragColor = vec4(color * diffuse.a, diffuse.a);\\n';\n+            }\n+        }\n+        else {\n+            if (defined(techniqueParameters.transparency)) {\n+                finalColorComputation = '  gl_FragColor = vec4(color, u_transparency);\\n';\n+            }\n+            else {\n+                finalColorComputation = '  gl_FragColor = vec4(color, 1.0);\\n';\n+            }\n+        }\n+\n+        if (defined(techniqueParameters.emission)) {\n+            if (techniqueParameters.emission.type === WebGLConstants.SAMPLER_2D) {\n+                fragmentShader += '  vec3 emission = texture2D(u_emission, ' + v_texcoord + ');\\n';\n+            }\n+            else {\n+                fragmentShader += '  vec3 emission = u_emission.rgb;\\n';\n+            }\n+            colorCreationBlock += '  color += emission;\\n';\n+        }\n+\n+        if (defined(techniqueParameters.ambient)) {\n+            if (techniqueParameters.ambient.type === WebGLConstants.SAMPLER_2D) {\n+                fragmentShader += '  vec3 ambient = texture2D(u_ambient, ' + v_texcoord + ');\\n';\n+            }\n+            else {\n+                fragmentShader += '  vec3 ambient = u_ambient.rgb;\\n';\n+            }\n+        }\n+        else {\n+            fragmentShader += '  vec3 ambient = diffuse.rgb;\\n';\n+        }\n+        fragmentShader += '  vec3 viewDir = -normalize(v_positionEC);\\n';\n+        fragmentShader += '  vec3 ambientLight = vec3(0.0, 0.0, 0.0);\\n';\n+        colorCreationBlock += '  color += ambient * ambientLight;\\n';\n+\n+        // Add in light computations\n+        fragmentShader += fragmentLightingBlock;\n+\n+        fragmentShader += colorCreationBlock;\n+        fragmentShader += finalColorComputation;\n+        fragmentShader += '}\\n';\n+\n+        // TODO: Handle texture transparency\n+        var techniqueStates;\n+        if (hasAlpha) {\n+            techniqueStates = {\n+                enable: [\n+                    WebGLConstants.DEPTH_TEST,\n+                    WebGLConstants.BLEND\n+                ],\n+                depthMask: false,\n+                functions: {\n+                    \"blendEquationSeparate\": [\n+                        WebGLConstants.FUNC_ADD,\n+                        WebGLConstants.FUNC_ADD\n+                    ],\n+                    \"blendFuncSeparate\": [\n+                        WebGLConstants.ONE,\n+                        WebGLConstants.ONE_MINUS_SRC_ALPHA,\n+                        WebGLConstants.ONE,\n+                        WebGLConstants.ONE_MINUS_SRC_ALPHA\n+                    ]\n+                }\n+            };\n+        }\n+        else {\n+            techniqueStates = {\n+                enable: [\n+                    WebGLConstants.CULL_FACE,\n+                    WebGLConstants.DEPTH_TEST\n+                ]\n+            };\n+        }\n+        techniques[techniqueId] = {\n+            attributes: techniqueAttributes,\n+            parameters: techniqueParameters,\n+            program: programId,\n+            states: techniqueStates,\n+            uniforms: techniqueUniforms\n+        };\n+\n+        // Add shaders\n+        shaders[vertexShaderId] = {\n+            type: WebGLConstants.VERTEX_SHADER,\n+            uri: '',\n+            extras: {\n+                source: vertexShader\n+            }\n+        };\n+        shaders[fragmentShaderId] = {\n+            type: WebGLConstants.FRAGMENT_SHADER,\n+            uri: '',\n+            extras: {\n+                source: fragmentShader\n+            }\n+        };\n+\n+        // Add program\n+        var programAttributes = [];\n+        for (i=0;i<attributesCount;++i) {\n+            programAttributes.push('a_' + attributes[i].toLowerCase());\n+        }\n+\n+        programs[programId] = {\n+            attributes: programAttributes,\n+            fragmentShader: fragmentShaderId,\n+            vertexShader: vertexShaderId\n+        };\n+\n+        return techniqueId;\n+    }\n+\n+    function getKey(khrMaterialsCommon) {\n+        var key = '';\n+        key += 'technique:' + khrMaterialsCommon.technique + ';';\n+\n+        var values = khrMaterialsCommon.values;\n+        var keys = Object.keys(values).sort();\n+        var keysCount = keys.length;\n+        for (var i=0;i<keysCount;++i) {\n+            var name = keys[i];\n+            if (values.hasOwnProperty(name)) {\n+                var value = values[name];\n+                key += name + ':';\n+                var type = typeof value;\n+                switch (type) {\n+                    case 'string':\n+                        key += 'texture';\n+                        break;\n+                    case 'number':\n+                        key += 'float';\n+                        break;\n+                    default:\n+                        if (Array.isArray(value)) {\n+                            key += 'vec' + value.length.toString();\n+                        }\n+                        break;\n+                }\n+                key += ';';\n+            }\n+        }\n+    }\n+\n+    function getPrimitiveInfo(materialId, gltf) {\n+        var meshes = gltf.meshes;\n+        for (var name in meshes) {\n+            if (meshes.hasOwnProperty(name)) {\n+                var mesh = meshes[name];\n+                var primitives = mesh.primitives;\n+                var primitivesCount = primitives.length;\n+                for (var i=0;i<primitivesCount;++i) {\n+                    var primitive = primitives[i];\n+                    if (primitive.material === materialId) {\n+                        var jointCount = 0;\n+                        if (defined(primitive.attributes.JOINT)) {\n+                            var nodes = gltf.nodes;\n+                            for (var nodeName in nodes) {\n+                                if (nodes.hasOwnProperty(nodeName)) {\n+                                    var node = nodes[nodeName];\n+                                    // We have skinning for this node and it contains this mesh\n+                                    if (defined(node.skeletons) && defined(node.meshes) &&\n+                                            node.meshes.indexOf(name) !== -1) {\n+                                        jointCount = node.skeletons.length;\n+                                    }\n+                                }\n+                            }\n+                        }\n+\n+                        return {\n+                            attributes : Object.keys(primitive.attributes),\n+                            jointCount : jointCount\n+                        };\n+                    }\n+                }\n+            }\n+        }\n+    }\n+\n+    /**\n+     * Modifies gltf in place.\n+     *\n+     * @private\n+     */\n+    var modelMaterialsCommon = function(gltf) {\n+        if (!defined(gltf)) {\n+            return undefined;\n+        }\n+\n+        var hasExtension = false;\n+        var extensionsUsed = gltf.extensionsUsed;\n+        if (defined(extensionsUsed)) {\n+            var extensionsUsedCount = extensionsUsed.length;\n+            for(var i=0;i<extensionsUsedCount;++i) {\n+                if (extensionsUsed[i] === 'KHR_materials_common') {\n+                    hasExtension = true;\n+                    extensionsUsed.splice(i, 1);\n+                    break;\n+                }\n+            }\n+        }\n+\n+        if (hasExtension) {\n+            if (!defined(gltf.programs)) {\n+                gltf.programs = {};\n+            }\n+            if (!defined(gltf.shaders)) {\n+                gltf.shaders = {};\n+            }\n+            if (!defined(gltf.techniques)) {\n+                gltf.techniques = {};\n+            }\n+\n+            var lightParameters = generateLightParameters(gltf);\n+\n+            var techniques = {};\n+            var materials = gltf.materials;\n+            var meshes = gltf.meshes;\n+            for (var name in materials) {\n+                if (materials.hasOwnProperty(name)) {\n+                    var material = materials[name];\n+                    var primitiveInfo = getPrimitiveInfo(name, gltf);\n+                    if (defined(material.extensions) && defined(material.extensions.KHR_materials_common)) {\n+                        var khrMaterialsCommon = material.extensions.KHR_materials_common;\n+                        var key = getKey(khrMaterialsCommon);","path":"Source/Scene/modelMaterialsCommon.js","position":759,"original_position":759,"commit_id":"fe520c8efe61de4af9f4790a45646efb15afe9ca","original_commit_id":"fe520c8efe61de4af9f4790a45646efb15afe9ca","user":{"login":"pjcozzi","id":782098,"avatar_url":"https://avatars.githubusercontent.com/u/782098?v=3","gravatar_id":"","url":"https://api.github.com/users/pjcozzi","html_url":"https://github.com/pjcozzi","followers_url":"https://api.github.com/users/pjcozzi/followers","following_url":"https://api.github.com/users/pjcozzi/following{/other_user}","gists_url":"https://api.github.com/users/pjcozzi/gists{/gist_id}","starred_url":"https://api.github.com/users/pjcozzi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pjcozzi/subscriptions","organizations_url":"https://api.github.com/users/pjcozzi/orgs","repos_url":"https://api.github.com/users/pjcozzi/repos","events_url":"https://api.github.com/users/pjcozzi/events{/privacy}","received_events_url":"https://api.github.com/users/pjcozzi/received_events","type":"User","site_admin":false},"body":"`key` is really `techniqueID`, right?  Can we rename it?","created_at":"2015-10-16T15:43:08Z","updated_at":"2015-10-16T15:43:08Z","html_url":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039#discussion_r42256890","pull_request_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039","_links":{"self":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/comments/42256890"},"html":{"href":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039#discussion_r42256890"},"pull_request":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039"}}},"pull_request":{"url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039","id":45415257,"html_url":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039","diff_url":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039.diff","patch_url":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039.patch","issue_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/3039","number":3039,"state":"open","locked":false,"title":"glTF 1.0 Changes","user":{"login":"tfili","id":1652382,"avatar_url":"https://avatars.githubusercontent.com/u/1652382?v=3","gravatar_id":"","url":"https://api.github.com/users/tfili","html_url":"https://github.com/tfili","followers_url":"https://api.github.com/users/tfili/followers","following_url":"https://api.github.com/users/tfili/following{/other_user}","gists_url":"https://api.github.com/users/tfili/gists{/gist_id}","starred_url":"https://api.github.com/users/tfili/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tfili/subscriptions","organizations_url":"https://api.github.com/users/tfili/orgs","repos_url":"https://api.github.com/users/tfili/repos","events_url":"https://api.github.com/users/tfili/events{/privacy}","received_events_url":"https://api.github.com/users/tfili/received_events","type":"User","site_admin":false},"body":"Don't merge yet\r\n\r\nFixes\r\n- [x] Handle KHR_binary_glTF extension\r\n- [ ] 1.0 Spec changes (https://github.com/KhronosGroup/glTF/issues/406)\r\n  - [x] `mesh.primitive.primitive` -> `mesh.primitive.mode`\r\n  - [ ] `mesh.primitive.indices` are now optional\r\n  - [x] `technique.parameter.source` -> `technique.parameter.node`\r\n  - [x] Removed `passes` from `technique`\r\n  - [ ] Make `technique` optional. Render gray material if no `technique` or extension\r\n  - [x] Support extensions for COLLADA common profile techniques\r\n  - [ ] Don't load models with extensions we don't support\r\n- [ ] Update all sample and test `bgltf` files to `glb` except one for testing\r\n- [ ] Update MIME type (https://github.com/KhronosGroup/glTF/issues/412)\r\n- [ ] Update CHANGES.md\r\n- [ ] Support for uniforms that are arrays of textures","created_at":"2015-09-18T14:53:05Z","updated_at":"2015-10-16T15:43:08Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c751f2665cc53be602f85a2569b3fb742f53e09b","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039/commits","review_comments_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039/comments","review_comment_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/comments{/number}","comments_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/3039/comments","statuses_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/statuses/fe520c8efe61de4af9f4790a45646efb15afe9ca","head":{"label":"tfili:glTF-1.0","ref":"glTF-1.0","sha":"fe520c8efe61de4af9f4790a45646efb15afe9ca","user":{"login":"tfili","id":1652382,"avatar_url":"https://avatars.githubusercontent.com/u/1652382?v=3","gravatar_id":"","url":"https://api.github.com/users/tfili","html_url":"https://github.com/tfili","followers_url":"https://api.github.com/users/tfili/followers","following_url":"https://api.github.com/users/tfili/following{/other_user}","gists_url":"https://api.github.com/users/tfili/gists{/gist_id}","starred_url":"https://api.github.com/users/tfili/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tfili/subscriptions","organizations_url":"https://api.github.com/users/tfili/orgs","repos_url":"https://api.github.com/users/tfili/repos","events_url":"https://api.github.com/users/tfili/events{/privacy}","received_events_url":"https://api.github.com/users/tfili/received_events","type":"User","site_admin":false},"repo":{"id":12764777,"name":"cesium","full_name":"tfili/cesium","owner":{"login":"tfili","id":1652382,"avatar_url":"https://avatars.githubusercontent.com/u/1652382?v=3","gravatar_id":"","url":"https://api.github.com/users/tfili","html_url":"https://github.com/tfili","followers_url":"https://api.github.com/users/tfili/followers","following_url":"https://api.github.com/users/tfili/following{/other_user}","gists_url":"https://api.github.com/users/tfili/gists{/gist_id}","starred_url":"https://api.github.com/users/tfili/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tfili/subscriptions","organizations_url":"https://api.github.com/users/tfili/orgs","repos_url":"https://api.github.com/users/tfili/repos","events_url":"https://api.github.com/users/tfili/events{/privacy}","received_events_url":"https://api.github.com/users/tfili/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/tfili/cesium","description":"WebGL virtual globe and map engine","fork":true,"url":"https://api.github.com/repos/tfili/cesium","forks_url":"https://api.github.com/repos/tfili/cesium/forks","keys_url":"https://api.github.com/repos/tfili/cesium/keys{/key_id}","collaborators_url":"https://api.github.com/repos/tfili/cesium/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/tfili/cesium/teams","hooks_url":"https://api.github.com/repos/tfili/cesium/hooks","issue_events_url":"https://api.github.com/repos/tfili/cesium/issues/events{/number}","events_url":"https://api.github.com/repos/tfili/cesium/events","assignees_url":"https://api.github.com/repos/tfili/cesium/assignees{/user}","branches_url":"https://api.github.com/repos/tfili/cesium/branches{/branch}","tags_url":"https://api.github.com/repos/tfili/cesium/tags","blobs_url":"https://api.github.com/repos/tfili/cesium/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/tfili/cesium/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/tfili/cesium/git/refs{/sha}","trees_url":"https://api.github.com/repos/tfili/cesium/git/trees{/sha}","statuses_url":"https://api.github.com/repos/tfili/cesium/statuses/{sha}","languages_url":"https://api.github.com/repos/tfili/cesium/languages","stargazers_url":"https://api.github.com/repos/tfili/cesium/stargazers","contributors_url":"https://api.github.com/repos/tfili/cesium/contributors","subscribers_url":"https://api.github.com/repos/tfili/cesium/subscribers","subscription_url":"https://api.github.com/repos/tfili/cesium/subscription","commits_url":"https://api.github.com/repos/tfili/cesium/commits{/sha}","git_commits_url":"https://api.github.com/repos/tfili/cesium/git/commits{/sha}","comments_url":"https://api.github.com/repos/tfili/cesium/comments{/number}","issue_comment_url":"https://api.github.com/repos/tfili/cesium/issues/comments{/number}","contents_url":"https://api.github.com/repos/tfili/cesium/contents/{+path}","compare_url":"https://api.github.com/repos/tfili/cesium/compare/{base}...{head}","merges_url":"https://api.github.com/repos/tfili/cesium/merges","archive_url":"https://api.github.com/repos/tfili/cesium/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/tfili/cesium/downloads","issues_url":"https://api.github.com/repos/tfili/cesium/issues{/number}","pulls_url":"https://api.github.com/repos/tfili/cesium/pulls{/number}","milestones_url":"https://api.github.com/repos/tfili/cesium/milestones{/number}","notifications_url":"https://api.github.com/repos/tfili/cesium/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/tfili/cesium/labels{/name}","releases_url":"https://api.github.com/repos/tfili/cesium/releases{/id}","created_at":"2013-09-11T18:56:08Z","updated_at":"2015-02-05T19:52:30Z","pushed_at":"2015-10-16T00:06:24Z","git_url":"git://github.com/tfili/cesium.git","ssh_url":"git@github.com:tfili/cesium.git","clone_url":"https://github.com/tfili/cesium.git","svn_url":"https://github.com/tfili/cesium","homepage":"http://cesium.agi.com/","size":242769,"stargazers_count":0,"watchers_count":0,"language":"JavaScript","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"AnalyticalGraphicsInc:master","ref":"master","sha":"933834c9b48fcaafa0367d5eea44ee1165c4cf64","user":{"login":"AnalyticalGraphicsInc","id":1490220,"avatar_url":"https://avatars.githubusercontent.com/u/1490220?v=3","gravatar_id":"","url":"https://api.github.com/users/AnalyticalGraphicsInc","html_url":"https://github.com/AnalyticalGraphicsInc","followers_url":"https://api.github.com/users/AnalyticalGraphicsInc/followers","following_url":"https://api.github.com/users/AnalyticalGraphicsInc/following{/other_user}","gists_url":"https://api.github.com/users/AnalyticalGraphicsInc/gists{/gist_id}","starred_url":"https://api.github.com/users/AnalyticalGraphicsInc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnalyticalGraphicsInc/subscriptions","organizations_url":"https://api.github.com/users/AnalyticalGraphicsInc/orgs","repos_url":"https://api.github.com/users/AnalyticalGraphicsInc/repos","events_url":"https://api.github.com/users/AnalyticalGraphicsInc/events{/privacy}","received_events_url":"https://api.github.com/users/AnalyticalGraphicsInc/received_events","type":"Organization","site_admin":false},"repo":{"id":3606738,"name":"cesium","full_name":"AnalyticalGraphicsInc/cesium","owner":{"login":"AnalyticalGraphicsInc","id":1490220,"avatar_url":"https://avatars.githubusercontent.com/u/1490220?v=3","gravatar_id":"","url":"https://api.github.com/users/AnalyticalGraphicsInc","html_url":"https://github.com/AnalyticalGraphicsInc","followers_url":"https://api.github.com/users/AnalyticalGraphicsInc/followers","following_url":"https://api.github.com/users/AnalyticalGraphicsInc/following{/other_user}","gists_url":"https://api.github.com/users/AnalyticalGraphicsInc/gists{/gist_id}","starred_url":"https://api.github.com/users/AnalyticalGraphicsInc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AnalyticalGraphicsInc/subscriptions","organizations_url":"https://api.github.com/users/AnalyticalGraphicsInc/orgs","repos_url":"https://api.github.com/users/AnalyticalGraphicsInc/repos","events_url":"https://api.github.com/users/AnalyticalGraphicsInc/events{/privacy}","received_events_url":"https://api.github.com/users/AnalyticalGraphicsInc/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/AnalyticalGraphicsInc/cesium","description":"WebGL virtual globe and map engine","fork":false,"url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium","forks_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/forks","keys_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/keys{/key_id}","collaborators_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/teams","hooks_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/hooks","issue_events_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/events{/number}","events_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/events","assignees_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/assignees{/user}","branches_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/branches{/branch}","tags_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/tags","blobs_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/git/refs{/sha}","trees_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/git/trees{/sha}","statuses_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/statuses/{sha}","languages_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/languages","stargazers_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/stargazers","contributors_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/contributors","subscribers_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/subscribers","subscription_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/subscription","commits_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/commits{/sha}","git_commits_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/git/commits{/sha}","comments_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/comments{/number}","issue_comment_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/comments{/number}","contents_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/contents/{+path}","compare_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/compare/{base}...{head}","merges_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/merges","archive_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/downloads","issues_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues{/number}","pulls_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls{/number}","milestones_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/milestones{/number}","notifications_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/labels{/name}","releases_url":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/releases{/id}","created_at":"2012-03-02T22:27:14Z","updated_at":"2015-10-16T09:09:52Z","pushed_at":"2015-10-16T15:24:45Z","git_url":"git://github.com/AnalyticalGraphicsInc/cesium.git","ssh_url":"git@github.com:AnalyticalGraphicsInc/cesium.git","clone_url":"https://github.com/AnalyticalGraphicsInc/cesium.git","svn_url":"https://github.com/AnalyticalGraphicsInc/cesium","homepage":"cesiumjs.org","size":497308,"stargazers_count":982,"watchers_count":982,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":585,"mirror_url":null,"open_issues_count":310,"forks":585,"open_issues":310,"watchers":982,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039"},"html":{"href":"https://github.com/AnalyticalGraphicsInc/cesium/pull/3039"},"issue":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/3039"},"comments":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/issues/3039/comments"},"review_comments":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039/comments"},"review_comment":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/pulls/3039/commits"},"statuses":{"href":"https://api.github.com/repos/AnalyticalGraphicsInc/cesium/statuses/fe520c8efe61de4af9f4790a45646efb15afe9ca"}}}}