OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright 2014 Google Inc. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license that can be | |
5 * found in the LICENSE file. | |
6 */ | |
7 | |
8 #include "SkColorPriv.h" | |
9 #include "SkImageDecoder.h" | |
10 #include "SkScaledBitmapSampler.h" | |
11 #include "SkStream.h" | |
12 #include "SkStreamHelpers.h" | |
13 #include "SkTypes.h" | |
14 | |
15 #include "ktx.h" | |
16 #include "etc1.h" | |
17 | |
18 //////////////////////////////////////////////////////////////////////////////// ///////// | |
19 | |
20 | |
21 //////////////////////////////////////////////////////////////////////////////// ///////// | |
22 | |
23 // KTX Image decoder | |
24 // --- | |
25 // KTX is a general texture data storage file format ratified by the Khronos Gro up. As an | |
26 // overview, a KTX file contains all of the appropriate values needed to fully s pecify a | |
27 // texture in an OpenGL application, including the use of compressed data. | |
28 // | |
29 // This decoder is meant to be used with an SkDiscardablePixelRef so that GPU ba ckends | |
30 // can sniff the data before creating a texture. If they encounter a compressed format | |
31 // that they understand, they can then upload the data directly to the GPU. Othe rwise, | |
32 // they will decode the data into a format that Skia supports. | |
33 | |
34 class SkKTXImageDecoder : public SkImageDecoder { | |
35 public: | |
36 SkKTXImageDecoder() { } | |
37 | |
38 virtual Format getFormat() const SK_OVERRIDE { | |
39 return kKTX_Format; | |
40 } | |
41 | |
42 protected: | |
43 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; | |
44 | |
45 private: | |
46 typedef SkImageDecoder INHERITED; | |
47 }; | |
48 | |
49 bool SkKTXImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) { | |
50 SkAutoDataUnref data(CopyStreamToData(stream)); | |
hal.canary
2014/06/03 19:22:48
// TODO: We should implement SkStream::copyToData(
krajcevski
2014/06/03 19:46:52
Done.
| |
51 if (NULL == data) { | |
52 return false; | |
53 } | |
54 | |
55 SkKTXFile ktxFile(data); | |
56 if (!ktxFile.valid()) { | |
57 return false; | |
58 } | |
59 | |
60 const unsigned short width = ktxFile.width(); | |
61 const unsigned short height = ktxFile.height(); | |
62 | |
63 // should we allow the Chooser (if present) to pick a config for us??? | |
64 if (!this->chooseFromOneChoice(SkBitmap::kARGB_8888_Config, width, height)) { | |
65 return false; | |
66 } | |
67 | |
68 // Setup the sampler... | |
69 SkScaledBitmapSampler sampler(width, height, this->getSampleSize()); | |
70 | |
71 // Set the config... | |
72 bm->setConfig(SkBitmap::kARGB_8888_Config, | |
73 sampler.scaledWidth(), sampler.scaledHeight(), | |
74 0, | |
75 ktxFile.isRGBA8()? kUnpremul_SkAlphaType : kOpaque_SkAlphaType ); | |
76 if (SkImageDecoder::kDecodeBounds_Mode == mode) { | |
77 return true; | |
78 } | |
79 | |
80 // If we've made it this far, then we know how to grok the data. | |
81 if (!this->allocPixelRef(bm, NULL)) { | |
82 return false; | |
83 } | |
84 | |
85 // Lock the pixels, since we're about to write to them... | |
86 SkAutoLockPixels alp(*bm); | |
87 | |
88 if (ktxFile.isETC1()) { | |
89 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { | |
90 return false; | |
91 } | |
92 | |
93 // ETC1 Data is encoded as RGB pixels, so we should extract it as such | |
94 int nPixels = width * height; | |
95 SkAutoMalloc outRGBData(nPixels * 3); | |
96 etc1_byte *outRGBDataPtr = reinterpret_cast<etc1_byte *>(outRGBData.get( )); | |
97 | |
98 // Decode ETC1 | |
99 const etc1_byte *buf = reinterpret_cast<const etc1_byte *>(ktxFile.pixel Data()); | |
100 if (etc1_decode_image(buf, outRGBDataPtr, width, height, 3, width*3)) { | |
101 return false; | |
102 } | |
103 | |
104 // Set each of the pixels... | |
105 const int srcRowBytes = width * 3; | |
106 const int dstHeight = sampler.scaledHeight(); | |
107 const uint8_t *srcRow = reinterpret_cast<uint8_t *>(outRGBDataPtr); | |
108 srcRow += sampler.srcY0() * srcRowBytes; | |
109 for (int y = 0; y < dstHeight; ++y) { | |
110 sampler.next(srcRow); | |
111 srcRow += sampler.srcDY() * srcRowBytes; | |
112 } | |
113 | |
114 return true; | |
115 | |
116 } else if (ktxFile.isRGB8()) { | |
117 | |
118 // Uncompressed RGB data (without alpha) | |
119 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) { | |
120 return false; | |
121 } | |
122 | |
123 // Just need to read RGB pixels | |
124 const int srcRowBytes = width * 3; | |
125 const int dstHeight = sampler.scaledHeight(); | |
126 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD ata()); | |
127 srcRow += sampler.srcY0() * srcRowBytes; | |
128 for (int y = 0; y < dstHeight; ++y) { | |
129 sampler.next(srcRow); | |
130 srcRow += sampler.srcDY() * srcRowBytes; | |
131 } | |
132 | |
133 return true; | |
134 | |
135 } else if (ktxFile.isRGBA8()) { | |
136 | |
137 // Uncompressed RGBA data | |
138 if (!sampler.begin(bm, SkScaledBitmapSampler::kRGBA, *this)) { | |
139 return false; | |
140 } | |
141 | |
142 // Just need to read RGBA pixels | |
143 const int srcRowBytes = width * 4; | |
144 const int dstHeight = sampler.scaledHeight(); | |
145 const uint8_t *srcRow = reinterpret_cast<const uint8_t *>(ktxFile.pixelD ata()); | |
146 srcRow += sampler.srcY0() * srcRowBytes; | |
147 for (int y = 0; y < dstHeight; ++y) { | |
148 sampler.next(srcRow); | |
149 srcRow += sampler.srcDY() * srcRowBytes; | |
150 } | |
151 | |
152 return true; | |
153 } | |
154 | |
155 return false; | |
156 } | |
157 | |
158 //////////////////////////////////////////////////////////////////////////////// ///////// | |
159 DEFINE_DECODER_CREATOR(KTXImageDecoder); | |
160 //////////////////////////////////////////////////////////////////////////////// ///////// | |
161 | |
162 static SkImageDecoder* sk_libktx_dfactory(SkStreamRewindable* stream) { | |
163 if (SkKTXFile::is_ktx(stream)) { | |
164 return SkNEW(SkKTXImageDecoder); | |
165 } | |
166 return NULL; | |
167 } | |
168 | |
169 static SkImageDecoder_DecodeReg gReg(sk_libktx_dfactory); | |
170 | |
171 static SkImageDecoder::Format get_format_ktx(SkStreamRewindable* stream) { | |
172 if (SkKTXFile::is_ktx(stream)) { | |
173 return SkImageDecoder::kKTX_Format; | |
174 } | |
175 return SkImageDecoder::kUnknown_Format; | |
176 } | |
177 | |
178 static SkImageDecoder_FormatReg gFormatReg(get_format_ktx); | |
OLD | NEW |