Image.cpp 23 KB

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