1 /*
2 * Copyright 2015 The Etc2Comp Authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifdef _WIN32
18 #define _CRT_SECURE_NO_WARNINGS (1)
19 #endif
20
21 #include "EtcConfig.h"
22
23
24 #include "EtcFile.h"
25
26 #include "EtcFileHeader.h"
27 #include "EtcColor.h"
28 #include "Etc.h"
29 #include "EtcBlock4x4EncodingBits.h"
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <assert.h>
34 #include <stdlib.h>
35
36 using namespace Etc;
37
38 // ----------------------------------------------------------------------------------------------------
39 //
File(const char * a_pstrFilename,Format a_fileformat,Image::Format a_imageformat,unsigned char * a_paucEncodingBits,unsigned int a_uiEncodingBitsBytes,unsigned int a_uiSourceWidth,unsigned int a_uiSourceHeight,unsigned int a_uiExtendedWidth,unsigned int a_uiExtendedHeight)40 File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
41 unsigned char *a_paucEncodingBits, unsigned int a_uiEncodingBitsBytes,
42 unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight,
43 unsigned int a_uiExtendedWidth, unsigned int a_uiExtendedHeight)
44 {
45 if (a_pstrFilename == nullptr)
46 {
47 m_pstrFilename = const_cast<char *>("");
48 }
49 else
50 {
51 m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
52 strcpy(m_pstrFilename, a_pstrFilename);
53 }
54
55 m_fileformat = a_fileformat;
56 if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
57 {
58 // ***** TODO: add this later *****
59 m_fileformat = Format::KTX;
60 }
61
62 m_imageformat = a_imageformat;
63
64 m_uiNumMipmaps = 1;
65 m_pMipmapImages = new RawImage[m_uiNumMipmaps];
66 m_pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(a_paucEncodingBits, [](unsigned char *p) { delete[] p; } );
67 m_pMipmapImages[0].uiEncodingBitsBytes = a_uiEncodingBitsBytes;
68 m_pMipmapImages[0].uiExtendedWidth = a_uiExtendedWidth;
69 m_pMipmapImages[0].uiExtendedHeight = a_uiExtendedHeight;
70
71 m_uiSourceWidth = a_uiSourceWidth;
72 m_uiSourceHeight = a_uiSourceHeight;
73
74 switch (m_fileformat)
75 {
76 case Format::PKM:
77 m_pheader = new FileHeader_Pkm(this);
78 break;
79
80 case Format::KTX:
81 m_pheader = new FileHeader_Ktx(this);
82 break;
83
84 default:
85 assert(0);
86 break;
87 }
88
89 }
90
91 // ----------------------------------------------------------------------------------------------------
92 //
File(const char * a_pstrFilename,Format a_fileformat,Image::Format a_imageformat,unsigned int a_uiNumMipmaps,RawImage * a_pMipmapImages,unsigned int a_uiSourceWidth,unsigned int a_uiSourceHeight)93 File::File(const char *a_pstrFilename, Format a_fileformat, Image::Format a_imageformat,
94 unsigned int a_uiNumMipmaps, RawImage *a_pMipmapImages,
95 unsigned int a_uiSourceWidth, unsigned int a_uiSourceHeight)
96 {
97 if (a_pstrFilename == nullptr)
98 {
99 m_pstrFilename = const_cast<char *>("");
100 }
101 else
102 {
103 m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
104 strcpy(m_pstrFilename, a_pstrFilename);
105 }
106
107 m_fileformat = a_fileformat;
108 if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
109 {
110 // ***** TODO: add this later *****
111 m_fileformat = Format::KTX;
112 }
113
114 m_imageformat = a_imageformat;
115
116 m_uiNumMipmaps = a_uiNumMipmaps;
117 m_pMipmapImages = new RawImage[m_uiNumMipmaps];
118
119 for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
120 {
121 m_pMipmapImages[mip] = a_pMipmapImages[mip];
122 }
123
124 m_uiSourceWidth = a_uiSourceWidth;
125 m_uiSourceHeight = a_uiSourceHeight;
126
127 switch (m_fileformat)
128 {
129 case Format::PKM:
130 m_pheader = new FileHeader_Pkm(this);
131 break;
132
133 case Format::KTX:
134 m_pheader = new FileHeader_Ktx(this);
135 break;
136
137 default:
138 assert(0);
139 break;
140 }
141
142 }
143
144 // ----------------------------------------------------------------------------------------------------
145 //
File(const char * a_pstrFilename,Format a_fileformat)146 File::File(const char *a_pstrFilename, Format a_fileformat)
147 {
148 if (a_pstrFilename == nullptr)
149 {
150 return;
151 }
152 else
153 {
154 m_pstrFilename = new char[strlen(a_pstrFilename) + 1];
155 strcpy(m_pstrFilename, a_pstrFilename);
156 }
157
158 m_fileformat = a_fileformat;
159 if (m_fileformat == Format::INFER_FROM_FILE_EXTENSION)
160 {
161 // ***** TODO: add this later *****
162 m_fileformat = Format::KTX;
163 }
164
165 FILE *pfile = fopen(m_pstrFilename, "rb");
166 if (pfile == nullptr)
167 {
168 printf("ERROR: Couldn't open %s", m_pstrFilename);
169 exit(1);
170 }
171 fseek(pfile, 0, SEEK_END);
172 unsigned int fileSize = ftell(pfile);
173 fseek(pfile, 0, SEEK_SET);
174 size_t szResult;
175
176 m_pheader = new FileHeader_Ktx(this);
177 szResult = fread( ((FileHeader_Ktx*)m_pheader)->GetData(), 1, sizeof(FileHeader_Ktx::Data), pfile);
178 assert(szResult > 0);
179
180 m_uiNumMipmaps = 1;
181 m_pMipmapImages = new RawImage[m_uiNumMipmaps];
182
183 if (((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData > 0)
184 fseek(pfile, ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32BytesOfKeyValueData, SEEK_CUR);
185 szResult = fread(&m_pMipmapImages->uiEncodingBitsBytes, 1, sizeof(unsigned int), pfile);
186 assert(szResult > 0);
187
188 m_pMipmapImages->paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[m_pMipmapImages->uiEncodingBitsBytes], [](unsigned char *p) { delete[] p; } );
189 assert(ftell(pfile) + m_pMipmapImages->uiEncodingBitsBytes <= fileSize);
190 szResult = fread(m_pMipmapImages->paucEncodingBits.get(), 1, m_pMipmapImages->uiEncodingBitsBytes, pfile);
191 assert(szResult == m_pMipmapImages->uiEncodingBitsBytes);
192
193 uint32_t uiInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlInternalFormat;
194 uint32_t uiBaseInternalFormat = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32GlBaseInternalFormat;
195
196 if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC1_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC1_RGB8)
197 {
198 m_imageformat = Image::Format::ETC1;
199 }
200 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8)
201 {
202 m_imageformat = Image::Format::RGB8;
203 }
204 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGB8A1 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGB8A1)
205 {
206 m_imageformat = Image::Format::RGB8A1;
207 }
208 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RGBA8 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RGBA8)
209 {
210 m_imageformat = Image::Format::RGBA8;
211 }
212 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
213 {
214 m_imageformat = Image::Format::R11;
215 }
216 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_R11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_R11)
217 {
218 m_imageformat = Image::Format::SIGNED_R11;
219 }
220 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
221 {
222 m_imageformat = Image::Format::RG11;
223 }
224 else if (uiInternalFormat == (uint32_t)FileHeader_Ktx::InternalFormat::ETC2_SIGNED_RG11 && uiBaseInternalFormat == (uint32_t)FileHeader_Ktx::BaseInternalFormat::ETC2_RG11)
225 {
226 m_imageformat = Image::Format::SIGNED_RG11;
227 }
228 else
229 {
230 m_imageformat = Image::Format::UNKNOWN;
231 }
232
233 m_uiSourceWidth = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelWidth;
234 m_uiSourceHeight = ((FileHeader_Ktx*)m_pheader)->GetData()->m_u32PixelHeight;
235 m_pMipmapImages->uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
236 m_pMipmapImages->uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
237
238 unsigned int uiBlocks = m_pMipmapImages->uiExtendedWidth * m_pMipmapImages->uiExtendedHeight / 16;
239 Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
240 unsigned int expectedbytes = uiBlocks * Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
241 assert(expectedbytes == m_pMipmapImages->uiEncodingBitsBytes);
242
243 fclose(pfile);
244 }
245
~File()246 File::~File()
247 {
248 if (m_pMipmapImages != nullptr)
249 {
250 delete [] m_pMipmapImages;
251 }
252
253 if(m_pstrFilename != nullptr)
254 {
255 delete[] m_pstrFilename;
256 m_pstrFilename = nullptr;
257 }
258 if (m_pheader != nullptr)
259 {
260 delete m_pheader;
261 m_pheader = nullptr;
262 }
263 }
264
UseSingleBlock(int a_iPixelX,int a_iPixelY)265 void File::UseSingleBlock(int a_iPixelX, int a_iPixelY)
266 {
267 if (a_iPixelX <= -1 || a_iPixelY <= -1)
268 return;
269 if (a_iPixelX >(int) m_uiSourceWidth)
270 {
271 //if we are using a ktx thats the size of a single block or less
272 //then make sure we use the 4x4 image as the single block
273 if (m_uiSourceWidth <= 4)
274 {
275 a_iPixelX = 0;
276 }
277 else
278 {
279 printf("blockAtHV: H coordinate out of range, capped to image width\n");
280 a_iPixelX = m_uiSourceWidth - 1;
281 }
282 }
283 if (a_iPixelY >(int) m_uiSourceHeight)
284 {
285 //if we are using a ktx thats the size of a single block or less
286 //then make sure we use the 4x4 image as the single block
287 if (m_uiSourceHeight <= 4)
288 {
289 a_iPixelY= 0;
290 }
291 else
292 {
293 printf("blockAtHV: V coordinate out of range, capped to image height\n");
294 a_iPixelY = m_uiSourceHeight - 1;
295 }
296 }
297
298 unsigned int origWidth = m_uiSourceWidth;
299 unsigned int origHeight = m_uiSourceHeight;
300
301 m_uiSourceWidth = 4;
302 m_uiSourceHeight = 4;
303
304 Block4x4EncodingBits::Format encodingbitsformat = Image::DetermineEncodingBitsFormat(m_imageformat);
305 unsigned int uiEncodingBitsBytesPerBlock = Block4x4EncodingBits::GetBytesPerBlock(encodingbitsformat);
306
307 int numMipmaps = 1;
308 RawImage* pMipmapImages = new RawImage[numMipmaps];
309 pMipmapImages[0].uiExtendedWidth = Image::CalcExtendedDimension((unsigned short)m_uiSourceWidth);
310 pMipmapImages[0].uiExtendedHeight = Image::CalcExtendedDimension((unsigned short)m_uiSourceHeight);
311 pMipmapImages[0].uiEncodingBitsBytes = 0;
312 pMipmapImages[0].paucEncodingBits = std::shared_ptr<unsigned char>(new unsigned char[uiEncodingBitsBytesPerBlock], [](unsigned char *p) { delete[] p; });
313
314 //block position in pixels
315 // remove the bottom 2 bits to get the block coordinates
316 unsigned int iBlockPosX = (a_iPixelX & 0xFFFFFFFC);
317 unsigned int iBlockPosY = (a_iPixelY & 0xFFFFFFFC);
318
319 int numXBlocks = (origWidth / 4);
320 int numYBlocks = (origHeight / 4);
321
322
323 // block location
324 //int iBlockX = (a_iPixelX % 4) == 0 ? a_iPixelX / 4.0f : (a_iPixelX / 4) + 1;
325 //int iBlockY = (a_iPixelY % 4) == 0 ? a_iPixelY / 4.0f : (a_iPixelY / 4) + 1;
326 //m_paucEncodingBits += ((iBlockY * numXBlocks) + iBlockX) * uiEncodingBitsBytesPerBlock;
327
328
329 unsigned int num = numXBlocks*numYBlocks;
330 unsigned int uiH = 0, uiV = 0;
331 unsigned char* pEncodingBits = m_pMipmapImages[0].paucEncodingBits.get();
332 for (unsigned int uiBlock = 0; uiBlock < num; uiBlock++)
333 {
334 if (uiH == iBlockPosX && uiV == iBlockPosY)
335 {
336 memcpy(pMipmapImages[0].paucEncodingBits.get(),pEncodingBits, uiEncodingBitsBytesPerBlock);
337 break;
338 }
339 pEncodingBits += uiEncodingBitsBytesPerBlock;
340 uiH += 4;
341
342 if (uiH >= origWidth)
343 {
344 uiH = 0;
345 uiV += 4;
346 }
347 }
348
349 delete [] m_pMipmapImages;
350 m_pMipmapImages = pMipmapImages;
351 }
352 // ----------------------------------------------------------------------------------------------------
353 //
Write()354 void File::Write()
355 {
356
357 FILE *pfile = fopen(m_pstrFilename, "wb");
358 if (pfile == nullptr)
359 {
360 printf("Error: couldn't open Etc file (%s)\n", m_pstrFilename);
361 exit(1);
362 }
363
364 m_pheader->Write(pfile);
365
366 for(unsigned int mip = 0; mip < m_uiNumMipmaps; mip++)
367 {
368 if(m_fileformat == Format::KTX)
369 {
370 // Write u32 image size
371 uint32_t u32ImageSize = m_pMipmapImages[mip].uiEncodingBitsBytes;
372 uint32_t szBytesWritten = fwrite(&u32ImageSize, 1, sizeof(u32ImageSize), pfile);
373 assert(szBytesWritten == sizeof(u32ImageSize));
374 }
375
376 unsigned int iResult = (int)fwrite(m_pMipmapImages[mip].paucEncodingBits.get(), 1, m_pMipmapImages[mip].uiEncodingBitsBytes, pfile);
377 if (iResult != m_pMipmapImages[mip].uiEncodingBitsBytes)
378 {
379 printf("Error: couldn't write Etc file (%s)\n", m_pstrFilename);
380 exit(1);
381 }
382 }
383
384 fclose(pfile);
385
386 }
387
388 // ----------------------------------------------------------------------------------------------------
389 //
390
391