Image.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Decompress.h"
  25. #include "File.h"
  26. #include "FileSystem.h"
  27. #include "Log.h"
  28. #include "Profiler.h"
  29. #include <cstring>
  30. #include <stb_image.h>
  31. #include <stb_image_write.h>
  32. #include <jo_jpeg.h>
  33. #include <SDL_surface.h>
  34. #include "DebugNew.h"
  35. #ifndef MAKEFOURCC
  36. #define MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned)(ch0) | ((unsigned)(ch1) << 8) | ((unsigned)(ch2) << 16) | ((unsigned)(ch3) << 24))
  37. #endif
  38. #define FOURCC_DXT1 (MAKEFOURCC('D','X','T','1'))
  39. #define FOURCC_DXT2 (MAKEFOURCC('D','X','T','2'))
  40. #define FOURCC_DXT3 (MAKEFOURCC('D','X','T','3'))
  41. #define FOURCC_DXT4 (MAKEFOURCC('D','X','T','4'))
  42. #define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5'))
  43. namespace Urho3D
  44. {
  45. struct DDColorKey
  46. {
  47. unsigned dwColorSpaceLowValue_;
  48. unsigned dwColorSpaceHighValue_;
  49. };
  50. struct DDPixelFormat
  51. {
  52. unsigned dwSize_;
  53. unsigned dwFlags_;
  54. unsigned dwFourCC_;
  55. union
  56. {
  57. unsigned dwRGBBitCount_;
  58. unsigned dwYUVBitCount_;
  59. unsigned dwZBufferBitDepth_;
  60. unsigned dwAlphaBitDepth_;
  61. unsigned dwLuminanceBitCount_;
  62. unsigned dwBumpBitCount_;
  63. unsigned dwPrivateFormatBitCount_;
  64. };
  65. union
  66. {
  67. unsigned dwRBitMask_;
  68. unsigned dwYBitMask_;
  69. unsigned dwStencilBitDepth_;
  70. unsigned dwLuminanceBitMask_;
  71. unsigned dwBumpDuBitMask_;
  72. unsigned dwOperations_;
  73. };
  74. union
  75. {
  76. unsigned dwGBitMask_;
  77. unsigned dwUBitMask_;
  78. unsigned dwZBitMask_;
  79. unsigned dwBumpDvBitMask_;
  80. struct
  81. {
  82. unsigned short wFlipMSTypes_;
  83. unsigned short wBltMSTypes_;
  84. } multiSampleCaps_;
  85. };
  86. union
  87. {
  88. unsigned dwBBitMask_;
  89. unsigned dwVBitMask_;
  90. unsigned dwStencilBitMask_;
  91. unsigned dwBumpLuminanceBitMask_;
  92. };
  93. union
  94. {
  95. unsigned dwRGBAlphaBitMask_;
  96. unsigned dwYUVAlphaBitMask_;
  97. unsigned dwLuminanceAlphaBitMask_;
  98. unsigned dwRGBZBitMask_;
  99. unsigned dwYUVZBitMask_;
  100. };
  101. };
  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. struct DDSurfaceDesc2
  114. {
  115. unsigned dwSize_;
  116. unsigned dwFlags_;
  117. unsigned dwHeight_;
  118. unsigned dwWidth_;
  119. union
  120. {
  121. unsigned lPitch_;
  122. unsigned dwLinearSize_;
  123. };
  124. union
  125. {
  126. unsigned dwBackBufferCount_;
  127. unsigned dwDepth_;
  128. };
  129. union
  130. {
  131. unsigned dwMipMapCount_;
  132. unsigned dwRefreshRate_;
  133. unsigned dwSrcVBHandle_;
  134. };
  135. unsigned dwAlphaBitDepth_;
  136. unsigned dwReserved_;
  137. unsigned lpSurface_; // Do not define as a void pointer, as it is 8 bytes in a 64bit build
  138. union
  139. {
  140. DDColorKey ddckCKDestOverlay_;
  141. unsigned dwEmptyFaceColor_;
  142. };
  143. DDColorKey ddckCKDestBlt_;
  144. DDColorKey ddckCKSrcOverlay_;
  145. DDColorKey ddckCKSrcBlt_;
  146. union
  147. {
  148. DDPixelFormat ddpfPixelFormat_;
  149. unsigned dwFVF_;
  150. };
  151. DDSCaps2 ddsCaps_;
  152. unsigned dwTextureStage_;
  153. };
  154. bool CompressedLevel::Decompress(unsigned char* dest)
  155. {
  156. if (!data_)
  157. return false;
  158. switch (format_)
  159. {
  160. case CF_DXT1:
  161. case CF_DXT3:
  162. case CF_DXT5:
  163. DecompressImageDXT(dest, data_, width_, height_, depth_, format_);
  164. return true;
  165. case CF_ETC1:
  166. DecompressImageETC(dest, data_, width_, height_);
  167. return true;
  168. case CF_PVRTC_RGB_2BPP:
  169. case CF_PVRTC_RGBA_2BPP:
  170. case CF_PVRTC_RGB_4BPP:
  171. case CF_PVRTC_RGBA_4BPP:
  172. DecompressImagePVRTC(dest, data_, width_, height_, format_);
  173. return true;
  174. default:
  175. // Unknown format
  176. return false;
  177. }
  178. }
  179. Image::Image(Context* context) :
  180. Resource(context),
  181. width_(0),
  182. height_(0),
  183. depth_(0),
  184. components_(0)
  185. {
  186. }
  187. Image::~Image()
  188. {
  189. }
  190. void Image::RegisterObject(Context* context)
  191. {
  192. context->RegisterFactory<Image>();
  193. }
  194. bool Image::Load(Deserializer& source)
  195. {
  196. PROFILE(LoadImage);
  197. // Check for DDS, KTX or PVR compressed format
  198. String fileID = source.ReadFileID();
  199. if (fileID == "DDS ")
  200. {
  201. // DDS compressed format
  202. DDSurfaceDesc2 ddsd;
  203. source.Read(&ddsd, sizeof(ddsd));
  204. switch (ddsd.ddpfPixelFormat_.dwFourCC_)
  205. {
  206. case FOURCC_DXT1:
  207. compressedFormat_ = CF_DXT1;
  208. components_ = 3;
  209. break;
  210. case FOURCC_DXT3:
  211. compressedFormat_ = CF_DXT3;
  212. components_ = 4;
  213. break;
  214. case FOURCC_DXT5:
  215. compressedFormat_ = CF_DXT5;
  216. components_ = 4;
  217. break;
  218. default:
  219. LOGERROR("Unsupported DDS format");
  220. return false;
  221. }
  222. unsigned dataSize = source.GetSize() - source.GetPosition();
  223. data_ = new unsigned char[dataSize];
  224. width_ = ddsd.dwWidth_;
  225. height_ = ddsd.dwHeight_;
  226. depth_ = ddsd.dwDepth_;
  227. numCompressedLevels_ = ddsd.dwMipMapCount_;
  228. if (!numCompressedLevels_)
  229. numCompressedLevels_ = 1;
  230. SetMemoryUse(dataSize);
  231. source.Read(data_.Get(), dataSize);
  232. }
  233. else if (fileID == "\253KTX")
  234. {
  235. source.Seek(12);
  236. unsigned endianness = source.ReadUInt();
  237. unsigned type = source.ReadUInt();
  238. /* unsigned typeSize = */ source.ReadUInt();
  239. unsigned format = source.ReadUInt();
  240. unsigned internalFormat = source.ReadUInt();
  241. /* unsigned baseInternalFormat = */ source.ReadUInt();
  242. unsigned width = source.ReadUInt();
  243. unsigned height = source.ReadUInt();
  244. unsigned depth = source.ReadUInt();
  245. /* unsigned arrayElements = */ source.ReadUInt();
  246. unsigned faces = source.ReadUInt();
  247. unsigned mipmaps = source.ReadUInt();
  248. unsigned keyValueBytes = source.ReadUInt();
  249. if (endianness != 0x04030201)
  250. {
  251. LOGERROR("Big-endian KTX files not supported");
  252. return false;
  253. }
  254. if (type != 0 || format != 0)
  255. {
  256. LOGERROR("Uncompressed KTX files not supported");
  257. return false;
  258. }
  259. if (faces > 1 || depth > 1)
  260. {
  261. LOGERROR("3D or cube KTX files not supported");
  262. return false;
  263. }
  264. if (mipmaps == 0)
  265. {
  266. LOGERROR("KTX files without explicitly specified mipmap count not supported");
  267. return false;
  268. }
  269. compressedFormat_ = CF_NONE;
  270. switch (internalFormat)
  271. {
  272. case 0x83f1:
  273. compressedFormat_ = CF_DXT1;
  274. components_ = 4;
  275. break;
  276. case 0x83f2:
  277. compressedFormat_ = CF_DXT3;
  278. components_ = 4;
  279. break;
  280. case 0x83f3:
  281. compressedFormat_ = CF_DXT5;
  282. components_ = 4;
  283. break;
  284. case 0x8d64:
  285. compressedFormat_ = CF_ETC1;
  286. components_ = 3;
  287. break;
  288. case 0x8c00:
  289. compressedFormat_ = CF_PVRTC_RGB_4BPP;
  290. components_ = 3;
  291. break;
  292. case 0x8c01:
  293. compressedFormat_ = CF_PVRTC_RGB_2BPP;
  294. components_ = 3;
  295. break;
  296. case 0x8c02:
  297. compressedFormat_ = CF_PVRTC_RGBA_4BPP;
  298. components_ = 4;
  299. break;
  300. case 0x8c03:
  301. compressedFormat_ = CF_PVRTC_RGBA_2BPP;
  302. components_ = 4;
  303. break;
  304. }
  305. if (compressedFormat_ == CF_NONE)
  306. {
  307. LOGERROR("Unsupported texture format in KTX file");
  308. return false;
  309. }
  310. source.Seek(source.GetPosition() + keyValueBytes);
  311. unsigned dataSize = source.GetSize() - source.GetPosition() - mipmaps * sizeof(unsigned);
  312. data_ = new unsigned char[dataSize];
  313. width_ = width;
  314. height_ = height;
  315. numCompressedLevels_ = mipmaps;
  316. unsigned dataOffset = 0;
  317. for (unsigned i = 0; i < mipmaps; ++i)
  318. {
  319. unsigned levelSize = source.ReadUInt();
  320. if (levelSize + dataOffset > dataSize)
  321. {
  322. LOGERROR("KTX mipmap level data size exceeds file size");
  323. return false;
  324. }
  325. source.Read(&data_[dataOffset], levelSize);
  326. dataOffset += levelSize;
  327. if (source.GetPosition() & 3)
  328. source.Seek((source.GetPosition() + 3) & 0xfffffffc);
  329. }
  330. SetMemoryUse(dataSize);
  331. }
  332. else if (fileID == "PVR\3")
  333. {
  334. /* unsigned flags = */ source.ReadUInt();
  335. unsigned pixelFormatLo = source.ReadUInt();
  336. /* unsigned pixelFormatHi = */ source.ReadUInt();
  337. /* unsigned colourSpace = */ source.ReadUInt();
  338. /* unsigned channelType = */ source.ReadUInt();
  339. unsigned height = source.ReadUInt();
  340. unsigned width = source.ReadUInt();
  341. unsigned depth = source.ReadUInt();
  342. /* unsigned numSurfaces = */ source.ReadUInt();
  343. unsigned numFaces = source.ReadUInt();
  344. unsigned mipmapCount = source.ReadUInt();
  345. unsigned metaDataSize = source.ReadUInt();
  346. if (depth > 1 || numFaces > 1)
  347. {
  348. LOGERROR("3D or cube PVR files not supported");
  349. return false;
  350. }
  351. if (mipmapCount == 0)
  352. {
  353. LOGERROR("PVR files without explicitly specified mipmap count not supported");
  354. return false;
  355. }
  356. compressedFormat_ = CF_NONE;
  357. switch (pixelFormatLo)
  358. {
  359. case 0:
  360. compressedFormat_ = CF_PVRTC_RGB_2BPP;
  361. components_ = 3;
  362. break;
  363. case 1:
  364. compressedFormat_ = CF_PVRTC_RGBA_2BPP;
  365. components_ = 4;
  366. break;
  367. case 2:
  368. compressedFormat_ = CF_PVRTC_RGB_4BPP;
  369. components_ = 3;
  370. break;
  371. case 3:
  372. compressedFormat_ = CF_PVRTC_RGBA_4BPP;
  373. components_ = 4;
  374. break;
  375. case 6:
  376. compressedFormat_ = CF_ETC1;
  377. components_ = 3;
  378. break;
  379. case 7:
  380. compressedFormat_ = CF_DXT1;
  381. components_ = 4;
  382. break;
  383. case 9:
  384. compressedFormat_ = CF_DXT3;
  385. components_ = 4;
  386. break;
  387. case 11:
  388. compressedFormat_ = CF_DXT5;
  389. components_ = 4;
  390. break;
  391. }
  392. if (compressedFormat_ == CF_NONE)
  393. {
  394. LOGERROR("Unsupported texture format in PVR file");
  395. return false;
  396. }
  397. source.Seek(source.GetPosition() + metaDataSize);
  398. unsigned dataSize = source.GetSize() - source.GetPosition();
  399. data_ = new unsigned char[dataSize];
  400. width_ = width;
  401. height_ = height;
  402. numCompressedLevels_ = mipmapCount;
  403. source.Read(data_.Get(), dataSize);
  404. SetMemoryUse(dataSize);
  405. }
  406. else
  407. {
  408. // Not DDS, KTX or PVR, use STBImage to load other image formats as uncompressed
  409. source.Seek(0);
  410. int width, height;
  411. unsigned components;
  412. unsigned char* pixelData = GetImageData(source, width, height, components);
  413. if (!pixelData)
  414. {
  415. LOGERROR("Could not load image " + source.GetName() + ": " + String(stbi_failure_reason()));
  416. return false;
  417. }
  418. SetSize(width, height, components);
  419. SetData(pixelData);
  420. FreeImageData(pixelData);
  421. }
  422. return true;
  423. }
  424. bool Image::SetSize(int width, int height, unsigned components)
  425. {
  426. return SetSize(width, height, 1, components);
  427. }
  428. bool Image::SetSize(int width, int height, int depth, unsigned components)
  429. {
  430. if (width == width_ && height == height_ && depth == depth_ && components == components_)
  431. return true;
  432. if (width <= 0 || height <= 0 || depth <= 0)
  433. return false;
  434. if (components > 4)
  435. {
  436. LOGERROR("More than 4 color components are not supported");
  437. return false;
  438. }
  439. data_ = new unsigned char[width * height * depth * components];
  440. width_ = width;
  441. height_ = height;
  442. depth_ = depth;
  443. components_ = components;
  444. compressedFormat_ = CF_NONE;
  445. numCompressedLevels_ = 0;
  446. SetMemoryUse(width * height * depth * components);
  447. return true;
  448. }
  449. void Image::SetPixel(int x, int y, const Color& color)
  450. {
  451. SetPixelInt(x, y, 0, color.ToUInt());
  452. }
  453. void Image::SetPixel(int x, int y, int z, const Color& color)
  454. {
  455. SetPixelInt(x, y, z, color.ToUInt());
  456. }
  457. void Image::SetPixelInt(int x, int y, unsigned uintColor)
  458. {
  459. SetPixelInt(x, y, 0, uintColor);
  460. }
  461. void Image::SetPixelInt(int x, int y, int z, unsigned uintColor)
  462. {
  463. if (!data_ || x < 0 || x >= width_ || y < 0 || y >= height_ || z < 0 || z >= depth_ || IsCompressed())
  464. return;
  465. unsigned char* dest = data_ + (z * width_ * height_ + y * width_ + x) * components_;
  466. unsigned char* src = (unsigned char*)&uintColor;
  467. switch (components_)
  468. {
  469. case 4:
  470. dest[3] = src[3];
  471. // Fall through
  472. case 3:
  473. dest[2] = src[2];
  474. // Fall through
  475. case 2:
  476. dest[1]= src[1];
  477. // Fall through
  478. default:
  479. dest[0] = src[0];
  480. break;
  481. }
  482. }
  483. void Image::SetData(const unsigned char* pixelData)
  484. {
  485. if (!data_)
  486. return;
  487. memcpy(data_.Get(), pixelData, width_ * height_ * depth_ * components_);
  488. }
  489. bool Image::LoadColorLUT(Deserializer& source)
  490. {
  491. String fileID = source.ReadFileID();
  492. if (fileID == "DDS " || fileID == "\253KTX" || fileID == "PVR\3")
  493. {
  494. LOGERROR("Invalid image format, can not load image");
  495. return false;
  496. }
  497. source.Seek(0);
  498. int width, height;
  499. unsigned components;
  500. unsigned char* pixelDataIn = GetImageData(source, width, height, components);
  501. if (!pixelDataIn)
  502. {
  503. LOGERROR("Could not load image " + source.GetName() + ": " + String(stbi_failure_reason()));
  504. return false;
  505. }
  506. if (components != 3)
  507. {
  508. LOGERROR("Invalid image format, can not load image");
  509. return false;
  510. }
  511. SetSize(COLOR_LUT_SIZE, COLOR_LUT_SIZE, COLOR_LUT_SIZE, components);
  512. SetMemoryUse(width_ * height_ * depth_ * components);
  513. unsigned char* pixelDataOut = GetData();
  514. for (int z = 0; z < depth_; ++z)
  515. {
  516. for (int y = 0; y < height_; ++y)
  517. {
  518. unsigned char* in = &pixelDataIn[z * width_ * 3 + y * width * 3];
  519. unsigned char* out = &pixelDataOut[z * width_ * height_ * 3 + y * width_ * 3];
  520. for (int x = 0; x < width_ * 3; x += 3)
  521. {
  522. out[x] = in[x];
  523. out[x+1] = in[x + 1];
  524. out[x+2] = in[x + 2];
  525. }
  526. }
  527. }
  528. FreeImageData(pixelDataIn);
  529. return true;
  530. }
  531. void Image::FlipVertical()
  532. {
  533. if (!data_)
  534. return;
  535. if (IsCompressed())
  536. {
  537. LOGERROR("FlipVertical not supported for compressed images");
  538. return;
  539. }
  540. if (depth_ > 1)
  541. {
  542. LOGERROR("FlipVertical not supported for 3D images");
  543. return;
  544. }
  545. SharedArrayPtr<unsigned char> newData(new unsigned char[width_ * height_ * components_]);
  546. unsigned rowSize = width_ * components_;
  547. for (int y = 0; y < height_; ++y)
  548. memcpy(&newData[(height_ - y - 1) * rowSize], &data_[y * rowSize], rowSize);
  549. data_ = newData;
  550. }
  551. bool Image::Resize(int width, int height)
  552. {
  553. PROFILE(ResizeImage);
  554. if (IsCompressed())
  555. {
  556. LOGERROR("Resize not supported for compressed images");
  557. return false;
  558. }
  559. if (depth_ > 1)
  560. {
  561. LOGERROR("Resize not supported for 3D images");
  562. return false;
  563. }
  564. if (!data_ || width <= 0 || height <= 0)
  565. return false;
  566. /// \todo Reducing image size does not sample all needed pixels
  567. SharedArrayPtr<unsigned char> newData(new unsigned char[width * height * components_]);
  568. for (int y = 0; y < height; ++y)
  569. {
  570. for (int x = 0; x < width; ++x)
  571. {
  572. // Calculate float coordinates between 0 - 1 for resampling
  573. float xF = (width_ > 1) ? (float)x / (float)(width - 1) : 0.0f;
  574. float yF = (height_ > 1) ? (float)y / (float)(height - 1) : 0.0f;
  575. unsigned uintColor = GetPixelBilinear(xF, yF).ToUInt();
  576. unsigned char* dest = newData + (y * width + x) * components_;
  577. unsigned char* src = (unsigned char*)&uintColor;
  578. switch (components_)
  579. {
  580. case 4:
  581. dest[3] = src[3];
  582. // Fall through
  583. case 3:
  584. dest[2] = src[2];
  585. // Fall through
  586. case 2:
  587. dest[1] = src[1];
  588. // Fall through
  589. default:
  590. dest[0] = src[0];
  591. break;
  592. }
  593. }
  594. }
  595. width_ = width;
  596. height_ = height;
  597. data_ = newData;
  598. SetMemoryUse(width * height * depth_ * components_);
  599. return true;
  600. }
  601. void Image::Clear(const Color& color)
  602. {
  603. ClearInt(color.ToUInt());
  604. }
  605. void Image::ClearInt(unsigned uintColor)
  606. {
  607. PROFILE(ClearImage);
  608. if (!data_)
  609. return;
  610. if (IsCompressed())
  611. {
  612. LOGERROR("Clear not supported for compressed images");
  613. return;
  614. }
  615. unsigned char* src = (unsigned char*)&uintColor;
  616. for (unsigned i = 0; i < width_ * height_ * depth_ * components_; ++i)
  617. data_[i] = src[i % components_];
  618. }
  619. bool Image::SaveBMP(const String& fileName) const
  620. {
  621. PROFILE(SaveImageBMP);
  622. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  623. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  624. {
  625. LOGERROR("Access denied to " + fileName);
  626. return false;
  627. }
  628. if (IsCompressed())
  629. {
  630. LOGERROR("Can not save compressed image to BMP");
  631. return false;
  632. }
  633. if (data_)
  634. return stbi_write_bmp(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  635. else
  636. return false;
  637. }
  638. bool Image::SavePNG(const String& fileName) const
  639. {
  640. PROFILE(SaveImagePNG);
  641. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  642. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  643. {
  644. LOGERROR("Access denied to " + fileName);
  645. return false;
  646. }
  647. if (IsCompressed())
  648. {
  649. LOGERROR("Can not save compressed image to PNG");
  650. return false;
  651. }
  652. if (data_)
  653. return stbi_write_png(GetNativePath(fileName).CString(), width_, height_, components_, data_.Get(), 0) != 0;
  654. else
  655. return false;
  656. }
  657. bool Image::SaveTGA(const String& fileName) const
  658. {
  659. PROFILE(SaveImageTGA);
  660. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  661. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  662. {
  663. LOGERROR("Access denied to " + fileName);
  664. return false;
  665. }
  666. if (IsCompressed())
  667. {
  668. LOGERROR("Can not save compressed image to TGA");
  669. return false;
  670. }
  671. if (data_)
  672. return stbi_write_tga(GetNativePath(fileName).CString(), width_, height_, components_, data_.Get()) != 0;
  673. else
  674. return false;
  675. }
  676. bool Image::SaveJPG(const String & fileName, int quality) const
  677. {
  678. PROFILE(SaveImageJPG);
  679. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  680. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  681. {
  682. LOGERROR("Access denied to " + fileName);
  683. return false;
  684. }
  685. if (IsCompressed())
  686. {
  687. LOGERROR("Can not save compressed image to JPG");
  688. return false;
  689. }
  690. if (data_)
  691. return jo_write_jpg(GetNativePath(fileName).CString(), data_.Get(), width_, height_, components_, quality) != 0;
  692. else
  693. return false;
  694. }
  695. Color Image::GetPixel(int x, int y) const
  696. {
  697. return GetPixel(x, y, 0);
  698. }
  699. Color Image::GetPixel(int x, int y, int z) const
  700. {
  701. if (!data_ || z < 0 || z >= depth_ || IsCompressed())
  702. return Color::BLACK;
  703. x = Clamp(x, 0, width_ - 1);
  704. y = Clamp(y, 0, height_ - 1);
  705. unsigned char* src = data_ + (z * width_ * height_ + y * width_ + x) * components_;
  706. Color ret;
  707. switch (components_)
  708. {
  709. case 4:
  710. ret.a_ = (float)src[3] / 255.0f;
  711. // Fall through
  712. case 3:
  713. ret.b_ = (float)src[2] / 255.0f;
  714. // Fall through
  715. case 2:
  716. ret.g_ = (float)src[1] / 255.0f;
  717. ret.r_ = (float)src[0] / 255.0f;
  718. break;
  719. default:
  720. ret.r_ = ret.g_ = ret.b_ = (float)src[0] / 255.0f;
  721. break;
  722. }
  723. return ret;
  724. }
  725. unsigned Image::GetPixelInt(int x, int y) const
  726. {
  727. return GetPixelInt(x, y, 0);
  728. }
  729. unsigned Image::GetPixelInt(int x, int y, int z) const
  730. {
  731. if (!data_ || z < 0 || z >= depth_ || IsCompressed())
  732. return 0xff000000;
  733. x = Clamp(x, 0, width_ - 1);
  734. y = Clamp(y, 0, height_ - 1);
  735. unsigned char* src = data_ + (z * width_ * height_ + y * width_ + x) * components_;
  736. unsigned ret = 0;
  737. if (components_ < 4)
  738. ret |= 0xff000000;
  739. switch (components_)
  740. {
  741. case 4:
  742. ret |= (unsigned)src[3] << 24;
  743. // Fall through
  744. case 3:
  745. ret |= (unsigned)src[2] << 16;
  746. // Fall through
  747. case 2:
  748. ret |= (unsigned)src[1] << 8;
  749. ret |= (unsigned)src[0];
  750. break;
  751. default:
  752. ret |= (unsigned)src[0] << 16;
  753. ret |= (unsigned)src[0] << 8;
  754. ret |= (unsigned)src[0];
  755. break;
  756. }
  757. return ret;
  758. }
  759. Color Image::GetPixelBilinear(float x, float y) const
  760. {
  761. x = Clamp(x * width_ - 0.5f, 0.0f, (float)(width_ - 1));
  762. y = Clamp(y * height_ - 0.5f, 0.0f, (float)(height_ - 1));
  763. int xI = (int)x;
  764. int yI = (int)y;
  765. float xF = x - floorf(x);
  766. float yF = y - floorf(y);
  767. Color topColor = GetPixel(xI, yI).Lerp(GetPixel(xI + 1, yI), xF);
  768. Color bottomColor = GetPixel(xI, yI + 1).Lerp(GetPixel(xI + 1, yI + 1), xF);
  769. return topColor.Lerp(bottomColor, yF);
  770. }
  771. Color Image::GetPixelTrilinear(float x, float y, float z) const
  772. {
  773. if (depth_ < 2)
  774. return GetPixelBilinear(x, y);
  775. x = Clamp(x * width_ - 0.5f, 0.0f, (float)(width_ - 1));
  776. y = Clamp(y * height_ - 0.5f, 0.0f, (float)(height_ - 1));
  777. z = Clamp(z * depth_ - 0.5f, 0.0f, (float)(depth_ - 1));
  778. int xI = (int)x;
  779. int yI = (int)y;
  780. int zI = (int)z;
  781. if (zI == depth_ - 1)
  782. return GetPixelBilinear(x, y);
  783. float xF = x - floorf(x);
  784. float yF = y - floorf(y);
  785. float zF = z - floorf(z);
  786. Color topColorNear = GetPixel(xI, yI, zI).Lerp(GetPixel(xI + 1, yI, zI), xF);
  787. Color bottomColorNear = GetPixel(xI, yI + 1, zI).Lerp(GetPixel(xI + 1, yI + 1, zI), xF);
  788. Color colorNear = topColorNear.Lerp(bottomColorNear, yF);
  789. Color topColorFar = GetPixel(xI, yI, zI + 1).Lerp(GetPixel(xI + 1, yI, zI + 1), xF);
  790. Color bottomColorFar = GetPixel(xI, yI + 1, zI + 1).Lerp(GetPixel(xI + 1, yI + 1, zI + 1), xF);
  791. Color colorFar = topColorNear.Lerp(bottomColorNear, yF);
  792. return colorNear.Lerp(colorFar, zF);
  793. }
  794. SharedPtr<Image> Image::GetNextLevel() const
  795. {
  796. if (IsCompressed())
  797. {
  798. LOGERROR("Can not generate mip level from compressed data");
  799. return SharedPtr<Image>();
  800. }
  801. if (components_ < 1 || components_ > 4)
  802. {
  803. LOGERROR("Illegal number of image components for mip level generation");
  804. return SharedPtr<Image>();
  805. }
  806. int widthOut = width_ / 2;
  807. int heightOut = height_ / 2;
  808. int depthOut = depth_ / 2;
  809. if (widthOut < 1)
  810. widthOut = 1;
  811. if (heightOut < 1)
  812. heightOut = 1;
  813. if (depthOut < 1)
  814. depthOut = 1;
  815. SharedPtr<Image> mipImage(new Image(context_));
  816. if (depth_ > 1)
  817. mipImage->SetSize(widthOut, heightOut, depthOut, components_);
  818. else
  819. mipImage->SetSize(widthOut, heightOut, components_);
  820. const unsigned char* pixelDataIn = data_.Get();
  821. unsigned char* pixelDataOut = mipImage->data_.Get();
  822. // 1D case
  823. if (depth_ == 1 && (height_ == 1 || width_ == 1))
  824. {
  825. // Loop using the larger dimension
  826. if (widthOut < heightOut)
  827. widthOut = heightOut;
  828. switch (components_)
  829. {
  830. case 1:
  831. for (int x = 0; x < widthOut; ++x)
  832. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+1]) >> 1;
  833. break;
  834. case 2:
  835. for (int x = 0; x < widthOut*2; x += 2)
  836. {
  837. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+2]) >> 1;
  838. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+3]) >> 1;
  839. }
  840. break;
  841. case 3:
  842. for (int x = 0; x < widthOut*3; x += 3)
  843. {
  844. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+3]) >> 1;
  845. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+4]) >> 1;
  846. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+5]) >> 1;
  847. }
  848. break;
  849. case 4:
  850. for (int x = 0; x < widthOut*4; x += 4)
  851. {
  852. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+4]) >> 1;
  853. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+5]) >> 1;
  854. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+6]) >> 1;
  855. pixelDataOut[x+3] = ((unsigned)pixelDataIn[x*2+3] + pixelDataIn[x*2+7]) >> 1;
  856. }
  857. break;
  858. }
  859. }
  860. // 2D case
  861. else if (depth_ == 1)
  862. {
  863. switch (components_)
  864. {
  865. case 1:
  866. for (int y = 0; y < heightOut; ++y)
  867. {
  868. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_];
  869. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_];
  870. unsigned char* out = &pixelDataOut[y*widthOut];
  871. for (int x = 0; x < widthOut; ++x)
  872. {
  873. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+1] + inLower[x*2] + inLower[x*2+1]) >> 2;
  874. }
  875. }
  876. break;
  877. case 2:
  878. for (int y = 0; y < heightOut; ++y)
  879. {
  880. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*2];
  881. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*2];
  882. unsigned char* out = &pixelDataOut[y*widthOut*2];
  883. for (int x = 0; x < widthOut*2; x += 2)
  884. {
  885. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+2] + inLower[x*2] + inLower[x*2+2]) >> 2;
  886. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+3] + inLower[x*2+1] + inLower[x*2+3]) >> 2;
  887. }
  888. }
  889. break;
  890. case 3:
  891. for (int y = 0; y < heightOut; ++y)
  892. {
  893. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*3];
  894. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*3];
  895. unsigned char* out = &pixelDataOut[y*widthOut*3];
  896. for (int x = 0; x < widthOut*3; x += 3)
  897. {
  898. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+3] + inLower[x*2] + inLower[x*2+3]) >> 2;
  899. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+4] + inLower[x*2+1] + inLower[x*2+4]) >> 2;
  900. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+5] + inLower[x*2+2] + inLower[x*2+5]) >> 2;
  901. }
  902. }
  903. break;
  904. case 4:
  905. for (int y = 0; y < heightOut; ++y)
  906. {
  907. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*4];
  908. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*4];
  909. unsigned char* out = &pixelDataOut[y*widthOut*4];
  910. for (int x = 0; x < widthOut*4; x += 4)
  911. {
  912. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+4] + inLower[x*2] + inLower[x*2+4]) >> 2;
  913. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+5] + inLower[x*2+1] + inLower[x*2+5]) >> 2;
  914. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+6] + inLower[x*2+2] + inLower[x*2+6]) >> 2;
  915. out[x+3] = ((unsigned)inUpper[x*2+3] + inUpper[x*2+7] + inLower[x*2+3] + inLower[x*2+7]) >> 2;
  916. }
  917. }
  918. break;
  919. }
  920. }
  921. // 3D case
  922. else
  923. {
  924. switch (components_)
  925. {
  926. case 1:
  927. for (int z = 0; z < depthOut; ++z)
  928. {
  929. const unsigned char* inOuter = &pixelDataIn[(z*2)*width_*height_];
  930. const unsigned char* inInner = &pixelDataIn[(z*2+1)*width_*height_];
  931. for (int y = 0; y < heightOut; ++y)
  932. {
  933. const unsigned char* inOuterUpper = &inOuter[(y*2)*width_];
  934. const unsigned char* inOuterLower = &inOuter[(y*2+1)*width_];
  935. const unsigned char* inInnerUpper = &inInner[(y*2)*width_];
  936. const unsigned char* inInnerLower = &inInner[(y*2+1)*width_];
  937. unsigned char* out = &pixelDataOut[z*widthOut*heightOut + y*widthOut];
  938. for (int x = 0; x < widthOut; ++x)
  939. {
  940. out[x] = ((unsigned)inOuterUpper[x*2] + inOuterUpper[x*2+1] + inOuterLower[x*2] + inOuterLower[x*2+1] +
  941. inInnerUpper[x*2] + inInnerUpper[x*2+1] + inInnerLower[x*2] + inInnerLower[x*2+1]) >> 3;
  942. }
  943. }
  944. }
  945. break;
  946. case 2:
  947. for (int z = 0; z < depthOut; ++z)
  948. {
  949. const unsigned char* inOuter = &pixelDataIn[(z*2)*width_*height_*2];
  950. const unsigned char* inInner = &pixelDataIn[(z*2+1)*width_*height_*2];
  951. for (int y = 0; y < heightOut; ++y)
  952. {
  953. const unsigned char* inOuterUpper = &inOuter[(y*2)*width_*2];
  954. const unsigned char* inOuterLower = &inOuter[(y*2+1)*width_*2];
  955. const unsigned char* inInnerUpper = &inInner[(y*2)*width_*2];
  956. const unsigned char* inInnerLower = &inInner[(y*2+1)*width_*2];
  957. unsigned char* out = &pixelDataOut[z*widthOut*heightOut*2 + y*widthOut*2];
  958. for (int x = 0; x < widthOut*2; x += 2)
  959. {
  960. out[x] = ((unsigned)inOuterUpper[x*2] + inOuterUpper[x*2+2] + inOuterLower[x*2] + inOuterLower[x*2+2] +
  961. inInnerUpper[x*2] + inInnerUpper[x*2+2] + inInnerLower[x*2] + inInnerLower[x*2+2]) >> 3;
  962. out[x+1] = ((unsigned)inOuterUpper[x*2+1] + inOuterUpper[x*2+3] + inOuterLower[x*2+1] + inOuterLower[x*2+3] +
  963. inInnerUpper[x*2+1] + inInnerUpper[x*2+3] + inInnerLower[x*2+1] + inInnerLower[x*2+3]) >> 3;
  964. }
  965. }
  966. }
  967. break;
  968. case 3:
  969. for (int z = 0; z < depthOut; ++z)
  970. {
  971. const unsigned char* inOuter = &pixelDataIn[(z*2)*width_*height_*3];
  972. const unsigned char* inInner = &pixelDataIn[(z*2+1)*width_*height_*3];
  973. for (int y = 0; y < heightOut; ++y)
  974. {
  975. const unsigned char* inOuterUpper = &inOuter[(y*2)*width_*3];
  976. const unsigned char* inOuterLower = &inOuter[(y*2+1)*width_*3];
  977. const unsigned char* inInnerUpper = &inInner[(y*2)*width_*3];
  978. const unsigned char* inInnerLower = &inInner[(y*2+1)*width_*3];
  979. unsigned char* out = &pixelDataOut[z*widthOut*heightOut*3 + y*widthOut*3];
  980. for (int x = 0; x < widthOut*3; x += 3)
  981. {
  982. out[x] = ((unsigned)inOuterUpper[x*2] + inOuterUpper[x*2+3] + inOuterLower[x*2] + inOuterLower[x*2+3] +
  983. inInnerUpper[x*2] + inInnerUpper[x*2+3] + inInnerLower[x*2] + inInnerLower[x*2+3]) >> 3;
  984. out[x+1] = ((unsigned)inOuterUpper[x*2+1] + inOuterUpper[x*2+4] + inOuterLower[x*2+1] + inOuterLower[x*2+4] +
  985. inInnerUpper[x*2+1] + inInnerUpper[x*2+4] + inInnerLower[x*2+1] + inInnerLower[x*2+4]) >> 3;
  986. out[x+2] = ((unsigned)inOuterUpper[x*2+2] + inOuterUpper[x*2+5] + inOuterLower[x*2+2] + inOuterLower[x*2+5] +
  987. inInnerUpper[x*2+2] + inInnerUpper[x*2+5] + inInnerLower[x*2+2] + inInnerLower[x*2+5]) >> 3;
  988. }
  989. }
  990. }
  991. break;
  992. case 4:
  993. for (int z = 0; z < depthOut; ++z)
  994. {
  995. const unsigned char* inOuter = &pixelDataIn[(z*2)*width_*height_*4];
  996. const unsigned char* inInner = &pixelDataIn[(z*2+1)*width_*height_*4];
  997. for (int y = 0; y < heightOut; ++y)
  998. {
  999. const unsigned char* inOuterUpper = &inOuter[(y*2)*width_*4];
  1000. const unsigned char* inOuterLower = &inOuter[(y*2+1)*width_*4];
  1001. const unsigned char* inInnerUpper = &inInner[(y*2)*width_*4];
  1002. const unsigned char* inInnerLower = &inInner[(y*2+1)*width_*4];
  1003. unsigned char* out = &pixelDataOut[z*widthOut*heightOut*4 + y*widthOut*4];
  1004. for (int x = 0; x < widthOut*4; x += 4)
  1005. {
  1006. out[x] = ((unsigned)inOuterUpper[x*2] + inOuterUpper[x*2+4] + inOuterLower[x*2] + inOuterLower[x*2+4] +
  1007. inInnerUpper[x*2] + inInnerUpper[x*2+4] + inInnerLower[x*2] + inInnerLower[x*2+4]) >> 3;
  1008. out[x+1] = ((unsigned)inOuterUpper[x*2+1] + inOuterUpper[x*2+5] + inOuterLower[x*2+1] + inOuterLower[x*2+5] +
  1009. inInnerUpper[x*2+1] + inInnerUpper[x*2+5] + inInnerLower[x*2+1] + inInnerLower[x*2+5]) >> 3;
  1010. out[x+2] = ((unsigned)inOuterUpper[x*2+2] + inOuterUpper[x*2+6] + inOuterLower[x*2+2] + inOuterLower[x*2+6] +
  1011. inInnerUpper[x*2+2] + inInnerUpper[x*2+6] + inInnerLower[x*2+2] + inInnerLower[x*2+6]) >> 3;
  1012. }
  1013. }
  1014. }
  1015. break;
  1016. }
  1017. }
  1018. return mipImage;
  1019. }
  1020. CompressedLevel Image::GetCompressedLevel(unsigned index) const
  1021. {
  1022. CompressedLevel level;
  1023. if (compressedFormat_ == CF_NONE)
  1024. {
  1025. LOGERROR("Image is not compressed");
  1026. return level;
  1027. }
  1028. if (index >= numCompressedLevels_)
  1029. {
  1030. LOGERROR("Compressed image mip level out of bounds");
  1031. return level;
  1032. }
  1033. level.format_ = compressedFormat_;
  1034. level.width_ = width_;
  1035. level.height_ = height_;
  1036. level.depth_ = depth_;
  1037. if (compressedFormat_ < CF_PVRTC_RGB_2BPP)
  1038. {
  1039. level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
  1040. unsigned i = 0;
  1041. unsigned offset = 0;
  1042. for (;;)
  1043. {
  1044. if (!level.width_)
  1045. level.width_ = 1;
  1046. if (!level.height_)
  1047. level.height_ = 1;
  1048. if (!level.depth_)
  1049. level.depth_ = 1;
  1050. level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
  1051. level.rows_ = ((level.height_ + 3) / 4);
  1052. level.data_ = data_.Get() + offset;
  1053. level.dataSize_ = level.depth_ * level.rows_ * level.rowSize_;
  1054. if (offset + level.dataSize_ > GetMemoryUse())
  1055. {
  1056. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  1057. " Datasize: " + String(GetMemoryUse()));
  1058. level.data_ = 0;
  1059. return level;
  1060. }
  1061. if (i == index)
  1062. return level;
  1063. offset += level.dataSize_;
  1064. level.width_ /= 2;
  1065. level.height_ /= 2;
  1066. level.depth_ /= 2;
  1067. ++i;
  1068. }
  1069. }
  1070. else
  1071. {
  1072. level.blockSize_ = compressedFormat_ < CF_PVRTC_RGB_4BPP ? 2 : 4;
  1073. unsigned i = 0;
  1074. unsigned offset = 0;
  1075. for (;;)
  1076. {
  1077. if (!level.width_)
  1078. level.width_ = 1;
  1079. if (!level.height_)
  1080. level.height_ = 1;
  1081. int dataWidth = Max(level.width_, level.blockSize_ == 2 ? 16 : 8);
  1082. int dataHeight = Max(level.height_, 8);
  1083. level.data_ = data_.Get() + offset;
  1084. level.dataSize_ = (dataWidth * dataHeight * level.blockSize_ + 7) >> 3;
  1085. level.rows_ = dataHeight;
  1086. level.rowSize_ = level.dataSize_ / level.rows_;
  1087. if (offset + level.dataSize_ > GetMemoryUse())
  1088. {
  1089. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  1090. " Datasize: " + String(GetMemoryUse()));
  1091. level.data_ = 0;
  1092. return level;
  1093. }
  1094. if (i == index)
  1095. return level;
  1096. offset += level.dataSize_;
  1097. level.width_ /= 2;
  1098. level.height_ /= 2;
  1099. ++i;
  1100. }
  1101. }
  1102. }
  1103. Image* Image::GetSubimage(const IntRect& rect) const
  1104. {
  1105. if (!data_)
  1106. return 0;
  1107. if (IsCompressed())
  1108. {
  1109. LOGERROR("Can not get subimage from compressed image " + GetName());
  1110. return 0;
  1111. }
  1112. if (rect.left_ < 0 || rect.top_ < 0 || rect.right_ >= width_ || rect.bottom_ >= height_)
  1113. {
  1114. LOGERROR("Can not get subimage from image " + GetName() + " with invalid region");
  1115. return 0;
  1116. }
  1117. int x = rect.left_;
  1118. int y = rect.top_;
  1119. int width = rect.Width();
  1120. int height = rect.Height();
  1121. Image* image = new Image(context_);
  1122. image->SetSize(width, height, components_);
  1123. unsigned char* dest = image->GetData();
  1124. unsigned char* source = data_.Get() + (y * width_ + x) * components_;
  1125. for (int i = 0; i < height; ++i)
  1126. {
  1127. memcpy(dest, source, width * components_);
  1128. dest += width * components_;
  1129. source += width_ * components_;
  1130. }
  1131. return image;
  1132. }
  1133. SDL_Surface* Image::GetSDLSurface(const IntRect& rect) const
  1134. {
  1135. if (!data_)
  1136. return 0;
  1137. if (IsCompressed())
  1138. {
  1139. LOGERROR("Can not get SDL surface from compressed image " + GetName());
  1140. return 0;
  1141. }
  1142. if (components_ < 3)
  1143. {
  1144. LOGERROR("Can not get SDL surface from image " + GetName() + " with less than 3 components");
  1145. return 0;
  1146. }
  1147. IntRect imageRect = rect;
  1148. // Use full image if illegal rect
  1149. if (imageRect.left_ < 0 || imageRect.top_ < 0 || imageRect.right_ > width_ || imageRect.bottom_ > height_ ||
  1150. imageRect.left_ >= imageRect.right_ || imageRect.top_ >= imageRect.bottom_)
  1151. {
  1152. imageRect.left_ = 0;
  1153. imageRect.top_ = 0;
  1154. imageRect.right_ = width_;
  1155. imageRect.bottom_ = height_;
  1156. }
  1157. int imageWidth = width_;
  1158. int width = imageRect.Width();
  1159. int height = imageRect.Height();
  1160. // Assume little-endian for all the supported platforms
  1161. unsigned rMask = 0x000000ff;
  1162. unsigned gMask = 0x0000ff00;
  1163. unsigned bMask = 0x00ff0000;
  1164. unsigned aMask = 0xff000000;
  1165. SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, components_ * 8, rMask, gMask, bMask, aMask);
  1166. if (surface)
  1167. {
  1168. SDL_LockSurface(surface);
  1169. unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
  1170. unsigned char* source = data_ + components_ * (imageWidth * imageRect.top_ + imageRect.left_);
  1171. for (int i = 0; i < height; ++i)
  1172. {
  1173. memcpy(destination, source, components_ * width);
  1174. destination += surface->pitch;
  1175. source += components_ * imageWidth;
  1176. }
  1177. SDL_UnlockSurface(surface);
  1178. }
  1179. else
  1180. LOGERROR("Failed to create SDL surface from image " + GetName());
  1181. return surface;
  1182. }
  1183. unsigned char* Image::GetImageData(Deserializer& source, int& width, int& height, unsigned& components)
  1184. {
  1185. unsigned dataSize = source.GetSize();
  1186. SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
  1187. source.Read(buffer.Get(), dataSize);
  1188. return stbi_load_from_memory(buffer.Get(), dataSize, &width, &height, (int *)&components, 0);
  1189. }
  1190. void Image::FreeImageData(unsigned char* pixelData)
  1191. {
  1192. if (!pixelData)
  1193. return;
  1194. stbi_image_free(pixelData);
  1195. }
  1196. }