text: import { Cartesian3, defined } from "../Source/Cesium.js";
  import { ComputeEngine } from "../Source/Cesium.js";
  import { Pass } from "../Source/Cesium.js";
  import { OctahedralProjectedCubeMap } from "../Source/Cesium.js";
  import createContext from "../createContext.js";
  import createFrameState from "../createFrameState.js";
  import pollToPromise from "../pollToPromise.js";
  
  describe(
    "Scene/OctahedralProjectedCubeMap",
    function () {
      var context;
      var computeEngine;
      var octahedralMap;
  
      var environmentMapUrl =
        "./Data/EnvironmentMap/kiara_6_afternoon_2k_ibl.ktx2";
      var fsOctahedralMap =
        "uniform sampler2D projectedMap;" +
        "uniform vec2 textureSize;" +
        "uniform vec3 direction;" +
        "uniform float lod;" +
        "uniform float maxLod;" +
        "void main() {" +
        "   vec3 color = czm_sampleOctahedralProjection(projectedMap, textureSize, direction, lod, maxLod);" +
        "   gl_FragColor = vec4(color, 1.0);" +
        "}";
  
      var fsCubeMap =
        "uniform samplerCube cubeMap;" +
        "uniform vec3 direction;" +
        "void main() {" +
        "   vec4 rgba = textureCube(cubeMap, direction);" +
        "   gl_FragColor = vec4(rgba.rgb, 1.0);" +
        "}";
  
      beforeAll(function () {
        context = createContext();
        computeEngine = new ComputeEngine(context);
      });
  
      afterAll(function () {
        context.destroyForSpecs();
        computeEngine.destroy();
      });
  
      afterEach(function () {
        octahedralMap = octahedralMap && octahedralMap.destroy();
        context.textureCache.destroyReleasedTextures();
      });
  
      function executeCommands(frameState) {
        var length = frameState.commandList.length;
        for (var i = 0; i < length; ++i) {
          var command = frameState.commandList[i];
          if (command.pass === Pass.COMPUTE) {
            command.execute(computeEngine);
          } else {
            command.execute(context);
          }
        }
        frameState.commandList.length = 0;
      }
  
      function sampleOctahedralMap(octahedralMap, direction, lod, callback) {
        expect({
          context: context,
          fragmentShader: fsOctahedralMap,
          uniformMap: {
            projectedMap: function () {
              return octahedralMap.texture;
            },
            textureSize: function () {
              return octahedralMap.texture.dimensions;
            },
            direction: function () {
              return direction;
            },
            lod: function () {
              return lod;
            },
            maxLod: function () {
              return octahedralMap.maximumMipmapLevel;
            },
          },
        }).contextToRenderAndCall(callback);
      }
  
      function sampleCubeMap(cubeMap, direction, callback) {
        expect({
          context: context,
          fragmentShader: fsCubeMap,
          uniformMap: {
            cubeMap: function () {
              return cubeMap;
            },
            direction: function () {
              return direction;
            },
          },
        }).contextToRenderAndCall(callback);
      }
  
      function expectCubeMapAndOctahedralMapEqual(octahedralMap, direction, lod) {
        return sampleCubeMap(octahedralMap._cubeMaps[lod], direction, function (
          cubeMapColor
        ) {
          var directionFlipY = direction.clone();
          directionFlipY.y *= -1;
  
          sampleOctahedralMap(octahedralMap, directionFlipY, lod, function (
            octahedralMapColor
          ) {
            return expect(cubeMapColor).toEqualEpsilon(octahedralMapColor, 6);
          });
        });
      }
  
      it("creates a packed texture with the right dimensions", function () {
        if (!OctahedralProjectedCubeMap.isSupported(context)) {
          return;
        }
  
        octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl);
        var frameState = createFrameState(context);
  
        return pollToPromise(function () {
          octahedralMap.update(frameState);
          return octahedralMap.ready;
        }).then(function () {
          expect(octahedralMap.texture.width).toEqual(770);
          expect(octahedralMap.texture.height).toEqual(512);
          expect(octahedralMap.maximumMipmapLevel).toEqual(5);
        });
      });
  
      it("correctly projects the given cube map and all mip levels", function () {
        if (!OctahedralProjectedCubeMap.isSupported(context)) {
          return;
        }
  
        octahedralMap = new OctahedralProjectedCubeMap(environmentMapUrl);
        var frameState = createFrameState(context);
  
        return pollToPromise(function () {
          // We manually call update and execute the commands
          // because calling scene.renderForSpecs does not
          // actually execute these commands, and we need
          // to get the output of the texture.
          octahedralMap.update(frameState);
          executeCommands(frameState);
  
          return octahedralMap.ready;
        }).then(function () {
          var directions = {
            positiveX: new Cartesian3(1, 0, 0),
            negativeX: new Cartesian3(-1, 0, 0),
            positiveY: new Cartesian3(0, 1, 0),
            negativeY: new Cartesian3(0, -1, 0),
            positiveZ: new Cartesian3(0, 0, 1),
            negativeZ: new Cartesian3(0, 0, -1),
          };
  
          for (
            var mipLevel = 0;
            mipLevel < octahedralMap.maximumMipmapLevel;
            mipLevel++
          ) {
            for (var key in directions) {
              if (directions.hasOwnProperty(key)) {
                var direction = directions[key];
  
                expectCubeMapAndOctahedralMapEqual(
                  octahedralMap,
                  direction,
                  mipLevel
                );
              }
            }
          }
        });
      });
  
      it("caches projected textures", function () {
        if (!OctahedralProjectedCubeMap.isSupported(context)) {
          return;
        }
  
        var projection = new OctahedralProjectedCubeMap(environmentMapUrl);
        var frameState = createFrameState(context);
  
        return pollToPromise(function () {
          projection.update(frameState);
          return projection.ready;
        })
          .then(function () {
            var projection2 = new OctahedralProjectedCubeMap(environmentMapUrl);
            projection2.update(frameState);
            expect(projection2.ready).toEqual(true);
            expect(projection.texture).toEqual(projection2.texture);
            projection2.destroy();
          })
          .always(function () {
            projection.destroy();
          });
      });
  
      it("rejects when environment map fails to load.", function () {
        if (!OctahedralProjectedCubeMap.isSupported(context)) {
          return;
        }
  
        var projection = new OctahedralProjectedCubeMap("http://invalid.url");
        var frameState = createFrameState(context);
        var error;
  
        projection.readyPromise
          .then(function () {
            fail("Should not resolve.");
          })
          .otherwise(function (e) {
            error = e;
            expect(error).toBeDefined();
            expect(projection.ready).toEqual(false);
          });
  
        return pollToPromise(function () {
          projection.update(frameState);
          return defined(error);
        });
      });
    },
    "WebGL"
  );
  