Image.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  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. FreeImageData(pixelData);
  408. }
  409. return true;
  410. }
  411. void Image::SetSize(int width, int height, unsigned components)
  412. {
  413. if (width == width_ && height == height_ && components == components_)
  414. return;
  415. if (width <= 0 || height <= 0)
  416. return;
  417. data_ = new unsigned char[width * height * components];
  418. width_ = width;
  419. height_ = height;
  420. components_ = components;
  421. compressedFormat_ = CF_NONE;
  422. numCompressedLevels_ = 0;
  423. SetMemoryUse(width * height * components);
  424. }
  425. void Image::SetData(const unsigned char* pixelData)
  426. {
  427. memcpy(data_.Get(), pixelData, width_ * height_ * components_);
  428. }
  429. bool Image::SaveBMP(const String& fileName)
  430. {
  431. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  432. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  433. {
  434. LOGERROR("Access denied to " + fileName);
  435. return false;
  436. }
  437. if (IsCompressed())
  438. {
  439. LOGERROR("Can not save compressed image to BMP");
  440. return false;
  441. }
  442. if (data_)
  443. return stbi_write_bmp(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  444. else
  445. return false;
  446. }
  447. bool Image::SaveTGA(const String& fileName)
  448. {
  449. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  450. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  451. {
  452. LOGERROR("Access denied to " + fileName);
  453. return false;
  454. }
  455. if (IsCompressed())
  456. {
  457. LOGERROR("Can not save compressed image to TGA");
  458. return false;
  459. }
  460. if (data_)
  461. return stbi_write_tga(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  462. else
  463. return false;
  464. }
  465. unsigned char* Image::GetImageData(Deserializer& source, int& width, int& height, unsigned& components)
  466. {
  467. unsigned dataSize = source.GetSize();
  468. SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
  469. source.Read(buffer.Get(), dataSize);
  470. return stbi_load_from_memory(buffer.Get(), dataSize, &width, &height, (int *)&components, 0);
  471. }
  472. void Image::FreeImageData(unsigned char* pixelData)
  473. {
  474. if (!pixelData)
  475. return;
  476. stbi_image_free(pixelData);
  477. }
  478. SharedPtr<Image> Image::GetNextLevel() const
  479. {
  480. if (IsCompressed())
  481. {
  482. LOGERROR("Can not generate mip level from compressed data");
  483. return SharedPtr<Image>();
  484. }
  485. if (components_ < 1 || components_ > 4)
  486. {
  487. LOGERROR("Illegal number of image components for mip level generation");
  488. return SharedPtr<Image>();
  489. }
  490. int widthOut = width_ / 2;
  491. int heightOut = height_ / 2;
  492. if (widthOut < 1)
  493. widthOut = 1;
  494. if (heightOut < 1)
  495. heightOut = 1;
  496. SharedPtr<Image> mipImage(new Image(context_));
  497. mipImage->SetSize(widthOut, heightOut, components_);
  498. const unsigned char* pixelDataIn = data_.Get();
  499. unsigned char* pixelDataOut = mipImage->data_.Get();
  500. // 1D case
  501. if (height_ == 1 || width_ == 1)
  502. {
  503. // Loop using the larger dimension
  504. if (widthOut < heightOut)
  505. widthOut = heightOut;
  506. switch (components_)
  507. {
  508. case 1:
  509. for (int x = 0; x < widthOut; ++x)
  510. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+1]) >> 1;
  511. break;
  512. case 2:
  513. for (int x = 0; x < widthOut*2; x += 2)
  514. {
  515. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+2]) >> 1;
  516. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+3]) >> 1;
  517. }
  518. break;
  519. case 3:
  520. for (int x = 0; x < widthOut*3; x += 3)
  521. {
  522. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+3]) >> 1;
  523. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+4]) >> 1;
  524. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+5]) >> 1;
  525. }
  526. break;
  527. case 4:
  528. for (int x = 0; x < widthOut*4; x += 4)
  529. {
  530. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+4]) >> 1;
  531. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+5]) >> 1;
  532. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+6]) >> 1;
  533. pixelDataOut[x+3] = ((unsigned)pixelDataIn[x*2+3] + pixelDataIn[x*2+7]) >> 1;
  534. }
  535. break;
  536. }
  537. }
  538. // 2D case
  539. else
  540. {
  541. switch (components_)
  542. {
  543. case 1:
  544. for (int y = 0; y < heightOut; ++y)
  545. {
  546. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_];
  547. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_];
  548. unsigned char* out = &pixelDataOut[y*widthOut];
  549. for (int x = 0; x < widthOut; ++x)
  550. {
  551. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+1] + inLower[x*2] + inLower[x*2+1]) >> 2;
  552. }
  553. }
  554. break;
  555. case 2:
  556. for (int y = 0; y < heightOut; ++y)
  557. {
  558. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*2];
  559. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*2];
  560. unsigned char* out = &pixelDataOut[y*widthOut*2];
  561. for (int x = 0; x < widthOut*2; x += 2)
  562. {
  563. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+2] + inLower[x*2] + inLower[x*2+2]) >> 2;
  564. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+3] + inLower[x*2+1] + inLower[x*2+3]) >> 2;
  565. }
  566. }
  567. break;
  568. case 3:
  569. for (int y = 0; y < heightOut; ++y)
  570. {
  571. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*3];
  572. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*3];
  573. unsigned char* out = &pixelDataOut[y*widthOut*3];
  574. for (int x = 0; x < widthOut*3; x += 3)
  575. {
  576. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+3] + inLower[x*2] + inLower[x*2+3]) >> 2;
  577. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+4] + inLower[x*2+1] + inLower[x*2+4]) >> 2;
  578. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+5] + inLower[x*2+2] + inLower[x*2+5]) >> 2;
  579. }
  580. }
  581. break;
  582. case 4:
  583. for (int y = 0; y < heightOut; ++y)
  584. {
  585. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*4];
  586. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*4];
  587. unsigned char* out = &pixelDataOut[y*widthOut*4];
  588. for (int x = 0; x < widthOut*4; x += 4)
  589. {
  590. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+4] + inLower[x*2] + inLower[x*2+4]) >> 2;
  591. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+5] + inLower[x*2+1] + inLower[x*2+5]) >> 2;
  592. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+6] + inLower[x*2+2] + inLower[x*2+6]) >> 2;
  593. out[x+3] = ((unsigned)inUpper[x*2+3] + inUpper[x*2+7] + inLower[x*2+3] + inLower[x*2+7]) >> 2;
  594. }
  595. }
  596. break;
  597. }
  598. }
  599. return mipImage;
  600. }
  601. CompressedLevel Image::GetCompressedLevel(unsigned index) const
  602. {
  603. CompressedLevel level;
  604. if (compressedFormat_ == CF_NONE)
  605. {
  606. LOGERROR("Image is not compressed");
  607. return level;
  608. }
  609. if (index >= numCompressedLevels_)
  610. {
  611. LOGERROR("Compressed image mip level out of bounds");
  612. return level;
  613. }
  614. level.compressedFormat_ = compressedFormat_;
  615. level.width_ = width_;
  616. level.height_ = height_;
  617. if (compressedFormat_ < CF_PVRTC_RGB_2BPP)
  618. {
  619. level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
  620. unsigned i = 0;
  621. unsigned offset = 0;
  622. for (;;)
  623. {
  624. if (!level.width_)
  625. level.width_ = 1;
  626. if (!level.height_)
  627. level.height_ = 1;
  628. level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
  629. level.rows_ = ((level.height_ + 3) / 4);
  630. level.data_ = data_.Get() + offset;
  631. level.dataSize_ = level.rows_ * level.rowSize_;
  632. if (offset + level.dataSize_ > GetMemoryUse())
  633. {
  634. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  635. " Datasize: " + String(GetMemoryUse()));
  636. level.data_ = 0;
  637. return level;
  638. }
  639. if (i == index)
  640. return level;
  641. offset += level.dataSize_;
  642. level.width_ /= 2;
  643. level.height_ /= 2;
  644. ++i;
  645. }
  646. }
  647. else
  648. {
  649. level.blockSize_ = compressedFormat_ < CF_PVRTC_RGB_4BPP ? 2 : 4;
  650. unsigned i = 0;
  651. unsigned offset = 0;
  652. for (;;)
  653. {
  654. if (!level.width_)
  655. level.width_ = 1;
  656. if (!level.height_)
  657. level.height_ = 1;
  658. int dataWidth = Max(level.width_, level.blockSize_ == 2 ? 16 : 8);
  659. int dataHeight = Max(level.height_, 8);
  660. level.data_ = data_.Get() + offset;
  661. level.dataSize_ = (dataWidth * dataHeight * level.blockSize_ + 7) >> 3;
  662. level.rows_ = dataHeight;
  663. level.rowSize_ = level.dataSize_ / level.rows_;
  664. if (offset + level.dataSize_ > GetMemoryUse())
  665. {
  666. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  667. " Datasize: " + String(GetMemoryUse()));
  668. level.data_ = 0;
  669. return level;
  670. }
  671. if (i == index)
  672. return level;
  673. offset += level.dataSize_;
  674. level.width_ /= 2;
  675. level.height_ /= 2;
  676. ++i;
  677. }
  678. }
  679. }