//
//   Copyright 2013 Pixar
//
//   Licensed under the Apache License, Version 2.0 (the "Apache License")
//   with the following modification; you may not use this file except in
//   compliance with the Apache License and the following modification to it:
//   Section 6. Trademarks. is deleted and replaced with:
//
//   6. Trademarks. This License does not grant permission to use the trade
//      names, trademarks, service marks, or product names of the Licensor
//      and its affiliates, except as required to comply with Section 4(c) of
//      the License and to reproduce the content of the NOTICE file.
//
//   You may obtain a copy of the Apache License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the Apache License with the above modification is
//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
//   KIND, either express or implied. See the Apache License for the specific
//   language governing permissions and limitations under the Apache License.
//

#ifndef OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H
#define OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H

#include <Ptexture.h>
#include <stdlib.h>
#include <stdint.h>
#include <vector>


class PtexMipmapTextureLoader {
public:
    PtexMipmapTextureLoader(PtexTexture *ptex,
                               int maxNumPages,
                               int maxLevels = -1,
                               size_t targetMemory = 0,
                               bool seamlessMipmap = true,
                               bool padAlpha = false);

    ~PtexMipmapTextureLoader();

    const unsigned char * GetLayoutBuffer() const {
        return _layoutBuffer;
    }
    const unsigned char * GetTexelBuffer() const {
        return _texelBuffer;
    }
    int GetNumFaces() const {
        return (int)_blocks.size();
    }
    int GetNumPages() const {
        return (int)_pages.size();
    }
    int GetPageWidth() const {
        return _pageWidth;
    }
    int GetPageHeight() const {
        return _pageHeight;
    }
    size_t GetMemoryUsage() const {
        return _memoryUsage;
    }

/*
  block : atomic texture unit
  XXX: face of 128x128 or more (64kb~) texels should be considered separately
       using ARB_sparse_texture...?

  . : per-face texels for each mipmap level
  x : guttering pixel

  xxxxxxxxxxxxxx
  x........xx..x 2x2
  x........xx..x
  x........xxxxx
  x..8x8...xxxxxxx
  x........xx....x
  x........xx....x 4x4
  x........xx....x
  x........xx....x
  xxxxxxxxxxxxxxxx

  For each face (w*h), texels with guttering and mipmap is stored into
  (w+2+w/2+2)*(h+2) area as above.

 */

/*
  Ptex loader

  Texels buffer : the packed texels

 */

private:
    struct Block {
        int index;                 // ptex index
        int nMipmaps;
        uint16_t u, v;             // top-left texel offset
        uint16_t width, height;    // texel dimension (includes mipmap)
        uint16_t adjSizeDiffs;     // maximum tile size difference around each vertices
        int8_t   ulog2, vlog2;     // texel dimension log2 (original tile)

        void Generate(PtexMipmapTextureLoader *loader, PtexTexture *ptex,
                      unsigned char *destination,
                      int bpp, int width, int maxLevels);

        void SetSize(unsigned char ulog2_, unsigned char vlog2_, bool mipmap);

        int GetNumTexels() const {
            return width*height;
        }

        void guttering(PtexMipmapTextureLoader *loader, PtexTexture *ptex,
                       int level, int width, int height,
                       unsigned char *pptr, int bpp, int stride);

        static bool sort(const Block *a, const Block *b) {
            return (a->height > b->height) ||
                   ((a->height == b->height) && (a->width > b->width));
        }
    };

    struct Page;
    class CornerIterator;

    void generateBuffers();
    void optimizePacking(int maxNumPages, size_t targetMemory);
    int  getLevelDiff(int face, int edge);
    bool getCornerPixel(float *resultPixel, int numchannels,
                        int face, int edge, int8_t res);
    void sampleNeighbor(unsigned char *border,
                        int face, int edge, int length, int bpp);
    int  resampleBorder(int face, int edgeId, unsigned char *result,
                        int dstLength, int bpp,
                        float srcStart = 0.0f, float srcEnd = 1.0f);
    void addAlphaChannel();

    std::vector<Block> _blocks;
    std::vector<Page *> _pages;

    PtexTexture *_ptex;
    int _maxLevels;
    int _bpp;
    int _pageWidth, _pageHeight;

    unsigned char *_texelBuffer;
    unsigned char *_layoutBuffer;

    size_t _memoryUsage;
};

#endif // OPENSUBDIV_EXAMPLES_PTEX_MIPMAP_TEXTURE_LOADER_H
