blob: 3aaea157269cea6e273f1bb0690587a8ff943f4b [file] [log] [blame]
/*
* Copyright 2014 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkKTXFile_DEFINED
#define SkKTXFile_DEFINED
#include "SkData.h"
#include "SkTextureCompressor.h"
#include "SkTypes.h"
#include "SkTDArray.h"
#include "SkString.h"
#include "SkRefCnt.h"
class SkBitmap;
class SkPixmap;
class SkStreamRewindable;
class SkWStream;
// KTX Image File
// ---
// KTX is a general texture data storage file format ratified by the Khronos Group. As an
// overview, a KTX file contains all of the appropriate values needed to fully specify a
// texture in an OpenGL application, including the use of compressed data.
//
// A full format specification can be found here:
// http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
class SkKTXFile {
public:
// The ownership of the data remains with the caller. This class is intended
// to be used as a logical wrapper around the data in order to properly
// access the pixels.
SkKTXFile(SkData* data) : fData(data), fSwapBytes(false) {
data->ref();
fValid = this->readKTXFile(fData->bytes(), fData->size());
}
bool valid() const { return fValid; }
int width() const { return static_cast<int>(fHeader.fPixelWidth); }
int height() const { return static_cast<int>(fHeader.fPixelHeight); }
const uint8_t *pixelData(int mipmap = 0) const {
SkASSERT(!this->valid() || mipmap < fPixelData.count());
return this->valid() ? fPixelData[mipmap].data() : NULL;
}
// If the decoded KTX file has the following key, then it will
// return the associated value. If not found, the empty string
// is returned.
SkString getValueForKey(const SkString& key) const;
int numMipmaps() const { return static_cast<int>(fHeader.fNumberOfMipmapLevels); }
bool isCompressedFormat(SkTextureCompressor::Format fmt) const;
bool isRGBA8() const;
bool isRGB8() const;
static bool is_ktx(const uint8_t data[], size_t size);
static bool is_ktx(SkStreamRewindable* stream);
static bool WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
uint32_t width, uint32_t height);
static bool WritePixmapToKTX(SkWStream* stream, const SkPixmap& pixmap);
static bool WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap);
private:
// The blob holding the file data.
sk_sp<SkData> fData;
// This header captures all of the data that describes the format
// of the image data in a KTX file.
struct Header {
uint32_t fGLType;
uint32_t fGLTypeSize;
uint32_t fGLFormat;
uint32_t fGLInternalFormat;
uint32_t fGLBaseInternalFormat;
uint32_t fPixelWidth;
uint32_t fPixelHeight;
uint32_t fPixelDepth;
uint32_t fNumberOfArrayElements;
uint32_t fNumberOfFaces;
uint32_t fNumberOfMipmapLevels;
uint32_t fBytesOfKeyValueData;
Header() { memset(this, 0, sizeof(*this)); }
} fHeader;
// A Key Value pair stored in the KTX file. There may be
// arbitrarily many of these.
class KeyValue {
public:
KeyValue(size_t size) : fDataSz(size) { }
bool readKeyAndValue(const uint8_t *data);
size_t size() const { return fDataSz; }
const SkString& key() const { return fKey; }
const SkString& value() const { return fValue; }
bool writeKeyAndValueForKTX(SkWStream* strm);
private:
const size_t fDataSz;
SkString fKey;
SkString fValue;
};
static KeyValue CreateKeyValue(const char *key, const char *value);
// The pixel data for a single mipmap level in an image. Based on how
// the rest of the data is stored, this may be compressed, a cubemap, etc.
// The header will describe the format of this data.
class PixelData {
public:
PixelData(const uint8_t *ptr, size_t sz) : fDataSz(sz), fDataPtr(ptr) { }
const uint8_t *data() const { return fDataPtr; }
size_t dataSize() const { return fDataSz; }
private:
const size_t fDataSz;
const uint8_t *fDataPtr;
};
// This function is only called once from the constructor. It loads the data
// and populates the appropriate fields of this class
// (fKeyValuePairs, fPixelData, fSwapBytes)
bool readKTXFile(const uint8_t *data, size_t dataLen);
SkTArray<KeyValue> fKeyValuePairs;
SkTDArray<PixelData> fPixelData;
bool fValid;
// If the endianness of the platform is different than the file,
// then we need to do proper byte swapping.
bool fSwapBytes;
// Read an integer from a buffer, advance the buffer, and swap
// bytes if fSwapBytes is set
uint32_t readInt(const uint8_t** buf, size_t* bytesLeft) const;
};
#endif // SkKTXFile_DEFINED