/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "Resources.h"
#include "SkCanvas.h"
#include "SkData.h"
#include "SkDecodingImageGenerator.h"
#include "SkImageDecoder.h"
#include "SkOSFile.h"

#ifndef SK_IGNORE_ETC1_SUPPORT

#include "etc1.h"

/**
 *  Remove the last row and column of ETC1 blocks, effectively
 *  making a texture that started as power of two into a texture
 *  that is no longer power of two...
 */
bool slice_etc1_data(void *data, int* width, int* height) {

    // First, parse the data and get to it...
    etc1_byte *origData = reinterpret_cast<etc1_byte *>(data);
    if (!etc1_pkm_is_valid(origData)) {
        return false;
    }

    int origW = etc1_pkm_get_width(origData);
    int origH = etc1_pkm_get_height(origData);

    int blockWidth = (origW + 3) >> 2;
    int blockHeight = (origH + 3) >> 2;

    // Make sure that we have blocks to trim off..
    if (blockWidth < 2 || blockHeight < 2) {
        return false;
    }

    int newWidth = (blockWidth - 1) << 2;
    int newHeight = (blockHeight - 1) << 2;

    size_t newDataSz = etc1_get_encoded_data_size(newWidth, newHeight) + ETC_PKM_HEADER_SIZE;
    SkAutoMalloc am(newDataSz);

    etc1_byte *newData = reinterpret_cast<etc1_byte *>(am.get());

    etc1_pkm_format_header(newData, newWidth, newHeight);
    newData += ETC_PKM_HEADER_SIZE;
    origData += ETC_PKM_HEADER_SIZE;

    for (int j = 0; j < blockHeight - 1; ++j) {
        memcpy(newData, origData, (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE);
        origData += blockWidth*ETC1_ENCODED_BLOCK_SIZE;
        newData += (blockWidth - 1)*ETC1_ENCODED_BLOCK_SIZE;
    }

    // Stick the data back whence it came
    memcpy(data, am.get(), newDataSz);
    *width = newWidth;
    *height = newHeight;

    return true;
}
#endif  // SK_IGNORE_ETC1_SUPPORT

namespace skiagm {

/**
 *  Test decoding an image from a PKM or KTX file and then
 *  from compressed ETC1 data.
 */
class ETC1BitmapGM : public GM {
public:
    ETC1BitmapGM() { }
    virtual ~ETC1BitmapGM() { }

protected:
    virtual SkString onShortName() SK_OVERRIDE {
        SkString str = SkString("etc1bitmap_");
        str.append(this->fileExtension());
        return str;
    }

    virtual SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(128, 128);
    }

    virtual SkString fileExtension() const = 0;

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        SkBitmap bm;
        SkString resourcePath = GetResourcePath();
        SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.");
        filename.append(this->fileExtension());

        SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(filename.c_str()));
        if (NULL == fileData) {
            SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
            return;
        }

        if (!SkInstallDiscardablePixelRef(
                SkDecodingImageGenerator::Create(
                    fileData, SkDecodingImageGenerator::Options()), &bm)) {
            SkDebugf("Could not install discardable pixel ref.\n");
            return;
        }

        canvas->drawBitmap(bm, 0, 0);
    }

private:
    typedef GM INHERITED;
};

// This class specializes ETC1BitmapGM to load the mandrill_128.pkm file.
class ETC1Bitmap_PKM_GM : public ETC1BitmapGM {
public:
    ETC1Bitmap_PKM_GM() : ETC1BitmapGM() { }
    virtual ~ETC1Bitmap_PKM_GM() { }

protected:

    virtual SkString fileExtension() const SK_OVERRIDE { return SkString("pkm"); }

private:
    typedef ETC1BitmapGM INHERITED;
};

// This class specializes ETC1BitmapGM to load the mandrill_128.ktx file.
class ETC1Bitmap_KTX_GM : public ETC1BitmapGM {
public:
    ETC1Bitmap_KTX_GM() : ETC1BitmapGM() { }
    virtual ~ETC1Bitmap_KTX_GM() { }

protected:

    virtual SkString fileExtension() const SK_OVERRIDE { return SkString("ktx"); }

private:
    typedef ETC1BitmapGM INHERITED;
};

#ifndef SK_IGNORE_ETC1_SUPPORT
/**
 *  Test decoding an image from a PKM file and then
 *  from non-power-of-two compressed ETC1 data. First slice
 *  off a row and column of blocks in order to make it non-power
 *  of two.
 */
class ETC1Bitmap_NPOT_GM : public GM {
public:
    ETC1Bitmap_NPOT_GM() { }
    virtual ~ETC1Bitmap_NPOT_GM() { }

protected:
    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("etc1bitmap_npot");
    }

    virtual SkISize onISize() SK_OVERRIDE {
        return SkISize::Make(124, 124);
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        SkBitmap bm;
        SkString resourcePath = GetResourcePath();
        SkString filename = SkOSPath::SkPathJoin(resourcePath.c_str(), "mandrill_128.pkm");

        SkAutoDataUnref fileData(SkData::NewFromFileName(filename.c_str()));
        if (NULL == fileData) {
            SkDebugf("Could not open the file. Did you forget to set the resourcePath?\n");
            return;
        }

        SkAutoMalloc am(fileData->size());
        memcpy(am.get(), fileData->data(), fileData->size());

        int width, height;
        if (!slice_etc1_data(am.get(), &width, &height)) {
            SkDebugf("ETC1 Data is poorly formatted.\n");
            return;
        }

        SkASSERT(124 == width);
        SkASSERT(124 == height);

        size_t dataSz = etc1_get_encoded_data_size(width, height) + ETC_PKM_HEADER_SIZE;
        SkAutoDataUnref nonPOTData(SkData::NewWithCopy(am.get(), dataSz));

        if (!SkInstallDiscardablePixelRef(
                SkDecodingImageGenerator::Create(
                    nonPOTData, SkDecodingImageGenerator::Options()), &bm)) {
            SkDebugf("Could not install discardable pixel ref.\n");
            return;
        }

        canvas->drawBitmap(bm, 0, 0);
    }

private:
    typedef GM INHERITED;
};
#endif  // SK_IGNORE_ETC1_SUPPORT

}  // namespace skiagm

//////////////////////////////////////////////////////////////////////////////

DEF_GM( return SkNEW(skiagm::ETC1Bitmap_PKM_GM); )
DEF_GM( return SkNEW(skiagm::ETC1Bitmap_KTX_GM); )

#ifndef SK_IGNORE_ETC1_SUPPORT
DEF_GM( return SkNEW(skiagm::ETC1Bitmap_NPOT_GM); )
#endif  // SK_IGNORE_ETC1_SUPPORT
