text: /*global defineSuite*/
  defineSuite([
          'Scene/TextureAtlas',
          'Core/BoundingRectangle',
          'Core/Cartesian2',
          'Core/loadImage',
          'Core/Math',
          'Core/PixelFormat',
          'Core/PrimitiveType',
          'Renderer/Buffer',
          'Renderer/BufferUsage',
          'Renderer/ClearCommand',
          'Renderer/DrawCommand',
          'Renderer/ShaderProgram',
          'Renderer/VertexArray',
          'Specs/createScene',
          'ThirdParty/when'
      ], function(
          TextureAtlas,
          BoundingRectangle,
          Cartesian2,
          loadImage,
          CesiumMath,
          PixelFormat,
          PrimitiveType,
          Buffer,
          BufferUsage,
          ClearCommand,
          DrawCommand,
          ShaderProgram,
          VertexArray,
          createScene,
          when) {
      'use strict';
  
      var scene;
      var atlas;
      var greenImage;
      var tallGreenImage;
      var blueImage;
      var bigRedImage;
      var bigBlueImage;
      var bigGreenImage;
  
      beforeAll(function() {
          scene = createScene();
  
          return when.join(
              loadImage('./Data/Images/Green.png').then(function(image) {
                  greenImage = image;
              }),
              loadImage('./Data/Images/Green1x4.png').then(function(image) {
                  tallGreenImage = image;
              }),
              loadImage('./Data/Images/Blue.png').then(function(image) {
                  blueImage = image;
              }),
              loadImage('./Data/Images/Red16x16.png').then(function(image) {
                  bigRedImage = image;
              }),
              loadImage('./Data/Images/Blue10x10.png').then(function(image) {
                  bigBlueImage = image;
              }),
              loadImage('./Data/Images/Green4x4.png').then(function(image) {
                  bigGreenImage = image;
              }));
      });
  
      afterAll(function() {
          scene.destroyForSpecs();
      });
  
      afterEach(function() {
          atlas = atlas && atlas.destroy();
      });
  
      function expectToRender(texture, textureCoordinates, expected) {
          var x = textureCoordinates.x + textureCoordinates.width / 2.0;
          var y = textureCoordinates.y + textureCoordinates.height / 2.0;
          var fs = 
              'uniform sampler2D u_texture;' +
              'void main() {' +
              '  gl_FragColor = texture2D(u_texture, vec2(' + x + ', ' + y + '));' +
              '}';
          var uniformMap = {
              u_texture : function() {
                  return texture;
              }
          };
  
          expect({
              context : scene.context,
              fragmentShader : fs,
              uniformMap : uniformMap
          }).contextToRender(expected);
      }
  
      it('creates a single image atlas', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(greenImage.src, greenImage).then(function(index) {
              expect(index).toEqual(0);
  
              expect(atlas.numberOfImages).toEqual(1);
              expect(atlas.borderWidthInPixels).toEqual(0);
  
              var texture = atlas.texture;
              var atlasWidth = 2.0;
              var atlasHeight = 2.0;
              expect(texture.pixelFormat).toEqual(PixelFormat.RGBA);
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              var coords = atlas.textureCoordinates[index];
              expect(coords.x).toEqual(0.0 / atlasWidth);
              expect(coords.y).toEqual(0.0 / atlasHeight);
              expect(coords.width).toEqual(1.0 / atlasWidth);
              expect(coords.height).toEqual(1.0 / atlasHeight);
          });
      });
  
      it('renders a single image atlas', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(greenImage.src, greenImage).then(function(index) {
              var texture = atlas.texture;
              var coords = atlas.textureCoordinates[index];
  
              expectToRender(texture, coords, [0, 255, 0, 255]);
          });
      });
  
      it('creates a single image atlas with default values', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          return atlas.addImage(greenImage.src, greenImage).then(function(index) {
              expect(index).toEqual(0);
  
              expect(atlas.numberOfImages).toEqual(1);
              expect(atlas.borderWidthInPixels).toEqual(1);
  
              var texture = atlas.texture;
  
              var atlasWidth = 16.0;
              var atlasHeight = 16.0;
              expect(texture.pixelFormat).toEqual(PixelFormat.RGBA);
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              var coords = atlas.textureCoordinates[index];
              expect(coords.x).toEqual(1.0 / atlasWidth);
              expect(coords.y).toEqual(1.0 / atlasHeight);
              expect(coords.width).toEqual(1.0 / atlasWidth);
              expect(coords.height).toEqual(1.0 / atlasHeight);
          });
      });
  
      it('renders a single image atlas with default values', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          return atlas.addImage(greenImage.src, greenImage).then(function(index) {
              var texture = atlas.texture;
              var coords = atlas.textureCoordinates[index];
  
              expectToRender(texture, coords, [0, 255, 0, 255]);
          });
      });
  
      it('creates a single image atlas with non-square initialSize', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1.0, 5.0)
          });
  
          return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) {
              expect(index).toEqual(0);
  
              expect(atlas.numberOfImages).toEqual(1);
  
              var texture = atlas.texture;
  
              var atlasWidth = 2.0;
              var atlasHeight = 8.0;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              var coords = atlas.textureCoordinates[index];
              expect(coords.x).toEqual(0.0 / atlasWidth);
              expect(coords.y).toEqual(0.0 / atlasHeight);
              expect(coords.width).toEqual(1.0 / atlasWidth);
              expect(coords.height).toEqual(4.0 / atlasHeight);
          });
      });
  
      it('renders a single image atlas with non-square initialSize', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1.0, 5.0)
          });
  
          return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) {
              var texture = atlas.texture;
              var coords = atlas.textureCoordinates[index];
  
              expectToRender(texture, coords, [0, 255, 0, 255]);
          });
      });
  
      it('creates a two image atlas', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(2, 2)
          });
  
          var promises = [];
          promises.push(atlas.addImage(greenImage.src, greenImage));
          promises.push(atlas.addImage(blueImage.src, blueImage));
  
          return when.all(promises, function(indices) {
              var greenIndex = indices[0];
              var blueIndex = indices[1];
  
              expect(atlas.numberOfImages).toEqual(2);
  
              var texture = atlas.texture;
              var atlasWidth = 2.0;
              var atlasHeight = 2.0;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              var greenCoords = atlas.textureCoordinates[greenIndex];
              expect(greenCoords.x).toEqual(0.0 / atlasWidth);
              expect(greenCoords.y).toEqual(0.0 / atlasHeight);
              expect(greenCoords.width).toEqual(1.0 / atlasWidth);
              expect(greenCoords.height).toEqual(1.0 / atlasHeight);
  
              var blueCoords = atlas.textureCoordinates[blueIndex];
              expect(blueCoords.x).toEqual(1.0 / atlasWidth);
              expect(blueCoords.y).toEqual(0.0 / atlasHeight);
              expect(blueCoords.width).toEqual(1.0 / atlasWidth);
              expect(blueCoords.height).toEqual(1.0 / atlasHeight);
          });
      });
  
      it('renders a two image atlas', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(2, 2)
          });
  
          var promises = [];
          promises.push(atlas.addImage(greenImage.src, greenImage));
          promises.push(atlas.addImage(blueImage.src, blueImage));
  
          return when.all(promises, function(indices) {
              var greenIndex = indices[0];
              var blueIndex = indices[1];
  
              var texture = atlas.texture;
  
              var greenCoords = atlas.textureCoordinates[greenIndex];
              expectToRender(texture, greenCoords, [0, 255, 0, 255]);
  
              var blueCoords = atlas.textureCoordinates[blueIndex];
              expectToRender(texture, blueCoords, [0, 0, 255, 255]);
          });
      });
  
      it('renders a four image atlas', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0
          });
  
          var promises = [];
          promises.push(atlas.addImage(greenImage.src, greenImage));
          promises.push(atlas.addImage(blueImage.src, blueImage));
          promises.push(atlas.addImage(bigRedImage.src, bigRedImage));
          promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage));
  
          return when.all(promises, function(indices) {
              var greenIndex = indices.shift();
              var blueIndex = indices.shift();
              var bigRedIndex = indices.shift();
              var bigBlueIndex = indices.shift();
  
              expect(atlas.numberOfImages).toEqual(4);
  
              var texture = atlas.texture;
              var c0 = atlas.textureCoordinates[greenIndex];
              var c1 = atlas.textureCoordinates[blueIndex];
              var c2 = atlas.textureCoordinates[bigRedIndex];
              var c3 = atlas.textureCoordinates[bigBlueIndex];
  
              expectToRender(texture, c0, [0, 255, 0, 255]);
              expectToRender(texture, c1, [0, 0, 255, 255]);
              expectToRender(texture, c2, [255, 0, 0, 255]);
              expectToRender(texture, c3, [0, 0, 255, 255]);
          });
      });
  
      it('creates a four image atlas with non-zero borderWidthInPixels', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 2
          });
  
          var promises = [];
          promises.push(atlas.addImage(greenImage.src, greenImage));
          promises.push(atlas.addImage(blueImage.src, blueImage));
          promises.push(atlas.addImage(bigRedImage.src, bigRedImage));
          promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage));
  
          return when.all(promises, function(indices) {
              var greenIndex = indices.shift();
              var blueIndex = indices.shift();
              var bigRedIndex = indices.shift();
              var bigBlueIndex = indices.shift();
  
              expect(atlas.borderWidthInPixels).toEqual(2);
              expect(atlas.numberOfImages).toEqual(4);
  
              var texture = atlas.texture;
              var c0 = atlas.textureCoordinates[greenIndex];
              var c1 = atlas.textureCoordinates[blueIndex];
              var c2 = atlas.textureCoordinates[bigRedIndex];
              var c3 = atlas.textureCoordinates[bigBlueIndex];
  
              var atlasWidth = 68.0;
              var atlasHeight = 68.0;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              expect(c0.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16);
              expect(c0.y).toEqualEpsilon(2.0 / atlasHeight, CesiumMath.EPSILON16);
              expect(c0.width).toEqualEpsilon(greenImage.width / atlasWidth, CesiumMath.EPSILON16);
              expect(c0.height).toEqualEpsilon(greenImage.height / atlasHeight, CesiumMath.EPSILON16);
  
              expect(c1.x).toEqualEpsilon((greenImage.width + 2 * atlas.borderWidthInPixels) / atlasWidth, CesiumMath.EPSILON16);
              expect(c1.y).toEqualEpsilon(2.0 / atlasHeight, CesiumMath.EPSILON16);
              expect(c1.width).toEqualEpsilon(blueImage.width / atlasWidth, CesiumMath.EPSILON16);
              expect(c1.height).toEqualEpsilon(blueImage.width / atlasHeight, CesiumMath.EPSILON16);
  
              expect(c2.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16);
              expect(c2.y).toEqualEpsilon((bigRedImage.height + atlas.borderWidthInPixels) / atlasHeight, CesiumMath.EPSILON16);
              expect(c2.width).toEqualEpsilon(bigRedImage.width / atlasWidth, CesiumMath.EPSILON16);
              expect(c2.height).toEqualEpsilon(bigRedImage.height / atlasHeight, CesiumMath.EPSILON16);
  
              expect(c3.x).toEqualEpsilon(2.0 / atlasWidth, CesiumMath.EPSILON16);
              expect(c3.y).toEqualEpsilon((greenImage.height + 2 * atlas.borderWidthInPixels) / atlasHeight, CesiumMath.EPSILON16);
              expect(c3.width).toEqualEpsilon(bigBlueImage.width / atlasWidth, CesiumMath.EPSILON16);
              expect(c3.height).toEqualEpsilon(bigBlueImage.height / atlasHeight, CesiumMath.EPSILON16);
          });
      });
  
      it('renders a four image atlas with non-zero borderWidthInPixels', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 2
          });
  
          var promises = [];
          promises.push(atlas.addImage(greenImage.src, greenImage));
          promises.push(atlas.addImage(blueImage.src, blueImage));
          promises.push(atlas.addImage(bigRedImage.src, bigRedImage));
          promises.push(atlas.addImage(bigBlueImage.src, bigBlueImage));
  
          return when.all(promises, function(indices) {
              var greenIndex = indices.shift();
              var blueIndex = indices.shift();
              var bigRedIndex = indices.shift();
              var bigBlueIndex = indices.shift();
  
              expect(atlas.numberOfImages).toEqual(4);
  
              var texture = atlas.texture;
              var c0 = atlas.textureCoordinates[greenIndex];
              var c1 = atlas.textureCoordinates[blueIndex];
              var c2 = atlas.textureCoordinates[bigRedIndex];
              var c3 = atlas.textureCoordinates[bigBlueIndex];
  
              expectToRender(texture, c0, [0, 255, 0, 255]);
              expectToRender(texture, c1, [0, 0, 255, 255]);
              expectToRender(texture, c2, [255, 0, 0, 255]);
              expectToRender(texture, c3, [0, 0, 255, 255]);
          });
      });
  
      it('creates an atlas that dynamically resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) {
              expect(atlas.numberOfImages).toEqual(1);
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var atlasWidth = 2.0;
              var atlasHeight = 2.0;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              // blue image
              expect(coordinates[blueIndex].x).toEqual(0.0 / atlasWidth);
              expect(coordinates[blueIndex].y).toEqual(0.0 / atlasHeight);
              expect(coordinates[blueIndex].width).toEqual(1.0 / atlasWidth);
              expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight);
  
              //Add the big green image
              return atlas.addImage(bigGreenImage.src, bigGreenImage).then(function(greenIndex) {
                  expect(atlas.numberOfImages).toEqual(2);
  
                  var texture = atlas.texture;
                  var coordinates = atlas.textureCoordinates;
  
                  var atlasWidth = 12.0;
                  var atlasHeight = 12.0;
                  expect(texture.width).toEqual(atlasWidth);
                  expect(texture.height).toEqual(atlasHeight);
  
                  // blue image
                  expect(coordinates[blueIndex].x).toEqual(0.0 / atlasWidth);
                  expect(coordinates[blueIndex].y).toEqual(0.0 / atlasHeight);
                  expect(coordinates[blueIndex].width).toEqual(1.0 / atlasWidth);
                  expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight);
  
                  // big green image
                  expect(coordinates[greenIndex].x).toEqual(0.0 / atlasWidth);
                  expect(coordinates[greenIndex].y).toEqual(2.0 / atlasHeight);
                  expect(coordinates[greenIndex].width).toEqual(4.0 / atlasWidth);
                  expect(coordinates[greenIndex].height).toEqual(4.0 / atlasHeight);
              });
          });
      });
  
      it('renders an atlas that dynamically resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) {
              expect(atlas.numberOfImages).toEqual(1);
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var blueCoords = coordinates[blueIndex];
              expectToRender(texture, blueCoords, [0, 0, 255, 255]);
  
              return atlas.addImage(bigGreenImage.src, bigGreenImage).then(function(greenIndex) {
                  expect(atlas.numberOfImages).toEqual(2);
  
                  var texture = atlas.texture;
                  var coordinates = atlas.textureCoordinates;
  
                  var blueCoords = coordinates[blueIndex];
                  expectToRender(texture, blueCoords, [0, 0, 255, 255]);
  
                  var greenCoords = coordinates[greenIndex];
                  expectToRender(texture, greenCoords, [0, 255, 0, 255]);
              });
          });
      });
  
      it('creates an atlas with smaller initialSize than first image', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(bigRedImage.src, bigRedImage).then(function(index) {
              expect(atlas.numberOfImages).toEqual(1);
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var atlasWidth = 32.0;
              var atlasHeight = 32.0;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              expect(coordinates[index].x).toEqual(0.0 / atlasWidth);
              expect(coordinates[index].y).toEqual(0.0 / atlasHeight);
              expect(coordinates[index].width).toEqual(16.0 / atlasWidth);
              expect(coordinates[index].height).toEqual(16.0 / atlasHeight);
          });
      });
  
      it('renders an atlas with smaller initialSize than first image', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          return atlas.addImage(bigRedImage.src, bigRedImage).then(function(index) {
              var texture = atlas.texture;
              var coords = atlas.textureCoordinates[index];
  
              expectToRender(texture, coords, [255, 0, 0, 255]);
          });
      });
  
      it('creates a two image atlas with non-zero borderWidthInPixels that resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 2,
              initialSize : new Cartesian2(2, 2)
          });
  
          var greenPromise = atlas.addImage(greenImage.src, greenImage);
          var bluePromise = atlas.addImage(blueImage.src, blueImage);
  
          return when.all([greenPromise, bluePromise], function(indices) {
              var greenIndex = indices.shift();
              var blueIndex = indices.shift();
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var atlasWidth = 10.0;
              var atlasHeight = 10.0;
              expect(atlas.borderWidthInPixels).toEqual(2);
              expect(atlas.numberOfImages).toEqual(2);
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              expect(coordinates[greenIndex].x).toEqual(atlas.borderWidthInPixels / atlasWidth);
              expect(coordinates[greenIndex].y).toEqual(atlas.borderWidthInPixels / atlasHeight);
              expect(coordinates[greenIndex].width).toEqual(1.0 / atlasWidth);
              expect(coordinates[greenIndex].height).toEqual(1.0 / atlasHeight);
  
              expect(coordinates[blueIndex].x).toEqual(5.0 / atlasWidth);
              expect(coordinates[blueIndex].y).toEqual(2.0 / atlasHeight);
              expect(coordinates[blueIndex].width).toEqual(1.0 / atlasWidth);
              expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight);
          });
      });
  
      it('renders a two image atlas with non-zero borderWidthInPixels that resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 2,
              initialSize : new Cartesian2(2, 2)
          });
  
          var greenPromise = atlas.addImage(greenImage.src, greenImage);
          var bluePromise = atlas.addImage(blueImage.src, blueImage);
  
          return when.all([greenPromise, bluePromise], function(indices) {
              var greenIndex = indices.shift();
              var blueIndex = indices.shift();
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var greenCoords = coordinates[greenIndex];
              var blueCoords = coordinates[blueIndex];
  
              expectToRender(texture, greenCoords, [0, 255, 0, 255]);
              expectToRender(texture, blueCoords, [0, 0, 255, 255]);
          });
      });
  
      it('creates an atlas with non-square initialSize that resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1.0, 1.0)
          });
  
          return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) {
              expect(atlas.numberOfImages).toEqual(1);
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
  
              var atlasWidth = 2;
              var atlasHeight = 8;
              expect(texture.width).toEqual(atlasWidth);
              expect(texture.height).toEqual(atlasHeight);
  
              expect(coordinates[index].x).toEqual(0.0 / atlasWidth);
              expect(coordinates[index].y).toEqual(0.0 / atlasHeight);
              expect(coordinates[index].width).toEqual(tallGreenImage.width / atlasWidth);
              expect(coordinates[index].height).toEqual(tallGreenImage.height / atlasHeight);
          });
      });
  
      it('renders an atlas with non-square initialSize that resizes', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1.0, 1.0)
          });
  
          return atlas.addImage(tallGreenImage.src, tallGreenImage).then(function(index) {
              var texture = atlas.texture;
              var coords = atlas.textureCoordinates[index];
  
              expectToRender(texture, coords, [0, 255, 0, 255]);
          });
      });
  
      it('renders an atlas that dynamically resizes twice', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          var bluePromise = atlas.addImage(blueImage.src, blueImage);
          var bigGreenPromise = atlas.addImage(bigGreenImage.src, bigGreenImage);
          var bigRedPromise = atlas.addImage(bigRedImage.src, bigRedImage);
  
          return when.all([bluePromise, bigGreenPromise, bigRedPromise], function(indices) {
              var blueIndex = indices.shift();
              var bigGreenIndex = indices.shift();
              var bigRedIndex = indices.shift();
  
              var texture = atlas.texture;
              var blueCoordinates = atlas.textureCoordinates[blueIndex];
              var bigGreenCoordinates = atlas.textureCoordinates[bigGreenIndex];
              var bigRedCoordinates = atlas.textureCoordinates[bigRedIndex];
  
              expectToRender(texture, blueCoordinates, [0, 0, 255, 255]);
              expectToRender(texture, bigGreenCoordinates, [0, 255, 0, 255]);
              expectToRender(texture, bigRedCoordinates, [255, 0, 0, 255]);
          });
      });
  
      it('promise resolves to index after calling addImage with Image', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(4, 4)
          });
  
          return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) {
              expect(blueIndex).toEqual(0);
  
              return atlas.addImage(greenImage.src, greenImage).then(function(greenIndex) {
                  expect(greenIndex).toEqual(1);
  
                  return atlas.addImage(blueImage.src, blueImage).then(function(index) {
                      expect(index).toEqual(blueIndex);
  
                      expect(atlas.numberOfImages).toEqual(2);
  
                      var texture = atlas.texture;
                      var coordinates = atlas.textureCoordinates;
  
                      var blueCoordinates = coordinates[blueIndex];
                      var greenCoordinates = coordinates[greenIndex];
  
                      expectToRender(texture, blueCoordinates, [0, 0, 255, 255]);
                      expectToRender(texture, greenCoordinates, [0, 255, 0, 255]);
                  });
              });
          });
      });
  
      it('creates an atlas with subregions', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          atlas.addImage(greenImage.src, greenImage);
  
          var promise1 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5));
          var promise2 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.5, 0.5, 0.5));
          var promise3 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.0, 0.5, 0.5));
          var promise4 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.5, 0.5, 0.5));
  
          return when.all([promise1, promise2, promise3, promise4], function(indices) {
              var index1 = indices.shift();
              var index2 = indices.shift();
              var index3 = indices.shift();
              var index4 = indices.shift();
  
              expect(atlas.numberOfImages).toEqual(5);
  
              var coordinates = atlas.textureCoordinates;
              var atlasWidth = 2.0;
              var atlasHeight = 2.0;
  
              expect(coordinates[index1].x).toEqual(0.0 / atlasWidth);
              expect(coordinates[index1].y).toEqual(0.0 / atlasHeight);
              expect(coordinates[index1].width).toEqual(0.5 / atlasWidth);
              expect(coordinates[index1].height).toEqual(0.5 / atlasHeight);
  
              expect(coordinates[index2].x).toEqual(0.0 / atlasWidth);
              expect(coordinates[index2].y).toEqual(0.5 / atlasHeight);
              expect(coordinates[index2].width).toEqual(0.5 / atlasWidth);
              expect(coordinates[index2].height).toEqual(0.5 / atlasHeight);
  
              expect(coordinates[index3].x).toEqual(0.5 / atlasWidth);
              expect(coordinates[index3].y).toEqual(0.0 / atlasHeight);
              expect(coordinates[index3].width).toEqual(0.5 / atlasWidth);
              expect(coordinates[index3].height).toEqual(0.5 / atlasHeight);
  
              expect(coordinates[index4].x).toEqual(0.5 / atlasWidth);
              expect(coordinates[index4].y).toEqual(0.5 / atlasHeight);
              expect(coordinates[index4].width).toEqual(0.5 / atlasWidth);
              expect(coordinates[index4].height).toEqual(0.5 / atlasHeight);
          });
      });
  
      it('creates an atlas that resizes with subregions', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              borderWidthInPixels : 0,
              initialSize : new Cartesian2(1, 1)
          });
  
          atlas.addImage(greenImage.src, greenImage);
  
          var promise1 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5));
          var promise2 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.5, 0.5, 0.5));
          var promise3 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.0, 0.5, 0.5));
          var promise4 = atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.5, 0.5, 0.5, 0.5));
  
          return when.all([promise1, promise2, promise3, promise4], function(indices) {
              var index1 = indices.shift();
              var index2 = indices.shift();
              var index3 = indices.shift();
              var index4 = indices.shift();
  
              expect(atlas.numberOfImages).toEqual(5);
  
              return atlas.addImage(blueImage.src, blueImage).then(function(blueIndex) {
                  expect(atlas.numberOfImages).toEqual(6);
  
                  var coordinates = atlas.textureCoordinates;
                  var atlasWidth = 2.0;
                  var atlasHeight = 2.0;
  
                  expect(coordinates[index1].x).toEqual(0.0 / atlasWidth);
                  expect(coordinates[index1].y).toEqual(0.0 / atlasHeight);
                  expect(coordinates[index1].width).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index1].height).toEqual(0.5 / atlasHeight);
  
                  expect(coordinates[index2].x).toEqual(0.0 / atlasWidth);
                  expect(coordinates[index2].y).toEqual(0.5 / atlasHeight);
                  expect(coordinates[index2].width).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index2].height).toEqual(0.5 / atlasHeight);
  
                  expect(coordinates[index3].x).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index3].y).toEqual(0.0 / atlasHeight);
                  expect(coordinates[index3].width).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index3].height).toEqual(0.5 / atlasHeight);
  
                  expect(coordinates[index4].x).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index4].y).toEqual(0.5 / atlasHeight);
                  expect(coordinates[index4].width).toEqual(0.5 / atlasWidth);
                  expect(coordinates[index4].height).toEqual(0.5 / atlasHeight);
  
                  expect(coordinates[blueIndex].x).toEqual(1.0 / atlasWidth);
                  expect(coordinates[blueIndex].y).toEqual(0.0 / atlasHeight);
                  expect(coordinates[blueIndex].width).toEqual(1.0 / atlasWidth);
                  expect(coordinates[blueIndex].height).toEqual(1.0 / atlasHeight);
              });
          });
      });
  
      it('creates a two image atlas using a url and a function', function() {
          atlas = new TextureAtlas({
              context : scene.context,
              pixelFormat : PixelFormat.RGBA,
              borderWidthInPixels : 0
          });
  
          var greenUrl = './Data/Images/Green.png';
          var greenPromise = atlas.addImage(greenUrl, greenUrl);
  
          var bluePromise = atlas.addImage('Blue Image', function(id) {
              expect(id).toEqual('Blue Image');
              return blueImage;
          });
  
          return when.all([greenPromise, bluePromise], function(results) {
              var greenIndex = results[0];
              var blueIndex = results[1];
  
              expect(atlas.numberOfImages).toEqual(2);
  
              var texture = atlas.texture;
              var coordinates = atlas.textureCoordinates;
              var blueCoordinates = coordinates[blueIndex];
              var greenCoordinates = coordinates[greenIndex];
  
              expectToRender(texture, blueCoordinates, [0, 0, 255, 255]);
              expectToRender(texture, greenCoordinates, [0, 255, 0, 255]);
  
              // after loading 'Blue Image', further adds should not call the function
  
              return atlas.addImage('Blue Image', function(id) {
                  throw 'should not get here';
              }).then(function(index) {
                  expect(index).toEqual(blueIndex);
              });
          });
      });
  
      it('GUID changes when atlas is modified', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          var guid1 = atlas.guid;
  
          return atlas.addImage(greenImage.src, greenImage).then(function(index) {
              var guid2 = atlas.guid;
              expect(guid1).not.toEqual(guid2);
  
              return atlas.addSubRegion(greenImage.src, new BoundingRectangle(0.0, 0.0, 0.5, 0.5)).then(function(index) {
                  var guid3 = atlas.guid;
                  expect(guid2).not.toEqual(guid3);
              });
          });
      });
  
      it('throws with a negative borderWidthInPixels', function() {
          expect(function() {
              atlas = new TextureAtlas({
                  context : scene.context,
                  borderWidthInPixels : -1
              });
          }).toThrowDeveloperError();
      });
  
      it('throws with a initialSize less than one', function() {
          expect(function() {
              atlas = new TextureAtlas({
                  context : scene.context,
                  initialSize : new Cartesian2(0, 0)
              });
          }).toThrowDeveloperError();
      });
  
      it('throws without context', function() {
          expect(function() {
              return new TextureAtlas({});
          }).toThrowDeveloperError();
      });
  
      it('addImage throws without id', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
          expect(function() {
              atlas.addImage(undefined, blueImage);
          }).toThrowDeveloperError();
      });
  
      it('addImage throws without image', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          expect(function() {
              atlas.addImage('./Data/Images/Green.png', undefined);
          }).toThrowDeveloperError();
      });
  
      it('addSubRegion throws without id', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          expect(function() {
              atlas.addSubRegion(undefined, new BoundingRectangle());
          }).toThrowDeveloperError();
      });
  
      it('addSubRegion throws without subregion', function() {
          atlas = new TextureAtlas({
              context : scene.context
          });
  
          expect(function() {
              atlas.addSubRegion('asdf', undefined);
          }).toThrowDeveloperError();
      });
  }, 'WebGL');
  