2
0

Image.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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. void 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 (data_)
  171. squish::DecompressImage(dest, width_, height_, data_, flags);
  172. }
  173. OBJECTTYPESTATIC(Image);
  174. Image::Image(Context* context) :
  175. Resource(context),
  176. width_(0),
  177. height_(0),
  178. components_(0)
  179. {
  180. }
  181. Image::~Image()
  182. {
  183. }
  184. void Image::RegisterObject(Context* context)
  185. {
  186. context->RegisterFactory<Image>();
  187. }
  188. bool Image::Load(Deserializer& source)
  189. {
  190. // Check for DDS compressed format
  191. if (source.ReadFileID() != "DDS ")
  192. {
  193. // Not DDS, use STBImage to load other image formats as uncompressed
  194. source.Seek(0);
  195. int width, height;
  196. unsigned components;
  197. unsigned char* pixelData = GetImageData(source, width, height, components);
  198. if (!pixelData)
  199. {
  200. LOGERROR("Could not load image: " + String(stbi_failure_reason()));
  201. return false;
  202. }
  203. SetSize(width, height, components);
  204. SetData(pixelData);
  205. FreeImageData(pixelData);
  206. }
  207. else
  208. {
  209. // DDS compressed format
  210. DDSurfaceDesc2 ddsd;
  211. source.Read(&ddsd, sizeof(ddsd));
  212. switch (ddsd.ddpfPixelFormat_.dwFourCC_)
  213. {
  214. case FOURCC_DXT1:
  215. compressedFormat_ = CF_DXT1;
  216. components_ = 3;
  217. break;
  218. case FOURCC_DXT3:
  219. compressedFormat_ = CF_DXT3;
  220. components_ = 4;
  221. break;
  222. case FOURCC_DXT5:
  223. compressedFormat_ = CF_DXT5;
  224. components_ = 4;
  225. break;
  226. default:
  227. LOGERROR("Unsupported DDS format");
  228. return false;
  229. }
  230. unsigned dataSize = source.GetSize() - source.GetPosition();
  231. data_ = new unsigned char[dataSize];
  232. width_ = ddsd.dwWidth_;
  233. height_ = ddsd.dwHeight_;
  234. numCompressedLevels_ = ddsd.dwMipMapCount_;
  235. if (!numCompressedLevels_)
  236. numCompressedLevels_ = 1;
  237. SetMemoryUse(dataSize);
  238. source.Read(data_.Get(), dataSize);
  239. }
  240. return true;
  241. }
  242. void Image::SetSize(int width, int height, unsigned components)
  243. {
  244. if (width == width_ && height == height_ && components == components_)
  245. return;
  246. if (width <= 0 || height <= 0)
  247. return;
  248. data_ = new unsigned char[width * height * components];
  249. width_ = width;
  250. height_ = height;
  251. components_ = components;
  252. compressedFormat_ = CF_NONE;
  253. numCompressedLevels_ = 0;
  254. SetMemoryUse(width * height * components);
  255. }
  256. void Image::SetData(const unsigned char* pixelData)
  257. {
  258. memcpy(data_.Get(), pixelData, width_ * height_ * components_);
  259. }
  260. bool Image::SaveBMP(const String& fileName)
  261. {
  262. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  263. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  264. {
  265. LOGERROR("Access denied to " + fileName);
  266. return false;
  267. }
  268. if (IsCompressed())
  269. {
  270. LOGERROR("Can not save compressed image to BMP");
  271. return false;
  272. }
  273. if (data_)
  274. return stbi_write_bmp(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  275. else
  276. return false;
  277. }
  278. bool Image::SaveTGA(const String& fileName)
  279. {
  280. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  281. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  282. {
  283. LOGERROR("Access denied to " + fileName);
  284. return false;
  285. }
  286. if (IsCompressed())
  287. {
  288. LOGERROR("Can not save compressed image to TGA");
  289. return false;
  290. }
  291. if (data_)
  292. return stbi_write_tga(fileName.CString(), width_, height_, components_, data_.Get()) != 0;
  293. else
  294. return false;
  295. }
  296. unsigned char* Image::GetImageData(Deserializer& source, int& width, int& height, unsigned& components)
  297. {
  298. unsigned dataSize = source.GetSize();
  299. SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
  300. source.Read(buffer.Get(), dataSize);
  301. return stbi_load_from_memory(buffer.Get(), dataSize, &width, &height, (int *)&components, 0);
  302. }
  303. void Image::FreeImageData(unsigned char* pixelData)
  304. {
  305. if (!pixelData)
  306. return;
  307. stbi_image_free(pixelData);
  308. }
  309. SharedPtr<Image> Image::GetNextLevel() const
  310. {
  311. if (IsCompressed())
  312. {
  313. LOGERROR("Can not generate mip level from compressed data");
  314. return SharedPtr<Image>();
  315. }
  316. if (components_ < 1 || components_ > 4)
  317. {
  318. LOGERROR("Illegal number of image components for mip level generation");
  319. return SharedPtr<Image>();
  320. }
  321. int widthOut = width_ / 2;
  322. int heightOut = height_ / 2;
  323. if (widthOut < 1)
  324. widthOut = 1;
  325. if (heightOut < 1)
  326. heightOut = 1;
  327. SharedPtr<Image> mipImage(new Image(context_));
  328. mipImage->SetSize(widthOut, heightOut, components_);
  329. const unsigned char* pixelDataIn = data_.Get();
  330. unsigned char* pixelDataOut = mipImage->data_.Get();
  331. // 1D case
  332. if (height_ == 1 || width_ == 1)
  333. {
  334. // Loop using the larger dimension
  335. if (widthOut < heightOut)
  336. widthOut = heightOut;
  337. switch (components_)
  338. {
  339. case 1:
  340. for (int x = 0; x < widthOut; ++x)
  341. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+1]) >> 1;
  342. break;
  343. case 2:
  344. for (int x = 0; x < widthOut*2; x += 2)
  345. {
  346. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+2]) >> 1;
  347. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+3]) >> 1;
  348. }
  349. break;
  350. case 3:
  351. for (int x = 0; x < widthOut*3; x += 3)
  352. {
  353. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+3]) >> 1;
  354. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+4]) >> 1;
  355. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+5]) >> 1;
  356. }
  357. break;
  358. case 4:
  359. for (int x = 0; x < widthOut*4; x += 4)
  360. {
  361. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+4]) >> 1;
  362. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+5]) >> 1;
  363. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+6]) >> 1;
  364. pixelDataOut[x+3] = ((unsigned)pixelDataIn[x*2+3] + pixelDataIn[x*2+7]) >> 1;
  365. }
  366. break;
  367. }
  368. }
  369. // 2D case
  370. else
  371. {
  372. switch (components_)
  373. {
  374. case 1:
  375. for (int y = 0; y < heightOut; ++y)
  376. {
  377. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_];
  378. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_];
  379. unsigned char* out = &pixelDataOut[y*widthOut];
  380. for (int x = 0; x < widthOut; ++x)
  381. {
  382. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+1] + inLower[x*2] + inLower[x*2+1]) >> 2;
  383. }
  384. }
  385. break;
  386. case 2:
  387. for (int y = 0; y < heightOut; ++y)
  388. {
  389. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*2];
  390. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*2];
  391. unsigned char* out = &pixelDataOut[y*widthOut*2];
  392. for (int x = 0; x < widthOut*2; x += 2)
  393. {
  394. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+2] + inLower[x*2] + inLower[x*2+2]) >> 2;
  395. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+3] + inLower[x*2+1] + inLower[x*2+3]) >> 2;
  396. }
  397. }
  398. break;
  399. case 3:
  400. for (int y = 0; y < heightOut; ++y)
  401. {
  402. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*3];
  403. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*3];
  404. unsigned char* out = &pixelDataOut[y*widthOut*3];
  405. for (int x = 0; x < widthOut*3; x += 3)
  406. {
  407. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+3] + inLower[x*2] + inLower[x*2+3]) >> 2;
  408. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+4] + inLower[x*2+1] + inLower[x*2+4]) >> 2;
  409. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+5] + inLower[x*2+2] + inLower[x*2+5]) >> 2;
  410. }
  411. }
  412. break;
  413. case 4:
  414. for (int y = 0; y < heightOut; ++y)
  415. {
  416. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*4];
  417. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*4];
  418. unsigned char* out = &pixelDataOut[y*widthOut*4];
  419. for (int x = 0; x < widthOut*4; x += 4)
  420. {
  421. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+4] + inLower[x*2] + inLower[x*2+4]) >> 2;
  422. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+5] + inLower[x*2+1] + inLower[x*2+5]) >> 2;
  423. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+6] + inLower[x*2+2] + inLower[x*2+6]) >> 2;
  424. out[x+3] = ((unsigned)inUpper[x*2+3] + inUpper[x*2+7] + inLower[x*2+3] + inLower[x*2+7]) >> 2;
  425. }
  426. }
  427. break;
  428. }
  429. }
  430. return mipImage;
  431. }
  432. CompressedLevel Image::GetCompressedLevel(unsigned index) const
  433. {
  434. CompressedLevel level;
  435. if (compressedFormat_ == CF_NONE)
  436. {
  437. LOGERROR("Image is not compressed");
  438. return level;
  439. }
  440. if (index >= numCompressedLevels_)
  441. {
  442. LOGERROR("Compressed image mip level out of bounds");
  443. return level;
  444. }
  445. level.compressedFormat_ = compressedFormat_;
  446. level.width_ = width_;
  447. level.height_ = height_;
  448. level.blockSize_ = compressedFormat_ == CF_DXT1 ? 8 : 16;
  449. unsigned i = 0;
  450. unsigned offset = 0;
  451. for (;;)
  452. {
  453. if (!level.width_)
  454. level.width_ = 1;
  455. if (!level.height_)
  456. level.height_ = 1;
  457. level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
  458. level.rows_ = ((level.height_ + 3) / 4);
  459. level.data_ = data_.Get() + offset;
  460. level.dataSize_ = level.rows_ * level.rowSize_;
  461. if (offset + level.dataSize_ > GetMemoryUse())
  462. {
  463. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  464. " Datasize: " + String(GetMemoryUse()));
  465. level.data_ = 0;
  466. return level;
  467. }
  468. if (i == index)
  469. return level;
  470. offset += level.dataSize_;
  471. level.width_ /= 2;
  472. level.height_ /= 2;
  473. ++i;
  474. }
  475. }