2014-06-03 20:04:35 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
2014-08-05 21:13:36 +00:00
|
|
|
#include "SkTextureCompressor.h"
|
2014-06-03 20:04:35 +00:00
|
|
|
#include "SkTypes.h"
|
|
|
|
#include "SkTDArray.h"
|
|
|
|
#include "SkString.h"
|
|
|
|
#include "SkRefCnt.h"
|
|
|
|
|
2014-06-06 13:16:28 +00:00
|
|
|
class SkBitmap;
|
2014-06-03 20:04:35 +00:00
|
|
|
class SkStreamRewindable;
|
2014-06-06 13:16:28 +00:00
|
|
|
class SkWStream;
|
2014-06-03 20:04:35 +00:00
|
|
|
|
|
|
|
// 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.
|
2016-04-12 14:41:22 +00:00
|
|
|
SkKTXFile(SkData* data) : fData(data), fSwapBytes(false) {
|
2014-06-03 20:04:35 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-06-06 13:16:28 +00:00
|
|
|
// 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;
|
|
|
|
|
2014-06-03 20:04:35 +00:00
|
|
|
int numMipmaps() const { return static_cast<int>(fHeader.fNumberOfMipmapLevels); }
|
|
|
|
|
2014-08-05 21:13:36 +00:00
|
|
|
bool isCompressedFormat(SkTextureCompressor::Format fmt) const;
|
2014-06-03 20:04:35 +00:00
|
|
|
bool isRGBA8() const;
|
|
|
|
bool isRGB8() const;
|
|
|
|
|
2016-04-12 14:41:22 +00:00
|
|
|
static bool is_ktx(const uint8_t data[], size_t size);
|
2014-06-03 20:04:35 +00:00
|
|
|
static bool is_ktx(SkStreamRewindable* stream);
|
|
|
|
|
2014-06-06 13:16:28 +00:00
|
|
|
static bool WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
|
|
|
|
uint32_t width, uint32_t height);
|
|
|
|
static bool WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap);
|
2014-06-03 20:04:35 +00:00
|
|
|
private:
|
|
|
|
|
|
|
|
// The blob holding the file data.
|
|
|
|
SkAutoTUnref<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);
|
2014-06-06 13:16:28 +00:00
|
|
|
size_t size() const { return fDataSz; }
|
|
|
|
const SkString& key() const { return fKey; }
|
|
|
|
const SkString& value() const { return fValue; }
|
|
|
|
bool writeKeyAndValueForKTX(SkWStream* strm);
|
2014-06-03 20:04:35 +00:00
|
|
|
private:
|
|
|
|
const size_t fDataSz;
|
2014-06-06 13:16:28 +00:00
|
|
|
SkString fKey;
|
|
|
|
SkString fValue;
|
2014-06-03 20:04:35 +00:00
|
|
|
};
|
|
|
|
|
2014-06-06 13:16:28 +00:00
|
|
|
static KeyValue CreateKeyValue(const char *key, const char *value);
|
|
|
|
|
2014-06-03 20:04:35 +00:00
|
|
|
// 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
|