Image.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 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 <stb_image.h>
  31. #include <stb_image_write.h>
  32. #include "DebugNew.h"
  33. #ifndef MAKEFOURCC
  34. #define MAKEFOURCC(ch0, ch1, ch2, ch3) ((unsigned)(ch0) | ((unsigned)(ch1) << 8) | ((unsigned)(ch2) << 16) | ((unsigned)(ch3) << 24))
  35. #endif
  36. #define FOURCC_DXT1 (MAKEFOURCC('D','X','T','1'))
  37. #define FOURCC_DXT2 (MAKEFOURCC('D','X','T','2'))
  38. #define FOURCC_DXT3 (MAKEFOURCC('D','X','T','3'))
  39. #define FOURCC_DXT4 (MAKEFOURCC('D','X','T','4'))
  40. #define FOURCC_DXT5 (MAKEFOURCC('D','X','T','5'))
  41. /// DirectDraw surface color key
  42. struct DDColorKey
  43. {
  44. unsigned dwColorSpaceLowValue_;
  45. unsigned dwColorSpaceHighValue_;
  46. };
  47. /// DirectDraw surface pixel format
  48. struct DDPixelFormat
  49. {
  50. unsigned dwSize_;
  51. unsigned dwFlags_;
  52. unsigned dwFourCC_;
  53. union
  54. {
  55. unsigned dwRGBBitCount_;
  56. unsigned dwYUVBitCount_;
  57. unsigned dwZBufferBitDepth_;
  58. unsigned dwAlphaBitDepth_;
  59. unsigned dwLuminanceBitCount_;
  60. unsigned dwBumpBitCount_;
  61. unsigned dwPrivateFormatBitCount_;
  62. };
  63. union
  64. {
  65. unsigned dwRBitMask_;
  66. unsigned dwYBitMask_;
  67. unsigned dwStencilBitDepth_;
  68. unsigned dwLuminanceBitMask_;
  69. unsigned dwBumpDuBitMask_;
  70. unsigned dwOperations_;
  71. };
  72. union
  73. {
  74. unsigned dwGBitMask_;
  75. unsigned dwUBitMask_;
  76. unsigned dwZBitMask_;
  77. unsigned dwBumpDvBitMask_;
  78. struct
  79. {
  80. unsigned short wFlipMSTypes_;
  81. unsigned short wBltMSTypes_;
  82. } multiSampleCaps_;
  83. };
  84. union
  85. {
  86. unsigned dwBBitMask_;
  87. unsigned dwVBitMask_;
  88. unsigned dwStencilBitMask_;
  89. unsigned dwBumpLuminanceBitMask_;
  90. };
  91. union
  92. {
  93. unsigned dwRGBAlphaBitMask_;
  94. unsigned dwYUVAlphaBitMask_;
  95. unsigned dwLuminanceAlphaBitMask_;
  96. unsigned dwRGBZBitMask_;
  97. unsigned dwYUVZBitMask_;
  98. };
  99. };
  100. /// DirectDraw surface capabilities
  101. struct DDSCaps2
  102. {
  103. unsigned dwCaps_;
  104. unsigned dwCaps2_;
  105. unsigned dwCaps3_;
  106. union
  107. {
  108. unsigned dwCaps4_;
  109. unsigned dwVolumeDepth_;
  110. };
  111. };
  112. /// DirectDraw surface description
  113. struct DDSurfaceDesc2
  114. {
  115. unsigned dwSize_;
  116. unsigned dwFlags_;
  117. unsigned dwHeight_;
  118. unsigned dwWidth_;
  119. union
  120. {
  121. long 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. void* lpSurface_;
  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. OBJECTTYPESTATIC(Image);
  155. Image::Image(Context* context) :
  156. Resource(context),
  157. width_(0),
  158. height_(0),
  159. components_(0)
  160. {
  161. }
  162. Image::~Image()
  163. {
  164. }
  165. void Image::RegisterObject(Context* context)
  166. {
  167. context->RegisterFactory<Image>();
  168. }
  169. bool Image::Load(Deserializer& source)
  170. {
  171. // Check for DDS compressed format
  172. if (source.ReadID() != "DDS ")
  173. {
  174. // Not DDS, use STBImage to load other image formats as uncompressed
  175. source.Seek(0);
  176. int width, height;
  177. unsigned components;
  178. unsigned char* pixelData = GetImageData(source, width, height, components);
  179. if (!pixelData)
  180. {
  181. LOGERROR("Could not load image: " + String(stbi_failure_reason()));
  182. return false;
  183. }
  184. SetSize(width, height, components);
  185. SetData(pixelData);
  186. FreeImageData(pixelData);
  187. }
  188. else
  189. {
  190. // DDS compressed format
  191. DDSurfaceDesc2 ddsd;
  192. source.Read(&ddsd, sizeof(ddsd));
  193. switch (ddsd.ddpfPixelFormat_.dwFourCC_)
  194. {
  195. case FOURCC_DXT1:
  196. compressedFormat_ = CF_DXT1;
  197. components_ = 3;
  198. break;
  199. case FOURCC_DXT3:
  200. compressedFormat_ = CF_DXT3;
  201. components_ = 4;
  202. break;
  203. case FOURCC_DXT5:
  204. compressedFormat_ = CF_DXT5;
  205. components_ = 4;
  206. break;
  207. default:
  208. LOGERROR("Unsupported DDS format");
  209. return false;
  210. }
  211. unsigned dataSize = source.GetSize() - source.GetPosition();
  212. data_ = new unsigned char[dataSize];
  213. width_ = ddsd.dwWidth_;
  214. height_ = ddsd.dwHeight_;
  215. numCompressedLevels_ = ddsd.dwMipMapCount_;
  216. if (!numCompressedLevels_)
  217. numCompressedLevels_ = 1;
  218. SetMemoryUse(dataSize);
  219. source.Read(data_.GetPtr(), dataSize);
  220. }
  221. return true;
  222. }
  223. void Image::SetSize(unsigned width, unsigned height, unsigned components)
  224. {
  225. if (width == width_ && height == height_ && components == components_)
  226. return;
  227. if (width <= 0 || height <= 0)
  228. return;
  229. data_ = new unsigned char[width * height * components];
  230. width_ = width;
  231. height_ = height;
  232. components_ = components;
  233. compressedFormat_ = CF_NONE;
  234. numCompressedLevels_ = 0;
  235. SetMemoryUse(width * height * components);
  236. }
  237. void Image::SetData(const unsigned char* pixelData)
  238. {
  239. memcpy(data_.GetPtr(), pixelData, width_ * height_ * components_);
  240. }
  241. bool Image::SaveBMP(const String& fileName)
  242. {
  243. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  244. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  245. {
  246. LOGERROR("Access denied to " + fileName);
  247. return false;
  248. }
  249. if (IsCompressed())
  250. {
  251. LOGERROR("Can not save compressed image to BMP");
  252. return false;
  253. }
  254. if (data_)
  255. return stbi_write_bmp(fileName.CString(), width_, height_, components_, data_.GetPtr()) != 0;
  256. else
  257. return false;
  258. }
  259. bool Image::SaveTGA(const String& fileName)
  260. {
  261. FileSystem* fileSystem = GetSubsystem<FileSystem>();
  262. if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
  263. {
  264. LOGERROR("Access denied to " + fileName);
  265. return false;
  266. }
  267. if (IsCompressed())
  268. {
  269. LOGERROR("Can not save compressed image to TGA");
  270. return false;
  271. }
  272. if (data_)
  273. return stbi_write_tga(fileName.CString(), width_, height_, components_, data_.GetPtr()) != 0;
  274. else
  275. return false;
  276. }
  277. unsigned char* Image::GetImageData(Deserializer& source, int& width, int& height, unsigned& components)
  278. {
  279. unsigned dataSize = source.GetSize();
  280. SharedArrayPtr<unsigned char> buffer(new unsigned char[dataSize]);
  281. source.Read(buffer.GetPtr(), dataSize);
  282. return stbi_load_from_memory(buffer.GetPtr(), dataSize, &width, &height, (int *)&components, 0);
  283. }
  284. void Image::FreeImageData(unsigned char* pixelData)
  285. {
  286. if (!pixelData)
  287. return;
  288. stbi_image_free(pixelData);
  289. }
  290. SharedPtr<Image> Image::GetNextLevel() const
  291. {
  292. if (IsCompressed())
  293. {
  294. LOGERROR("Can not generate mip level from compressed data");
  295. return SharedPtr<Image>();
  296. }
  297. if (components_ < 1 || components_ > 4)
  298. {
  299. LOGERROR("Illegal number of image components for mip level generation");
  300. return SharedPtr<Image>();
  301. }
  302. int widthOut = width_ / 2;
  303. int heightOut = height_ / 2;
  304. if (widthOut < 1)
  305. widthOut = 1;
  306. if (heightOut < 1)
  307. heightOut = 1;
  308. SharedPtr<Image> mipImage(new Image(context_));
  309. mipImage->SetSize(widthOut, heightOut, components_);
  310. const unsigned char* pixelDataIn = data_.GetPtr();
  311. unsigned char* pixelDataOut = mipImage->data_.GetPtr();
  312. // 1D case
  313. if (height_ == 1 || width_ == 1)
  314. {
  315. // Loop using the larger dimension
  316. if (widthOut < heightOut)
  317. widthOut = heightOut;
  318. switch (components_)
  319. {
  320. case 1:
  321. for (int x = 0; x < widthOut; ++x)
  322. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+1]) >> 1;
  323. break;
  324. case 2:
  325. for (int x = 0; x < widthOut*2; x += 2)
  326. {
  327. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+2]) >> 1;
  328. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+3]) >> 1;
  329. }
  330. break;
  331. case 3:
  332. for (int x = 0; x < widthOut*3; x += 3)
  333. {
  334. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+3]) >> 1;
  335. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+4]) >> 1;
  336. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+5]) >> 1;
  337. }
  338. break;
  339. case 4:
  340. for (int x = 0; x < widthOut*4; x += 4)
  341. {
  342. pixelDataOut[x] = ((unsigned)pixelDataIn[x*2] + pixelDataIn[x*2+4]) >> 1;
  343. pixelDataOut[x+1] = ((unsigned)pixelDataIn[x*2+1] + pixelDataIn[x*2+5]) >> 1;
  344. pixelDataOut[x+2] = ((unsigned)pixelDataIn[x*2+2] + pixelDataIn[x*2+6]) >> 1;
  345. pixelDataOut[x+3] = ((unsigned)pixelDataIn[x*2+3] + pixelDataIn[x*2+7]) >> 1;
  346. }
  347. break;
  348. }
  349. }
  350. // 2D case
  351. else
  352. {
  353. switch (components_)
  354. {
  355. case 1:
  356. for (int y = 0; y < heightOut; ++y)
  357. {
  358. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_];
  359. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_];
  360. unsigned char* out = &pixelDataOut[y*widthOut];
  361. for (int x = 0; x < widthOut; ++x)
  362. {
  363. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+1] + inLower[x*2] + inLower[x*2+1]) >> 2;
  364. }
  365. }
  366. break;
  367. case 2:
  368. for (int y = 0; y < heightOut; ++y)
  369. {
  370. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*2];
  371. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*2];
  372. unsigned char* out = &pixelDataOut[y*widthOut*2];
  373. for (int x = 0; x < widthOut*2; x += 2)
  374. {
  375. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+2] + inLower[x*2] + inLower[x*2+2]) >> 2;
  376. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+3] + inLower[x*2+1] + inLower[x*2+3]) >> 2;
  377. }
  378. }
  379. break;
  380. case 3:
  381. for (int y = 0; y < heightOut; ++y)
  382. {
  383. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*3];
  384. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*3];
  385. unsigned char* out = &pixelDataOut[y*widthOut*3];
  386. for (int x = 0; x < widthOut*3; x += 3)
  387. {
  388. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+3] + inLower[x*2] + inLower[x*2+3]) >> 2;
  389. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+4] + inLower[x*2+1] + inLower[x*2+4]) >> 2;
  390. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+5] + inLower[x*2+2] + inLower[x*2+5]) >> 2;
  391. }
  392. }
  393. break;
  394. case 4:
  395. for (int y = 0; y < heightOut; ++y)
  396. {
  397. const unsigned char* inUpper = &pixelDataIn[(y*2)*width_*4];
  398. const unsigned char* inLower = &pixelDataIn[(y*2+1)*width_*4];
  399. unsigned char* out = &pixelDataOut[y*widthOut*4];
  400. for (int x = 0; x < widthOut*4; x += 4)
  401. {
  402. out[x] = ((unsigned)inUpper[x*2] + inUpper[x*2+4] + inLower[x*2] + inLower[x*2+4]) >> 2;
  403. out[x+1] = ((unsigned)inUpper[x*2+1] + inUpper[x*2+5] + inLower[x*2+1] + inLower[x*2+5]) >> 2;
  404. out[x+2] = ((unsigned)inUpper[x*2+2] + inUpper[x*2+6] + inLower[x*2+2] + inLower[x*2+6]) >> 2;
  405. out[x+3] = ((unsigned)inUpper[x*2+3] + inUpper[x*2+7] + inLower[x*2+3] + inLower[x*2+7]) >> 2;
  406. }
  407. }
  408. break;
  409. }
  410. }
  411. return mipImage;
  412. }
  413. CompressedLevel Image::GetCompressedLevel(unsigned index) const
  414. {
  415. CompressedLevel level;
  416. if (compressedFormat_ == CF_NONE)
  417. {
  418. LOGERROR("Image is not compressed");
  419. return level;
  420. }
  421. if (index >= numCompressedLevels_)
  422. {
  423. LOGERROR("Compressed image mip level out of bounds");
  424. return level;
  425. }
  426. level.width_ = width_;
  427. level.height_ = height_;
  428. level.blockSize_ = compressedFormat_ == CF_DXT1 ? 8 : 16;
  429. unsigned i = 0;
  430. unsigned offset = 0;
  431. for (;;)
  432. {
  433. if (!level.width_)
  434. level.width_ = 1;
  435. if (!level.height_)
  436. level.height_ = 1;
  437. level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
  438. level.rows_ = ((level.height_ + 3) / 4);
  439. level.data_ = data_.GetPtr() + offset;
  440. level.dataSize_ = level.rows_ * level.rowSize_;
  441. if (offset + level.dataSize_ > GetMemoryUse())
  442. {
  443. LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
  444. " Datasize: " + String(GetMemoryUse()));
  445. level.data_ = 0;
  446. return level;
  447. }
  448. if (i == index)
  449. return level;
  450. offset += level.dataSize_;
  451. level.width_ /= 2;
  452. level.height_ /= 2;
  453. ++i;
  454. }
  455. }