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 
20 class SkBitmap;
21 class SkStreamRewindable;
22 class 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 
33 class SkKTXFile {
34 public:
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.
SkKTXFile(SkData * data)38     SkKTXFile(SkData* data)
39         : fData(data), fSwapBytes(false)
40     {
41         data->ref();
42         fValid = this->readKTXFile(fData->bytes(), fData->size());
43     }
44 
valid()45     bool valid() const { return fValid; }
46 
width()47     int width() const { return static_cast<int>(fHeader.fPixelWidth); }
height()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 
numMipmaps()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);
72 private:
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 
HeaderHeader93         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:
KeyValue(size_t size)100         KeyValue(size_t size) : fDataSz(size) { }
101         bool readKeyAndValue(const uint8_t *data);
size()102         size_t size() const { return fDataSz; }
key()103         const SkString& key() const { return fKey; }
value()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:
PixelData(const uint8_t * ptr,size_t sz)119         PixelData(const uint8_t *ptr, size_t sz) : fDataSz(sz), fDataPtr(ptr) { }
data()120         const uint8_t *data() const { return fDataPtr; }
dataSize()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