//
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) Contributors to the OpenEXR Project.
//

//-----------------------------------------------------------------------------
//
//	function makeLatLongMap() -- makes latitude-longitude environment maps
//
//-----------------------------------------------------------------------------

#include <makeLatLongMap.h>

#include "Iex.h"
#include <ImfRgbaFile.h>
#include <ImfStandardAttributes.h>
#include <ImfTiledRgbaFile.h>
#include <algorithm>
#include <iostream>
#include <resizeImage.h>

#include "namespaceAlias.h"
using namespace IMF;
using namespace std;
using namespace IMATH;

void
makeLatLongMap (
    EnvmapImage&      image1,
    Header&           header,
    RgbaChannels      channels,
    const char        outFileName[],
    int               tileWidth,
    int               tileHeight,
    LevelMode         levelMode,
    LevelRoundingMode roundingMode,
    Compression       compression,
    int               mapWidth,
    float             filterRadius,
    int               numSamples,
    bool              verbose)
{
    if (levelMode == RIPMAP_LEVELS)
    {
        throw IEX::NoImplExc ("Cannot generate ripmap "
                              "latitude-longitude environments.");
    }

    //
    // Open the file that will contain the latitude-longitude map,
    // and write the header.
    //

    int mapHeight = mapWidth / 2;

    header.dataWindow () =
        Box2i (V2i (0, 0), V2i (mapWidth - 1, mapHeight - 1));
    header.displayWindow () = header.dataWindow ();
    header.compression ()   = compression;

    addEnvmap (header, ENVMAP_LATLONG);

    TiledRgbaOutputFile out (
        outFileName,
        header,
        channels,
        tileWidth,
        tileHeight,
        levelMode,
        roundingMode);
    if (verbose) cout << "writing file " << outFileName << endl;

    //
    // Generate the pixels for the various levels of the latitude-longitude
    // map, and store them in the file.  The pixels for the highest-resolution
    // level are generated by resampling the original input image; for each of
    // the other levels, the pixels are generated by resampling the previous
    // level.
    //

    EnvmapImage  image2;
    EnvmapImage* iptr1 = &image1;
    EnvmapImage* iptr2 = &image2;

    for (int level = 0; level < out.numLevels (); ++level)
    {
        if (verbose) cout << "level " << level << endl;

        Box2i dw = out.dataWindowForLevel (level);
        resizeLatLong (*iptr1, *iptr2, dw, filterRadius, numSamples);

        out.setFrameBuffer (&(iptr2->pixels ()[0][0]), 1, dw.max.x + 1);

        for (int tileY = 0; tileY < out.numYTiles (level); ++tileY)
            for (int tileX = 0; tileX < out.numXTiles (level); ++tileX)
                out.writeTile (tileX, tileY, level);

        swap (iptr1, iptr2);
    }

    if (verbose) cout << "done." << endl;
}
