1
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkKTXFile_DEFINED
11#define SkKTXFile_DEFINED
12
13#include "SkData.h"
14#include "SkTextureCompressor.h"
15#include "SkTypes.h"
16#include "SkTDArray.h"
17#include "SkString.h"
18#include "SkRefCnt.h"
19
20class SkBitmap;
21class SkStreamRewindable;
22class SkWStream;
23
24// KTX Image File
25// ---
26// KTX is a general texture data storage file format ratified by the Khronos Group. As an
27// overview, a KTX file contains all of the appropriate values needed to fully specify a
28// texture in an OpenGL application, including the use of compressed data.
29//
30// A full format specification can be found here:
31// http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
32
33class SkKTXFile {
34public:
35    // The ownership of the data remains with the caller. This class is intended
36    // to be used as a logical wrapper around the data in order to properly
37    // access the pixels.
38    SkKTXFile(SkData* data)
39        : fData(data), fSwapBytes(false)
40    {
41        data->ref();
42        fValid = this->readKTXFile(fData->bytes(), fData->size());
43    }
44
45    bool valid() const { return fValid; }
46
47    int width() const { return static_cast<int>(fHeader.fPixelWidth); }
48    int height() const { return static_cast<int>(fHeader.fPixelHeight); }
49
50    const uint8_t *pixelData(int mipmap = 0) const {
51        SkASSERT(!this->valid() || mipmap < fPixelData.count());
52        return this->valid() ? fPixelData[mipmap].data() : NULL;
53    }
54
55    // If the decoded KTX file has the following key, then it will
56    // return the associated value. If not found, the empty string
57    // is returned.
58    SkString getValueForKey(const SkString& key) const;
59
60    int numMipmaps() const { return static_cast<int>(fHeader.fNumberOfMipmapLevels); }
61
62    bool isCompressedFormat(SkTextureCompressor::Format fmt) const;
63    bool isRGBA8() const;
64    bool isRGB8() const;
65
66    static bool is_ktx(const uint8_t *data);
67    static bool is_ktx(SkStreamRewindable* stream);
68
69    static bool WriteETC1ToKTX(SkWStream* stream, const uint8_t *etc1Data,
70                               uint32_t width, uint32_t height);
71    static bool WriteBitmapToKTX(SkWStream* stream, const SkBitmap& bitmap);
72private:
73
74    // The blob holding the file data.
75    SkAutoTUnref<SkData> fData;
76
77    // This header captures all of the data that describes the format
78    // of the image data in a KTX file.
79    struct Header {
80        uint32_t fGLType;
81        uint32_t fGLTypeSize;
82        uint32_t fGLFormat;
83        uint32_t fGLInternalFormat;
84        uint32_t fGLBaseInternalFormat;
85        uint32_t fPixelWidth;
86        uint32_t fPixelHeight;
87        uint32_t fPixelDepth;
88        uint32_t fNumberOfArrayElements;
89        uint32_t fNumberOfFaces;
90        uint32_t fNumberOfMipmapLevels;
91        uint32_t fBytesOfKeyValueData;
92
93        Header() { memset(this, 0, sizeof(*this)); }
94    } fHeader;
95
96    // A Key Value pair stored in the KTX file. There may be
97    // arbitrarily many of these.
98    class KeyValue {
99    public:
100        KeyValue(size_t size) : fDataSz(size) { }
101        bool readKeyAndValue(const uint8_t *data);
102        size_t size() const { return fDataSz; }
103        const SkString& key() const { return fKey; }
104        const SkString& value() const { return fValue; }
105        bool writeKeyAndValueForKTX(SkWStream* strm);
106    private:
107        const size_t fDataSz;
108        SkString     fKey;
109        SkString     fValue;
110    };
111
112    static KeyValue CreateKeyValue(const char *key, const char *value);
113
114    // The pixel data for a single mipmap level in an image. Based on how
115    // the rest of the data is stored, this may be compressed, a cubemap, etc.
116    // The header will describe the format of this data.
117    class PixelData {
118    public:
119        PixelData(const uint8_t *ptr, size_t sz) : fDataSz(sz), fDataPtr(ptr) { }
120        const uint8_t *data() const { return fDataPtr; }
121        size_t dataSize() const { return fDataSz; }
122    private:
123        const size_t fDataSz;
124        const uint8_t *fDataPtr;
125    };
126
127    // This function is only called once from the constructor. It loads the data
128    // and populates the appropriate fields of this class
129    // (fKeyValuePairs, fPixelData, fSwapBytes)
130    bool readKTXFile(const uint8_t *data, size_t dataLen);
131
132    SkTArray<KeyValue> fKeyValuePairs;
133    SkTDArray<PixelData> fPixelData;
134    bool fValid;
135
136    // If the endianness of the platform is different than the file,
137    // then we need to do proper byte swapping.
138    bool fSwapBytes;
139
140    // Read an integer from a buffer, advance the buffer, and swap
141    // bytes if fSwapBytes is set
142    uint32_t readInt(const uint8_t** buf, size_t* bytesLeft) const;
143};
144
145#endif  // SkKTXFile_DEFINED
146