title: WebGL: cannot display two textures
body: <p>I am trying to render a textured cube (using vertices, indices and tex coords) with a textured skybox (using cubemap) around it but somehow I always get the following error message:</p>
  
  <p>WebGL: INVALID_OPERATION: bindTexture: textures can not be used with multiple targets</p>
  
  <p>I have two textures and am probably using gl.activeTexture wrongly but I cannot figure it out.</p>
  
  <p>As you can see, the textured cube breifly flashes before the skybox seems to be drawn over it.</p>
  
  <p>temporary (24h) website with this code: <a href="http://priceless-dijkstra-4bf2a5.netlify.com/" rel="nofollow noreferrer">http://priceless-dijkstra-4bf2a5.netlify.com/</a></p>
  
  <p>Any ideas? </p>
  
  <pre><code>&lt;!-- Licensed under a BSD license. See license.html for license --&gt;
  &lt;!-- src: https://webglfundamentals.org/ --&gt;
  &lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;meta charset = "utf-8"&gt;
          &lt;meta name = "viewport" content = "width=device-width, initial-scale=1.0, user-scalable=yes"&gt;
          &lt;title&gt; WebGL - Textures - Data Texture 3 x2&lt;/title&gt;
          &lt;link type = "text/css" href = "./webgl-tutorials.css" rel = "stylesheet" /&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;div class = "description"&gt;
              A 3 x2 texture &lt;br /&gt;
          &lt;/div&gt;
          &lt;canvas id = "canvas"&gt;&lt;/canvas&gt;
      &lt;/body&gt;
      &lt;!-- vertex shader --&gt;
      &lt;script id = "3d-vertex-shader" type = "x-shader/x-vertex"&gt;
          attribute vec4 a_position;
          attribute vec2 a_texcoord;
          uniform mat4 u_matrix;
          varying vec2 v_texcoord;
          void main()
          {
              // Multiply the position by the matrix.
              gl_Position = u_matrix * a_position;
              // Pass the texcoord to the fragment shader.
              v_texcoord = a_texcoord;
          }
      &lt;/script&gt;
      &lt;!-- fragment shader --&gt;
      &lt;script id = "3d-fragment-shader" type = "x-shader/x-fragment"&gt;
          precision mediump float;
          // Passed in from the vertex shader.
          varying vec2 v_texcoord;
          // The texture.
          uniform sampler2D u_texture;
          void main()
          {
              gl_FragColor = texture2D(u_texture, v_texcoord);
          }
      &lt;/script&gt;
      &lt;!--skybox vertex shader--&gt;
      &lt;script id="skybox-vertex-shader" type="x-shader/x-vertex"&gt;
          attribute vec4 a_position;
          varying vec4 v_position;
          void main() 
          {
            v_position = a_position;
            gl_Position = a_position;
          }
      &lt;/script&gt;
      &lt;!--skybox fragment shader--&gt;
      &lt;script id="skybox-fragment-shader" type="x-shader/x-fragment"&gt;
          precision mediump float;
          uniform samplerCube u_skybox;
          uniform mat4 u_viewDirectionProjectionInverse;
          varying vec4 v_position;
          void main() 
          {
            vec4 t = u_viewDirectionProjectionInverse * v_position;
            gl_FragColor = textureCube(u_skybox, normalize(t.xyz / t.w));
          }
      &lt;/script&gt;
      &lt;script src = "./webgl-utils.js"&gt;&lt;/script&gt;
      &lt;script src = "./m4.js"&gt;&lt;/script&gt;
      &lt;script src = "./primitives.js"&gt;&lt;/script&gt;
      &lt;script type = "module"&gt;
          "use strict";
          function main()
          {
              // Get A WebGL context
              /** @type {HTMLCanvasElement} */
              var canvas = document.getElementById("canvas");
              var gl = canvas.getContext("webgl");
              if (!gl)
              {
                  return;
              }
              // setup GLSL program
              var program = webglUtils.createProgramFromScripts(gl, ["3d-vertex-shader", "3d-fragment-shader"]);
              // look up where the vertex data needs to go.
              var positionLocation = gl.getAttribLocation(program, "a_position");
              var texcoordLocation = gl.getAttribLocation(program, "a_texcoord");
              // lookup uniforms
              var matrixLocation = gl.getUniformLocation(program, "u_matrix");
              var textureLocation = gl.getUniformLocation(program, "u_texture");
  
              //create program for skybox
              const skyboxProgramInfo = webglUtils.createProgramInfo(gl, ["skybox-vertex-shader", "skybox-fragment-shader"]);
              var sb_textureLocation = gl.getUniformLocation(skyboxProgramInfo.program, "u_skybox");
              // create buffers and fill with vertex data
              const cubeBufferInfo = primitives.createCubeBufferInfo(gl, 1);
              const quadBufferInfo = primitives.createXYQuadBufferInfo(gl);
              // Create a texture.
              const sb_texture = gl.createTexture();
              gl.activeTexture(gl.TEXTURE0 + 1);
              gl.bindTexture(gl.TEXTURE_CUBE_MAP, sb_texture);
              const faceInfos = 
              [
                  { target: gl.TEXTURE_CUBE_MAP_POSITIVE_X, url: './pos-x.jpg', },
                  { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X, url: './neg-x.jpg', },
                  { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y, url: './pos-y.jpg', },
                  { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, url: './neg-y.jpg', },
                  { target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z, url: './pos-z.jpg', },
                  { target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, url: './neg-z.jpg', },
              ];
              faceInfos.forEach((faceInfo) =&gt; 
              {
                  const {target, url} = faceInfo;
                  // Upload the canvas to the cubemap face.
                  const level = 0;
                  const internalFormat = gl.RGBA;
                  const width = 512;
                  const height = 512;
                  const format = gl.RGBA;
                  const type = gl.UNSIGNED_BYTE;
                  // setup each face so it's immediately renderable
                  gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null);
                  // Asynchronously load an image
                  const image = new Image();
                  image.src = url;
                  image.addEventListener('load', function() 
                  {
                      // Now that the image has loaded make copy it to the skybox texture.
                      gl.activeTexture(gl.TEXTURE0 + 1);
                      gl.bindTexture(gl.TEXTURE_CUBE_MAP, sb_texture);
                      gl.texImage2D(target, level, internalFormat, format, type, image);
                      gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
                  });
              });
              gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
              gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
  
  
              // Create a buffer for positions
              var positionBuffer = gl.createBuffer();
              // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
              gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
              // Put the positions in the buffer
              setGeometry(gl);
  
              // Create a buffer for positions
              var indexBuffer = gl.createBuffer();
              // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer)
              gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
              // Put the positions in the buffer
              setIndices(gl);
  
              // provide texture coordinates for the rectangle.
              var texcoordBuffer = gl.createBuffer();
              gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
              // Set Texcoords.
              setTexcoords(gl);
              // Create a texture.
              var texture = gl.createTexture();
              //void gl.bindTexture(target, texture);
              gl.activeTexture(gl.TEXTURE0);
              gl.bindTexture(gl.TEXTURE_2D, texture);
              // fill texture with 3x2 pixels
              const level = 0;
              const internalFormat = gl.RGB;
              const width = 2;                
              const height = 2;               
              const border = 0;
              const format = gl.RGB;          
              const type = gl.UNSIGNED_BYTE;
              const data = new Uint8Array     
              ([
                  255, 0, 0,      0, 255, 0,
                  0, 0, 255,      128, 128, 128,
              ]);
              const alignment = 1;
              gl.pixelStorei(gl.UNPACK_ALIGNMENT, alignment);
              gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border, format, type, data);
              // set the filtering so we don't need mips and it's not filtered
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
              gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  
              function degToRad(d)
              {
                  return d * Math.PI / 180;
              }
              var fieldOfViewRadians = degToRad(60);
              var modelXRotationRadians = degToRad(0);
              var modelYRotationRadians = degToRad(0);
              // Get the starting time.
              var then = 0;
              requestAnimationFrame(drawScene);
              // Draw the scene.
              function drawScene(time)
              {
                  // convert to seconds
                  time *= 0.001;
                  // Subtract the previous time from the current time
                  var deltaTime = time - then;
                  // Remember the current time for the next frame.
                  then = time;
                  webglUtils.resizeCanvasToDisplaySize(gl.canvas);
                  // Tell WebGL how to convert from clip space to pixels
                  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
                  gl.enable(gl.CULL_FACE);
                  gl.enable(gl.DEPTH_TEST);
                  // Animate the rotation
                  modelYRotationRadians += -0.7 * deltaTime;
                  modelXRotationRadians += -0.4 * deltaTime;
                  // Clear the canvas AND the depth buffer.
                  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
                  // Tell it to use our program (pair of shaders)
                  gl.useProgram(program);
  
                  // Turn on the position attribute
                  gl.enableVertexAttribArray(positionLocation);
                  // Bind the position buffer.
                  gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
                  // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
                  var size = 3; // 3 components per iteration
                  var type = gl.FLOAT; // the data is 32bit floats
                  var normalize = false; // don't normalize the data
                  var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
                  var offset = 0; // start at the beginning of the buffer
                  gl.vertexAttribPointer( positionLocation, size, type, normalize, stride, offset);
  
                  // Turn on the teccord attribute
                  gl.enableVertexAttribArray(texcoordLocation);
                  // Bind the position buffer.
                  gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
                  // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER)
                  var size = 2; // 2 components per iteration
                  var type = gl.FLOAT; // the data is 32bit floats
                  var normalize = false; // don't normalize the data
                  var stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position
                  var offset = 0; // start at the beginning of the buffer
                  gl.vertexAttribPointer( texcoordLocation, size, type, normalize, stride, offset);
  
                  // Compute the projection matrix
                  var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
                  var projectionMatrix = m4.perspective(fieldOfViewRadians, aspect, 1, 2000);
                  var cameraPosition = [0, 0, 2];
                  var up = [0, 1, 0];
                  var target = [0, 0, 0];
                  // Compute the camera's matrix using look at.
                  var cameraMatrix = m4.lookAt(cameraPosition, target, up);
                  // Make a view matrix from the camera matrix.
                  var viewMatrix = m4.inverse(cameraMatrix);
                  var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
                  var matrix = m4.xRotate(viewProjectionMatrix, modelXRotationRadians);
                  matrix = m4.yRotate(matrix, modelYRotationRadians);
                  // Set the matrix.
                  gl.uniformMatrix4fv(matrixLocation, false, matrix);
                  // Tell the shader to use texture unit 0 for u_texture
                  gl.uniform1i(textureLocation, 0);
                  // Draw the geometry.
                  gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
  
                  // Skybox: we only care about direction so remove the translation
                  var viewDirectionMatrix = m4.copy(viewMatrix);
                  viewDirectionMatrix[12] = 0;
                  viewDirectionMatrix[13] = 0;
                  viewDirectionMatrix[14] = 0;
                  var viewDirectionProjectionMatrix = m4.multiply(projectionMatrix, viewDirectionMatrix);
                  var viewDirectionProjectionInverseMatrix = m4.inverse(viewDirectionProjectionMatrix);
                  // draw the skybox
                  gl.useProgram(skyboxProgramInfo.program);
                  webglUtils.setBuffersAndAttributes(gl, skyboxProgramInfo, quadBufferInfo);
                  webglUtils.setUniforms(skyboxProgramInfo, {
                    u_viewDirectionProjectionInverse: viewDirectionProjectionInverseMatrix,
                    u_skybox: texture,
                  });
                  // Tell the shader to use texture unit 0 for u_texture
                  gl.uniform1i(sb_textureLocation, 1);
                  webglUtils.drawBufferInfo(gl, quadBufferInfo);
  
                  requestAnimationFrame(drawScene);
              }
          }
  
          // Fill the buffer with the values that define a cube.
          function setGeometry(gl)
          {
              var positions = new Float32Array
              ([  
                  // Front face
                  -0.5, -0.5,  0.5,
                   0.5, -0.5,  0.5,
                   0.5,  0.5,  0.5,
                  -0.5,  0.5,  0.5,
                  // Back face
                  -0.5, -0.5, -0.5,
                  -0.5,  0.5, -0.5,
                   0.5,  0.5, -0.5,
                   0.5, -0.5, -0.5,
                  // Top face
                  -0.5,  0.5, -0.5,
                  -0.5,  0.5,  0.5,
                   0.5,  0.5,  0.5,
                   0.5,  0.5, -0.5,
                  // Bottom face
                  -0.5, -0.5, -0.5,
                   0.5, -0.5, -0.5,
                   0.5, -0.5,  0.5,
                  -0.5, -0.5,  0.5,
                  // Right face
                   0.5, -0.5, -0.5,
                   0.5,  0.5, -0.5,
                   0.5,  0.5,  0.5,
                   0.5, -0.5,  0.5,
                  // Left face
                  -0.5, -0.5, -0.5,
                  -0.5, -0.5,  0.5,
                  -0.5,  0.5,  0.5,
                  -0.5,  0.5, -0.5,
              ]);
              gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
          }
  
          // Fill the buffer with texture coordinates the cube.
          function setTexcoords(gl)
          {
              gl.bufferData
              (
                  gl.ARRAY_BUFFER,
                  new Float32Array
                  ([
                      // Front
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                      // Back
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                      // Top
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                      // Bottom
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                      // Right
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                      // Left
                      0.0,  0.0,
                      1.0,  0.0,
                      1.0,  1.0,
                      0.0,  1.0,
                  ]),
              gl.STATIC_DRAW);
          }
  
  
          // Fill the buffer with vertex indices
          function setIndices(gl)
          {
              var indices = new Uint16Array
              ([  
                  0,  1,  2,      0,  2,  3,    // front
                  4,  5,  6,      4,  6,  7,    // back
                  8,  9,  10,     8,  10, 11,   // top
                  12, 13, 14,     12, 14, 15,   // bottom
                  16, 17, 18,     16, 18, 19,   // right
                  20, 21, 22,     20, 22, 23,   // left
              ]);
              gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
          }
  
          main();
      &lt;/script&gt;
  &lt;/html&gt;
  </code></pre>