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