Image.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2012 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Context.h"
  25. #include "Decompress.h"
  26. #include "File.h"
  27. #include "FileSystem.h"
  28. #include "Log.h"
  29. #include <cstring>
  30. #include <stb_image.h>
  31. #include <stb_image_write.h>
  32. #include "DebugNew.h"
  33. #ifndef MAKEFOURCC
  34. #define MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned)(ch0) | ((unsigned)(ch1) << 8) | ((unsigned)(ch2) << 16) | ((unsigned)(ch3) << 24))
  35. #endif
  36. #define FOURCC_DXT1 (MAKEFOURCC('D','X','T','1'))
  37. #define FOURCC_DXT2 (MAKEFOURCC('D','X','T','2'))
  38. #define FOURCC_DXT3 (MAKEFOURCC('D','X','T','3'))
  39. #define FOURCC_DXT4 (MAKEFOURCC('D','X','T','4'))
  40. #define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5'))
  41. struct DDColorKey
  42. {
  43. unsigned dwColorSpaceLowValue_;
  44. unsigned dwColorSpaceHighValue_;
  45. };
  46. struct DDPixelFormat
  47. {
  48. unsigned dwSize_;
  49. unsigned dwFlags_;
  50. unsigned dwFourCC_;
  51. union
  52. {
  53. unsigned dwRGBBitCount_;
  54. unsigned dwYUVBitCount_;
  55. unsigned dwZBufferBitDepth_;
  56. unsigned dwAlphaBitDepth_;
  57. unsigned dwLuminanceBitCount_;
  58. unsigned dwBumpBitCount_;
  59. unsigned dwPrivateFormatBitCount_;
  60. };
  61. union
  62. {
  63. unsigned dwRBitMask_;
  64. unsigned dwYBitMask_;
  65. unsigned dwStencilBitDepth_;
  66. unsigned dwLuminanceBitMask_;
  67. unsigned dwBumpDuBitMask_;
  68. unsigned dwOperations_;
  69. };
  70. union
  71. {
  72. unsigned dwGBitMask_;
  73. unsigned dwUBitMask_;
  74. unsigned dwZBitMask_;
  75. unsigned dwBumpDvBitMask_;
  76. struct
  77. {
  78. unsigned short wFlipMSTypes_;
  79. unsigned short wBltMSTypes_;
  80. } multiSampleCaps_;
  81. };
  82. union
  83. {
  84. unsigned dwBBitMask_;
  85. unsigned dwVBitMask_;
  86. unsigned dwStencilBitMask_;
  87. unsigned dwBumpLuminanceBitMask_;
  88. };
  89. union
  90. {
  91. unsigned dwRGBAlphaBitMask_;
  92. unsigned dwYUVAlphaBitMask_;
  93. unsigned dwLuminanceAlphaBitMask_;
  94. unsigned dwRGBZBitMask_;
  95. unsigned dwYUVZBitMask_;
  96. };
  97. };
  98. struct DDSCaps2
  99. {
  100. unsigned dwCaps_;
  101. unsigned dwCaps2_;
  102. unsigned dwCaps3_;
  103. union
  104. {
  105. unsigned dwCaps4_;
  106. unsigned dwVolumeDepth_;
  107. };
  108. };
  109. struct DDSurfaceDesc2
  110. {
  111. unsigned dwSize_;
  112. unsigned dwFlags_;
  113. unsigned dwHeight_;
  114. unsigned dwWidth_;
  115. union
  116. {
  117. long lPitch_;
  118. unsigned dwLinearSize_;
  119. };
  120. union
  121. {
  122. unsigned dwBackBufferCount_;
  123. unsigned dwDepth_;
  124. };
  125. union
  126. {
  127. unsigned dwMipMapCount_;
  128. unsigned dwRefreshRate_;
  129. unsigned dwSrcVBHandle_;
  130. };
  131. unsigned dwAlphaBitDepth_;
  132. unsigned dwReserved_;
  133. void* lpSurface_;
  134. union
  135. {
  136. DDColorKey ddckCKDestOverlay_;
  137. unsigned dwEmptyFaceColor_;
  138. };
  139. DDColorKey ddckCKDestBlt_;
  140. DDColorKey ddckCKSrcOverlay_;
  141. DDColorKey ddckCKSrcBlt_;
  142. union
  143. {
  144. DDPixelFormat ddpfPixelFormat_;
  145. unsigned dwFVF_;
  146. };
  147. DDSCaps2 ddsCaps_;
  148. unsigned dwTextureStage_;
  149. };
  150. bool CompressedLevel::Decompress(unsigned char* dest)
  151. {
  152. if (!data_)
  153. return false;
  154. switch (format_)
  155. {
  156. case CF_DXT1:
  157. case CF_DXT3:
  158. case CF_DXT5:
  159. DecompressImageDXT(dest, data_, width_, height_, format_);
  160. return true;
  161. case CF_ETC1:
  162. DecompressImageETC(dest, data_, width_, height_);
  163. return true;
  164. case CF_PVRTC_RGB_2BPP:
  165. case CF_PVRTC_RGBA_2BPP:
  166. case CF_PVRTC_RGB_4BPP:
  167. case CF_PVRTC_RGBA_4BPP:
  168. DecompressImagePVRTC(dest, data_, width_, height_, format_);
  169. return true;
  170. }
  171. // Unknown format
  172. return false;
  173. }
  174. OBJECTTYPESTATIC(Image);
  175. Image::Image(Context* context) :
  176. Resource(context),
  177. width_(0),
  178. height_(0),
  179. components_(0)
  180. {
  181. }
  182. Image::~Image()
  183. {
  184. }
  185. void Image::RegisterObject(Context* context)
  186. {
  187. context->RegisterFactory<Image>();
  188. }
  189. bool Image::Load(Deserializer& source)
  190. {
  191. // Check for DDS, KTX or PVR compressed format
  192. String fileID = source.ReadFileID();
  193. if (fileID == "DDS ")
  194. {
  195. // DDS compressed format
  196. DDSurfaceDesc2 ddsd;
  197. source.Read(&ddsd, sizeof(ddsd));
  198. switch (ddsd.ddpfPixelFormat_.dwFourCC_)
  199. {
  200. case FOURCC_DXT1:
  201. compressedFormat_ = CF_DXT1;
  202. components_ = 3;
  203. break;
  204. case FOURCC_DXT3:
  205. compressedFormat_ = CF_DXT3;
  206. components_ = 4;
  207. break;
  208. case FOURCC_DXT5:
  209. compressedFormat_ = CF_DXT5;
  210. components_ = 4;
  211. break;
  212. default:
  213. LOGERROR("Unsupported DDS format");
  214. return false;
  215. }
  216. unsigned dataSize = source.GetSize() - source.GetPosition();
  217. data_ = new unsigned char[dataSize];
  218. width_ = ddsd.dwWidth_;
  219. height_ = ddsd.dwHeight_;
  220. numCompressedLevels_ = ddsd.dwMipMapCount_;
  221. if (!numCompressedLevels_)
  222. numCompressedLevels_ = 1;
  223. SetMemoryUse(dataSize);
  224. source.Read(data_.Get(), dataSize);
  225. }
  226. else if (fileID == "\253KTX")
  227. {
  228. source.Seek(12);
  229. unsigned endianness = source.ReadUInt();
  230. unsigned type = source.ReadUInt();
  231. unsigned typeSize = source.ReadUInt();
  232. unsigned format = source.ReadUInt();
  233. unsigned internalFormat = source.ReadUInt();
  234. unsigned baseInternalFormat = source.ReadUInt();
  235. unsigned width = source.ReadUInt();
  236. unsigned height = source.ReadUInt();
  237. unsigned depth = source.ReadUInt();
  238. unsigned arrayElements = source.ReadUInt();
  239. unsigned faces = source.ReadUInt();
  240. unsigned mipmaps = source.ReadUInt();
  241. unsigned keyValueBytes = source.ReadUInt();
  242. if (endianness != 0x04030201)
  243. {
  244. LOGERROR("Big-endian KTX files not supported");
  245. return false;
  246. }
  247. if (type != 0 || format != 0)
  248. {
  249. LOGERROR("Uncompressed KTX files not supported");
  250. return false;
  251. }
  252. if (faces > 1 || depth > 1)
  253. {
  254. LOGERROR("3D or cube KTX files not supported");
  255. return false;
  256. }
  257. if (mipmaps == 0)
  258. {
  259. LOGERROR("KTX files without explicitly specified mipmap count not supported");
  260. return false;
  261. }
  262. compressedFormat_ = CF_NONE;
  263. switch (internalFormat)
  264. {
  265. case 0x83f1:
  266. compressedFormat_ = CF_DXT1;
  267. components_ = 4;
  268. break;
  269. case 0x83f2:
  270. compressedFormat_ = CF_DXT3;
  271. components_ = 4;
  272. break;
  273. case 0x83f3:
  274. compressedFormat_ = CF_DXT5;
  275. components_ = 4;
  276. break;
  277. case 0x8d64:
  278. compressedFormat_ = CF_ETC1;
  279. components_ = 3;
  280. break;
  281. case 0x8c00:
  282. compressedFormat_ = CF_PVRTC_RGB_4BPP;
  283. components_ = 3;
  284. break;
  285. case 0x8c01:
  286. compressedFormat_ = CF_PVRTC_RGB_2BPP;
  287. components_ = 3;
  288. break;
  289. case 0x8c02:
  290. compressedFormat_ = CF_PVRTC_RGBA_4BPP;
  291. components_ = 4;
  292. break;
  293. case 0x8c03:
  294. compressedFormat_ = CF_PVRTC_RGBA_2BPP;
  295. components_ = 4;
  296. break;
  297. }
  298. if (compressedFormat_ == CF_NONE)
  299. {
  300. LOGERROR("Unsupported texture format in KTX file");
  301. return false;
  302. }
  303. source.Seek(source.GetPosition() + keyValueBytes);
  304. unsigned dataSize = source.GetSize() - source.GetPosition() - mipmaps * sizeof(unsigned);
  305. data_ = new unsigned char[dataSize];
  306. width_ = width;
  307. height_ = height;
  308. numCompressedLevels_ = mipmaps;
  309. unsigned dataOffset = 0;
  310. for (unsigned i = 0; i < mipmaps; ++i)
  311. {
  312. unsigned levelSize = source.ReadUInt();
  313. if (levelSize + dataOffset > dataSize)
  314. {
  315. LOGERROR("KTX mipmap level data size exceeds file size");
  316. return false;
  317. }
  318. source.Read(&data_[dataOffset], levelSize);
  319. dataOffset += levelSize;
  320. if (source.GetPosition() & 3)
  321. source.Seek((source.GetPosition() + 3) & 0xfffffffc);
  322. }
  323. SetMemoryUse(dataSize);
  324. }
  325. else if (fileID == "PVR\3")
  326. {
  327. unsigned flags = source.ReadUInt();
  328. unsigned pixelFormatLo = source.ReadUInt();
  329. unsigned pixelFormatHi = source.ReadUInt();
  330. unsigned colourSpace = source.ReadUInt();
  331. unsigned channelType = source.ReadUInt();
  332. unsigned height = source.ReadUInt();
  333. unsigned width = source.ReadUInt();
  334. unsigned depth = source.ReadUInt();
  335. unsigned numSurfaces = source.ReadUInt();
  336. unsigned numFaces = source.ReadUInt();
  337. unsigned mipmapCount = source.ReadUInt();
  338. unsigned metaDataSize = source.ReadUInt();
  339. if (depth > 1 || numFaces > 1)
  340. {
  341. LOGERROR("3D or cube PVR files not supported");
  342. return false;
  343. }
  344. if (mipmapCount == 0)
  345. {
  346. LOGERROR("PVR files without explicitly specified mipmap count not supported");
  347. return false;
  348. }
  349. compressedFormat_ = CF_NONE;
  350. switch (pixelFormatLo)
  351. {
  352. case 0:
  353. compressedFormat_ = CF_PVRTC_RGB_2BPP;
  354. components_ = 3;
  355. break;
  356. case 1:
  357. compressedFormat_ = CF_PVRTC_RGBA_2BPP;
  358. components_ = 4;
  359. break;
  360. case 2:
  361. compressedFormat_ = CF_PVRTC_RGB_4BPP;
  362. components_ = 3;
  363. break;
  364. case 3:
  365. compressedFormat_ = CF_PVRTC_RGBA_4BPP;
  366. components_ = 4;
  367. break;
  368. case 6:
  369. compressedFormat_ = CF_ETC1;
  370. components_ = 3;
  371. break;
  372. case 7:
  373. compressedFormat_ = CF_DXT1;
  374. components_ = 4;
  375. break;
  376. case 9:
  377. compressedFormat_ = CF_DXT3;
  378. components_ = 4;
  379. break;
  380. case 11:
  381. compressedFormat_ = CF_DXT5;
  382. components_ = 4;
  383. break;
  384. }
  385. if (compressedFormat_ == CF_NONE)
  386. {
  387. LOGERROR("Unsupported texture format in PVR file");
  388. return false;
  389. }
  390. source.Seek(source.GetPosition() + metaDataSize);
  391. unsigned dataSize = source.GetSize() - source.GetPosition();
  392. data_ = new unsigned char[dataSize];
  393. width_ = width;
  394. height_ = height;
  395. numCompressedLevels_ = mipmapCount;
  396. source.Read(data_.Get(), dataSize);
  397. SetMemoryUse(dataSize);
  398. }
  399. else
  400. {
  401. // Not DDS, KTX or PVR, use STBImage to load other image formats as uncompressed
  402. source.Seek(0);
  403. int width, height;
  404. unsigned components;
  405. unsigned char* pixelData = GetImageData(source, width, height, components);
  406. if (!pixelData)
  407. {
  408. LOGERROR("Could not load image: " + String(stbi_failure_reason()));
  409. return false;
  410. }
  411. SetSize(width, height, components);
  412. SetData(pixelData);
  413. FreeImageData(pixelData);
  414. }
  415. return true;
  416. }
  417. void Image::SetSize(int width, int height, unsigned components)
  418. {
  419. if (width == width_ && height == height_ && components == components_)
  420. return;
  421. if (width <= 0 || height <= 0)
  422. return;
  423. data_ = new unsigned char[width * height * components];
  424. width_ = width;
  425. height_ = height;
  426. components_ = components;
  427. compressedFormat_ = CF_NONE;
  428. numCompressedLevels_ = 0;
  429. SetMemoryUse(width * height * components);
  430. }
  431. void Image::SetData(const unsigned char* pixelData)
  432. {
  433. memcpy(data_.Get(), pixelData, width_ * height_ * components_);
  434. }
  435. bool Image::SaveBMP(const String& fileName)
  436. {
  437. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  438. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  439. {
  440. LOGERROR("Access denied to " + fileName);
  441. return false;
  442. }
  443. if (IsCompressed())
  444. {
  445. LOGERROR("Can not save compressed image to BMP");
  446. return false;
  447. }
  448. if (data_)
  449. return stbi_write_bmp(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  450. else
  451. return false;
  452. }
  453. bool Image::SaveTGA(const String& fileName)
  454. {
  455. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  456. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  457. {
  458. LOGERROR("Access denied to " + fileName);
  459. return false;
  460. }
  461. if (IsCompressed())
  462. {
  463. LOGERROR("Can not save compressed image to TGA");
  464. return false;
  465. }
  466. if (data_)
  467. return stbi_write_tga(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  468. else
  469. return false;
  470. }
  471. unsigned char* Image::GetImageData(Deserializer& source, int& width, int& height, unsigned& components)
  472. {
  473. unsigned dataSize = source.GetSize();
  474. SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
  475. source.Read(buffer.Get(), dataSize);
  476. return stbi_load_from_memory(buffer.Get(), dataSize, &width, &height, (int *)&components, 0);
  477. }
  478. void Image::FreeImageData(unsigned char* pixelData)
  479. {
  480. if (!pixelData)
  481. return;
  482. stbi_image_free(pixelData);
  483. }
  484. SharedPtr<Image> Image::GetNextLevel() const
  485. {
  486. if (IsCompressed())
  487. {
  488. LOGERROR("Can not generate mip level from compressed data");
  489. return SharedPtr<Image>();
  490. }
  491. if (components_ < 1 || components_ > 4)
  492. {
  493. LOGERROR("Illegal number of image components for mip level generation");
  494. return SharedPtr<Image>();
  495. }
  496. int widthOut = width_ / 2;
  497. int heightOut = height_ / 2;
  498. if (widthOut < 1)
  499. widthOut = 1;
  500. if (heightOut < 1)
  501. heightOut = 1;
  502. SharedPtr<Image> mipImage(new Image(context_));
  503. mipImage->SetSize(widthOut, heightOut, components_);
  504. const unsigned char* pixelDataIn = data_.Get();
  505. unsigned char* pixelDataOut = mipImage->data_.Get();
  506. // 1D case
  507. if (height_ == 1 || width_ == 1)
  508. {
  509. // Loop using the larger dimension
  510. if (widthOut < heightOut)
  511. widthOut = heightOut;
  512. switch (components_)
  513. {
  514. case 1:
  515. for (int x = 0; x < widthOut; ++x)
  516. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+1]) >> 1;
  517. break;
  518. case 2:
  519. for (int x = 0; x < widthOut*2; x += 2)
  520. {
  521. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+2]) >> 1;
  522. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+3]) >> 1;
  523. }
  524. break;
  525. case 3:
  526. for (int x = 0; x < widthOut*3; x += 3)
  527. {
  528. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+3]) >> 1;
  529. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+4]) >> 1;
  530. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+5]) >> 1;
  531. }
  532. break;
  533. case 4:
  534. for (int x = 0; x < widthOut*4; x += 4)
  535. {
  536. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+4]) >> 1;
  537. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+5]) >> 1;
  538. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+6]) >> 1;
  539. pixelDataOut[x+3] = ((unsigned)pixelDataIn[x*2+3] + pixelDataIn[x*2+7]) >> 1;
  540. }
  541. break;
  542. }
  543. }
  544. // 2D case
  545. else
  546. {
  547. switch (components_)
  548. {
  549. case 1:
  550. for (int y = 0; y < heightOut; ++y)
  551. {
  552. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_];
  553. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_];
  554. unsigned char* out = &pixelDataOut[y*widthOut];
  555. for (int x = 0; x < widthOut; ++x)
  556. {
  557. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+1] + inLower[x*2] + inLower[x*2+1]) >> 2;
  558. }
  559. }
  560. break;
  561. case 2:
  562. for (int y = 0; y < heightOut; ++y)
  563. {
  564. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*2];
  565. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*2];
  566. unsigned char* out = &pixelDataOut[y*widthOut*2];
  567. for (int x = 0; x < widthOut*2; x += 2)
  568. {
  569. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+2] + inLower[x*2] + inLower[x*2+2]) >> 2;
  570. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+3] + inLower[x*2+1] + inLower[x*2+3]) >> 2;
  571. }
  572. }
  573. break;
  574. case 3:
  575. for (int y = 0; y < heightOut; ++y)
  576. {
  577. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*3];
  578. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*3];
  579. unsigned char* out = &pixelDataOut[y*widthOut*3];
  580. for (int x = 0; x < widthOut*3; x += 3)
  581. {
  582. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+3] + inLower[x*2] + inLower[x*2+3]) >> 2;
  583. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+4] + inLower[x*2+1] + inLower[x*2+4]) >> 2;
  584. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+5] + inLower[x*2+2] + inLower[x*2+5]) >> 2;
  585. }
  586. }
  587. break;
  588. case 4:
  589. for (int y = 0; y < heightOut; ++y)
  590. {
  591. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*4];
  592. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*4];
  593. unsigned char* out = &pixelDataOut[y*widthOut*4];
  594. for (int x = 0; x < widthOut*4; x += 4)
  595. {
  596. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+4] + inLower[x*2] + inLower[x*2+4]) >> 2;
  597. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+5] + inLower[x*2+1] + inLower[x*2+5]) >> 2;
  598. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+6] + inLower[x*2+2] + inLower[x*2+6]) >> 2;
  599. out[x+3] = ((unsigned)inUpper[x*2+3] + inUpper[x*2+7] + inLower[x*2+3] + inLower[x*2+7]) >> 2;
  600. }
  601. }
  602. break;
  603. }
  604. }
  605. return mipImage;
  606. }
  607. CompressedLevel Image::GetCompressedLevel(unsigned index) const
  608. {
  609. CompressedLevel level;
  610. if (compressedFormat_ == CF_NONE)
  611. {
  612. LOGERROR("Image is not compressed");
  613. return level;
  614. }
  615. if (index >= numCompressedLevels_)
  616. {
  617. LOGERROR("Compressed image mip level out of bounds");
  618. return level;
  619. }
  620. level.format_ = compressedFormat_;
  621. level.width_ = width_;
  622. level.height_ = height_;
  623. if (compressedFormat_ < CF_PVRTC_RGB_2BPP)
  624. {
  625. level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
  626. unsigned i = 0;
  627. unsigned offset = 0;
  628. for (;;)
  629. {
  630. if (!level.width_)
  631. level.width_ = 1;
  632. if (!level.height_)
  633. level.height_ = 1;
  634. level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
  635. level.rows_ = ((level.height_ + 3) / 4);
  636. level.data_ = data_.Get() + offset;
  637. level.dataSize_ = level.rows_ * level.rowSize_;
  638. if (offset + level.dataSize_ > GetMemoryUse())
  639. {
  640. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  641. " Datasize: " + String(GetMemoryUse()));
  642. level.data_ = 0;
  643. return level;
  644. }
  645. if (i == index)
  646. return level;
  647. offset += level.dataSize_;
  648. level.width_ /= 2;
  649. level.height_ /= 2;
  650. ++i;
  651. }
  652. }
  653. else
  654. {
  655. level.blockSize_ = compressedFormat_ < CF_PVRTC_RGB_4BPP ? 2 : 4;
  656. unsigned i = 0;
  657. unsigned offset = 0;
  658. for (;;)
  659. {
  660. if (!level.width_)
  661. level.width_ = 1;
  662. if (!level.height_)
  663. level.height_ = 1;
  664. int dataWidth = Max(level.width_, level.blockSize_ == 2 ? 16 : 8);
  665. int dataHeight = Max(level.height_, 8);
  666. level.data_ = data_.Get() + offset;
  667. level.dataSize_ = (dataWidth * dataHeight * level.blockSize_ + 7) >> 3;
  668. level.rows_ = dataHeight;
  669. level.rowSize_ = level.dataSize_ / level.rows_;
  670. if (offset + level.dataSize_ > GetMemoryUse())
  671. {
  672. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  673. " Datasize: " + String(GetMemoryUse()));
  674. level.data_ = 0;
  675. return level;
  676. }
  677. if (i == index)
  678. return level;
  679. offset += level.dataSize_;
  680. level.width_ /= 2;
  681. level.height_ /= 2;
  682. ++i;
  683. }
  684. }
  685. }