gBitmap.cpp 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  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
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell 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
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "gfx/bitmap/gBitmap.h"
  24. #include "core/resourceManager.h"
  25. #include "core/stream/fileStream.h"
  26. #include "core/strings/stringFunctions.h"
  27. #include "core/color.h"
  28. #include "gfx/bitmap/bitmapUtils.h"
  29. #include "math/mRect.h"
  30. #include "console/console.h"
  31. #include "platform/profiler.h"
  32. #include "console/engineAPI.h"
  33. #include "gfx/bitmap/ddsFile.h"
  34. using namespace Torque;
  35. const U32 GBitmap::csFileVersion = 3;
  36. Vector<GBitmap::Registration> GBitmap::sRegistrations( __FILE__, __LINE__ );
  37. GBitmap::GBitmap()
  38. : mInternalFormat(GFXFormatR8G8B8),
  39. mBits(NULL),
  40. mByteSize(0),
  41. mWidth(0),
  42. mHeight(0),
  43. mBytesPerPixel(0),
  44. mNumMipLevels(0),
  45. mHasTransparency(false),
  46. mNumFaces(1)
  47. {
  48. std::fill_n(mMipLevelOffsets, c_maxMipLevels, 0xffffffff);
  49. std::fill_n(mFaceOffsets, 6, 0xffffffff);
  50. }
  51. GBitmap::GBitmap(const GBitmap& rCopy)
  52. {
  53. mInternalFormat = rCopy.mInternalFormat;
  54. mByteSize = rCopy.mByteSize;
  55. mBits = new U8[mByteSize];
  56. dMemcpy(mBits, rCopy.mBits, mByteSize);
  57. mWidth = rCopy.mWidth;
  58. mHeight = rCopy.mHeight;
  59. mBytesPerPixel = rCopy.mBytesPerPixel;
  60. mNumMipLevels = rCopy.mNumMipLevels;
  61. dMemcpy(mMipLevelOffsets, rCopy.mMipLevelOffsets, sizeof(mMipLevelOffsets));
  62. dMemcpy(mFaceOffsets, rCopy.mFaceOffsets, sizeof(mFaceOffsets));
  63. mHasTransparency = rCopy.mHasTransparency;
  64. mNumFaces = rCopy.mNumFaces;
  65. }
  66. GBitmap::GBitmap(const U32 in_width,
  67. const U32 in_height,
  68. const bool in_extrudeMipLevels,
  69. const GFXFormat in_format,
  70. const U32 in_numFaces)
  71. : mBits(NULL),
  72. mByteSize(0),
  73. mNumFaces(in_numFaces)
  74. {
  75. for (U32 i = 0; i < c_maxMipLevels; i++)
  76. mMipLevelOffsets[i] = 0xffffffff;
  77. for(U32 i = 0; i < 6; i++)
  78. mFaceOffsets[i] = 0xffffffff;
  79. allocateBitmap(in_width, in_height, in_extrudeMipLevels, in_format, in_numFaces);
  80. mHasTransparency = false;
  81. }
  82. GBitmap::GBitmap(const U32 in_width,
  83. const U32 in_height,
  84. const U8* data,
  85. const U32 in_numFaces)
  86. : mBits(NULL),
  87. mByteSize(0),
  88. mNumFaces(in_numFaces)
  89. {
  90. allocateBitmap(in_width, in_height, false, GFXFormatR8G8B8A8, in_numFaces);
  91. mHasTransparency = false;
  92. for (U32 x = 0; x < in_width; x++)
  93. {
  94. for (U32 y = 0; y < in_height; y++)
  95. {
  96. U32 offset = (x + y * in_width) * 4;
  97. ColorI color(data[offset],
  98. data[offset + 1],
  99. data[offset + 2],
  100. data[offset + 3]);
  101. if (color.alpha < 255)
  102. mHasTransparency = true;
  103. setColor(x, y, color);
  104. }
  105. }
  106. }
  107. //--------------------------------------------------------------------------
  108. GBitmap::~GBitmap()
  109. {
  110. deleteImage();
  111. }
  112. //--------------------------------------------------------------------------
  113. U32 GBitmap::getFormatBytesPerPixel(GFXFormat fmt)
  114. {
  115. switch (fmt)
  116. {
  117. // 8-bit formats
  118. case GFXFormatA8:
  119. case GFXFormatL8:
  120. case GFXFormatA4L4:
  121. return 1;
  122. // 16-bit formats
  123. case GFXFormatR5G6B5:
  124. case GFXFormatR5G5B5A1:
  125. case GFXFormatR5G5B5X1:
  126. case GFXFormatA8L8:
  127. case GFXFormatL16:
  128. case GFXFormatR16F:
  129. case GFXFormatD16:
  130. return 2;
  131. // 24-bit formats
  132. case GFXFormatR8G8B8:
  133. case GFXFormatR8G8B8_SRGB:
  134. return 3;
  135. // 32-bit formats
  136. case GFXFormatR8G8B8A8:
  137. case GFXFormatR8G8B8X8:
  138. case GFXFormatB8G8R8A8:
  139. case GFXFormatR8G8B8A8_SRGB:
  140. case GFXFormatR32F:
  141. case GFXFormatR10G10B10A2:
  142. case GFXFormatR11G11B10:
  143. case GFXFormatD24X8:
  144. case GFXFormatD24S8:
  145. case GFXFormatD24FS8:
  146. case GFXFormatR16G16:
  147. case GFXFormatR16G16F:
  148. case GFXFormatR8G8B8A8_LINEAR_FORCE:
  149. return 4;
  150. // 64-bit formats
  151. case GFXFormatR16G16B16A16:
  152. case GFXFormatR16G16B16A16F:
  153. case GFXFormatD32FS8X24:
  154. return 8;
  155. // 128-bit formats
  156. case GFXFormatR32G32B32A32F:
  157. return 16;
  158. default:
  159. AssertWarn(false, "getFormatBytesPerPixel() - Unknown or compressed format");
  160. return 4;
  161. }
  162. }
  163. //--------------------------------------------------------------------------
  164. void GBitmap::sRegisterFormat( const GBitmap::Registration &reg )
  165. {
  166. U32 insert = sRegistrations.size();
  167. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  168. {
  169. if ( sRegistrations[i].priority <= reg.priority )
  170. {
  171. insert = i;
  172. break;
  173. }
  174. }
  175. sRegistrations.insert( insert, reg );
  176. }
  177. const GBitmap::Registration *GBitmap::sFindRegInfo( const String &extension )
  178. {
  179. for ( U32 i = 0; i < GBitmap::sRegistrations.size(); i++ )
  180. {
  181. const GBitmap::Registration &reg = GBitmap::sRegistrations[i];
  182. const Vector<String> &extensions = reg.extensions;
  183. for ( U32 j = 0; j < extensions.size(); ++j )
  184. {
  185. if ( extensions[j].equal( extension, String::NoCase ) )
  186. return &reg;
  187. }
  188. }
  189. return NULL;
  190. }
  191. bool GBitmap::sFindFile( const Path &path, Path *outPath )
  192. {
  193. PROFILE_SCOPE( GBitmap_sFindFile );
  194. const String origExt( String::ToLower( path.getExtension() ) );
  195. Path tryPath( path );
  196. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  197. {
  198. const Registration &reg = sRegistrations[i];
  199. const Vector<String> &extensions = reg.extensions;
  200. for ( U32 j = 0; j < extensions.size(); ++j )
  201. {
  202. // We've already tried this one.
  203. if ( extensions[j] == origExt )
  204. continue;
  205. tryPath.setExtension( extensions[j] );
  206. if ( !Torque::FS::IsFile( tryPath ) )
  207. continue;
  208. if ( outPath )
  209. *outPath = tryPath;
  210. return true;
  211. }
  212. }
  213. return false;
  214. }
  215. bool GBitmap::sFindFiles( const Path &path, Vector<Path> *outFoundPaths )
  216. {
  217. PROFILE_SCOPE( GBitmap_sFindFiles );
  218. Path tryPath( path );
  219. for ( U32 i = 0; i < GBitmap::sRegistrations.size(); i++ )
  220. {
  221. const GBitmap::Registration &reg = GBitmap::sRegistrations[i];
  222. const Vector<String> &extensions = reg.extensions;
  223. for ( U32 j = 0; j < extensions.size(); ++j )
  224. {
  225. tryPath.setExtension( extensions[j] );
  226. if ( Torque::FS::IsFile( tryPath ) )
  227. {
  228. if ( outFoundPaths )
  229. outFoundPaths->push_back( tryPath );
  230. else
  231. return true;
  232. }
  233. }
  234. }
  235. return outFoundPaths ? outFoundPaths->size() > 0 : false;
  236. }
  237. String GBitmap::sGetExtensionList()
  238. {
  239. String list;
  240. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  241. {
  242. const Registration &reg = sRegistrations[i];
  243. for ( U32 j = 0; j < reg.extensions.size(); j++ )
  244. {
  245. list += reg.extensions[j];
  246. list += " ";
  247. }
  248. }
  249. return list;
  250. }
  251. //--------------------------------------------------------------------------
  252. void GBitmap::deleteImage()
  253. {
  254. delete [] mBits;
  255. mBits = NULL;
  256. mByteSize = 0;
  257. mWidth = 0;
  258. mHeight = 0;
  259. mNumMipLevels = 0;
  260. }
  261. //--------------------------------------------------------------------------
  262. void GBitmap::copyRect(const GBitmap *src, const RectI &srcRect, const Point2I &dstPt, const U32 srcMipLevel, const U32 dstMipLevel)
  263. {
  264. if(src->getFormat() != getFormat())
  265. return;
  266. if(srcRect.extent.x + srcRect.point.x > src->getWidth(srcMipLevel) || srcRect.extent.y + srcRect.point.y > src->getHeight(srcMipLevel))
  267. return;
  268. if(srcRect.extent.x + dstPt.x > getWidth(dstMipLevel) || srcRect.extent.y + dstPt.y > getHeight(dstMipLevel))
  269. return;
  270. for(U32 i = 0; i < srcRect.extent.y; i++)
  271. {
  272. dMemcpy(getAddress(dstPt.x, dstPt.y + i, dstMipLevel),
  273. src->getAddress(srcRect.point.x, srcRect.point.y + i, srcMipLevel),
  274. mBytesPerPixel * srcRect.extent.x);
  275. }
  276. }
  277. //--------------------------------------------------------------------------
  278. void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool in_extrudeMipLevels, const GFXFormat in_format, const U32 in_numFaces)
  279. {
  280. //-------------------------------------- Some debug checks...
  281. U32 svByteSize = mByteSize;
  282. U8 *svBits = mBits;
  283. AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
  284. if (in_extrudeMipLevels == true)
  285. {
  286. AssertFatal(isPow2(in_width) == true && isPow2(in_height) == true, "GBitmap::GBitmap: in order to extrude mip levels, bitmap w/h must be pow2");
  287. }
  288. mInternalFormat = in_format;
  289. mWidth = in_width;
  290. mHeight = in_height;
  291. mNumFaces = in_numFaces;
  292. mBytesPerPixel = getFormatBytesPerPixel(mInternalFormat);
  293. // Set up the mip levels, if necessary...
  294. mNumMipLevels = 1;
  295. mMipLevelOffsets[0] = 0;
  296. if (in_extrudeMipLevels == true)
  297. {
  298. U32 currWidth = in_width;
  299. U32 currHeight = in_height;
  300. while (currWidth != 1 || currHeight != 1)
  301. {
  302. mMipLevelOffsets[mNumMipLevels] = mMipLevelOffsets[mNumMipLevels - 1] +
  303. (currWidth * currHeight * mBytesPerPixel);
  304. currWidth >>= 1;
  305. currHeight >>= 1;
  306. if (currWidth == 0) currWidth = 1;
  307. if (currHeight == 0) currHeight = 1;
  308. mNumMipLevels++;
  309. }
  310. U32 expectedMips = mFloor(mLog2(mMax(in_width, in_height))) + 1;
  311. AssertFatal(mNumMipLevels == expectedMips, "GBitmap::allocateBitmap: mipmap count wrong");
  312. }
  313. AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
  314. U32 faceStride = 0;
  315. for (U32 mip = 0; mip < mNumMipLevels; mip++)
  316. faceStride += getWidth(mip) * getHeight(mip) * mBytesPerPixel;
  317. for (U32 face = 0; face < mNumFaces; face++)
  318. mFaceOffsets[face] = face * faceStride;
  319. U32 allocBytes = faceStride * mNumFaces;
  320. // Set up the memory...
  321. mByteSize = allocBytes;
  322. mBits = new U8[mByteSize];
  323. dMemset(mBits, 0xFF, mByteSize);
  324. if(svBits != NULL)
  325. {
  326. dMemcpy(mBits, svBits, getMin(mByteSize, svByteSize));
  327. delete[] svBits;
  328. }
  329. }
  330. //--------------------------------------------------------------------------
  331. void GBitmap::allocateBitmapWithMips(const U32 in_width, const U32 in_height, const U32 in_numMips, const GFXFormat in_format, const U32 in_numFaces)
  332. {
  333. //-------------------------------------- Some debug checks...
  334. U32 svByteSize = mByteSize;
  335. U8 *svBits = mBits;
  336. AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
  337. mInternalFormat = in_format;
  338. mWidth = in_width;
  339. mHeight = in_height;
  340. mNumFaces = in_numFaces;
  341. mBytesPerPixel = getFormatBytesPerPixel(mInternalFormat);
  342. // Set up the mip levels, if necessary...
  343. mNumMipLevels = 1;
  344. mMipLevelOffsets[0] = 0;
  345. if (in_numMips != 0)
  346. {
  347. U32 currWidth = in_width;
  348. U32 currHeight = in_height;
  349. do
  350. {
  351. mMipLevelOffsets[mNumMipLevels] = mMipLevelOffsets[mNumMipLevels - 1] +
  352. (currWidth * currHeight * mBytesPerPixel);
  353. currWidth >>= 1;
  354. currHeight >>= 1;
  355. if (currWidth == 0) currWidth = 1;
  356. if (currHeight == 0) currHeight = 1;
  357. mNumMipLevels++;
  358. } while ((currWidth != 1 || currHeight != 1) && (mNumMipLevels != in_numMips));
  359. }
  360. AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
  361. U32 faceStride = 0;
  362. for (U32 mip = 0; mip < mNumMipLevels; mip++)
  363. faceStride += getWidth(mip) * getHeight(mip) * mBytesPerPixel;
  364. for (U32 face = 0; face < mNumFaces; face++)
  365. mFaceOffsets[face] = face * faceStride;
  366. U32 allocBytes = faceStride * mNumFaces;
  367. // Set up the memory...
  368. mByteSize = allocBytes;
  369. mBits = new U8[mByteSize];
  370. dMemset(mBits, 0xFF, mByteSize);
  371. if (svBits != NULL)
  372. {
  373. dMemcpy(mBits, svBits, getMin(mByteSize, svByteSize));
  374. delete[] svBits;
  375. }
  376. }
  377. //--------------------------------------------------------------------------
  378. void GBitmap::extrudeMipLevels(bool clearBorders)
  379. {
  380. if(mNumMipLevels == 1)
  381. allocateBitmap(getWidth(), getHeight(), true, getFormat());
  382. if (getFormat() == GFXFormatR5G5B5A1)
  383. {
  384. for (U32 i = 1; i < mNumMipLevels; i++)
  385. bitmapExtrude5551(getBits(i - 1), getWritableBits(i), getHeight(i), getWidth(i));
  386. }
  387. else
  388. {
  389. for (U32 i = 1; i < mNumMipLevels; i++)
  390. {
  391. bitmapResizeToOutput(
  392. getBits(i - 1),
  393. getHeight(i - 1),
  394. getWidth(i - 1),
  395. getWritableBits(i),
  396. getHeight(i),
  397. getWidth(i),
  398. mBytesPerPixel,
  399. getFormat()
  400. );
  401. }
  402. }
  403. if (clearBorders)
  404. {
  405. for (U32 i = 1; i<mNumMipLevels; i++)
  406. {
  407. U32 width = getWidth(i);
  408. U32 height = getHeight(i);
  409. if (height<3 || width<3)
  410. // bmp is all borders at this mip level
  411. dMemset(getWritableBits(i),0,width*height*mBytesPerPixel);
  412. else
  413. {
  414. width *= mBytesPerPixel;
  415. U8 * bytes = getWritableBits(i);
  416. U8 * end = bytes + (height-1)*width - mBytesPerPixel; // end = last row, 2nd column
  417. // clear first row sans the last pixel
  418. dMemset(bytes,0,width-mBytesPerPixel);
  419. bytes -= mBytesPerPixel;
  420. while (bytes<end)
  421. {
  422. // clear last pixel of row N-1 and first pixel of row N
  423. bytes += width;
  424. dMemset(bytes,0,mBytesPerPixel*2);
  425. }
  426. // clear last row sans the first pixel
  427. dMemset(bytes+2*mBytesPerPixel,0,width-mBytesPerPixel);
  428. }
  429. }
  430. }
  431. }
  432. //--------------------------------------------------------------------------
  433. void GBitmap::chopTopMips(U32 mipsToChop)
  434. {
  435. U32 scalePower = getMin(mipsToChop, getNumMipLevels() - 1);
  436. U32 newMipCount = getNumMipLevels() - scalePower;
  437. U32 realWidth = getMax((U32)1, getWidth() >> scalePower);
  438. U32 realHeight = getMax((U32)1, getHeight() >> scalePower);
  439. U8 *destBits = mBits;
  440. U32 destOffsets[c_maxMipLevels];
  441. for (U32 i = scalePower; i<mNumMipLevels; i++)
  442. {
  443. // Copy to the new bitmap...
  444. dMemcpy(destBits,
  445. getWritableBits(i),
  446. getSurfaceSize(i));
  447. destOffsets[i - scalePower] = destBits - mBits;
  448. destBits += getSurfaceSize(i);
  449. }
  450. dMemcpy(mMipLevelOffsets, destOffsets, sizeof(destOffsets));
  451. mWidth = realWidth;
  452. mHeight = realHeight;
  453. mByteSize = destBits - mBits;
  454. mNumMipLevels = newMipCount;
  455. }
  456. //--------------------------------------------------------------------------
  457. void GBitmap::extrudeMipLevelsDetail()
  458. {
  459. AssertFatal(getFormat() == GFXFormatR8G8B8, "Error, only handles RGB for now...");
  460. U32 i,j;
  461. if(mNumMipLevels == 1)
  462. allocateBitmap(getWidth(), getHeight(), true, getFormat());
  463. for (i = 1; i < mNumMipLevels; i++) {
  464. bitmapExtrudeRGB(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1), mBytesPerPixel);
  465. }
  466. // Ok, now that we have the levels extruded, we need to move the lower miplevels
  467. // closer to 0.5.
  468. for (i = 1; i < mNumMipLevels - 1; i++) {
  469. U8* pMipBits = (U8*)getWritableBits(i);
  470. U32 numBytes = getWidth(i) * getHeight(i) * 3;
  471. U32 shift = i;
  472. U32 start = ((1 << i) - 1) * 0x80;
  473. for (j = 0; j < numBytes; j++) {
  474. U32 newVal = (start + pMipBits[j]) >> shift;
  475. AssertFatal(newVal <= 255, "Error, oob");
  476. pMipBits[j] = U8(newVal);
  477. }
  478. }
  479. AssertFatal(getWidth(mNumMipLevels - 1) == 1 && getHeight(mNumMipLevels - 1) == 1,
  480. "Error, last miplevel should be 1x1!");
  481. ((U8*)getWritableBits(mNumMipLevels - 1))[0] = 0x80;
  482. ((U8*)getWritableBits(mNumMipLevels - 1))[1] = 0x80;
  483. ((U8*)getWritableBits(mNumMipLevels - 1))[2] = 0x80;
  484. }
  485. //--------------------------------------------------------------------------
  486. bool GBitmap::setFormat(GFXFormat fmt)
  487. {
  488. if (getFormat() == fmt)
  489. return true;
  490. PROFILE_SCOPE(GBitmap_setFormat);
  491. // this is a nasty pointer math hack
  492. // is there a quick way to calc pixels of a fully mipped bitmap?
  493. U32 pixels = 0;
  494. for (U32 i=0; i < mNumMipLevels; i++)
  495. pixels += getHeight(i) * getWidth(i);
  496. if (getFormat() == GFXFormatR8G8B8 && fmt == GFXFormatR5G5B5A1)
  497. {
  498. #ifdef _XBOX
  499. bitmapConvertRGB_to_1555(mBits, pixels);
  500. #else
  501. bitmapConvertRGB_to_5551(mBits, pixels);
  502. #endif
  503. mInternalFormat = GFXFormatR5G5B5A1;
  504. mBytesPerPixel = 2;
  505. }
  506. else
  507. {
  508. bitmapConvertToOutput(&mBits, pixels, getFormat(), fmt);
  509. mInternalFormat = fmt;
  510. mBytesPerPixel = getFormatBytesPerPixel(fmt);
  511. }
  512. U32 offset = 0;
  513. for (U32 j=0; j < mNumMipLevels; j++)
  514. {
  515. mMipLevelOffsets[j] = offset;
  516. offset += getHeight(j) * getWidth(j) * mBytesPerPixel;
  517. }
  518. return true;
  519. }
  520. //------------------------------------------------------------------------------
  521. bool GBitmap::checkForTransparency()
  522. {
  523. mHasTransparency = false;
  524. if (!mBits || mByteSize == 0)
  525. return false;
  526. ColorI pixel(255, 255, 255, 255);
  527. // Only check formats that can *possibly* have alpha.
  528. switch (mInternalFormat)
  529. {
  530. case GFXFormatA8:
  531. case GFXFormatA4L4:
  532. case GFXFormatA8L8:
  533. case GFXFormatR5G5B5A1:
  534. case GFXFormatR8G8B8A8:
  535. case GFXFormatB8G8R8A8:
  536. case GFXFormatR8G8B8A8_SRGB:
  537. case GFXFormatR10G10B10A2:
  538. case GFXFormatR16G16B16A16:
  539. case GFXFormatR16G16B16A16F:
  540. case GFXFormatR32G32B32A32F:
  541. break; // alpha-capable
  542. default:
  543. return false; // skip formats with no alpha
  544. }
  545. for (U32 x = 0; x < mWidth; x++)
  546. {
  547. for (U32 y = 0; y < mHeight; y++)
  548. {
  549. if (getColor(x, y, pixel))
  550. {
  551. if (pixel.alpha < 255)
  552. {
  553. mHasTransparency = true;
  554. break;
  555. }
  556. }
  557. }
  558. }
  559. return mHasTransparency;
  560. }
  561. //------------------------------------------------------------------------------
  562. LinearColorF GBitmap::sampleTexel(F32 u, F32 v, bool retAlpha) const
  563. {
  564. LinearColorF col(0.5f, 0.5f, 0.5f);
  565. // normally sampling wraps all the way around at 1.0,
  566. // but locking doesn't support this, and we seem to calc
  567. // the uv based on a clamped 0 - 1...
  568. Point2F max((F32)(getWidth()-1), (F32)(getHeight()-1));
  569. Point2F posf;
  570. posf.x = mClampF(((u) * max.x), 0.0f, max.x);
  571. posf.y = mClampF(((v) * max.y), 0.0f, max.y);
  572. Point2I posi((S32)posf.x, (S32)posf.y);
  573. const U8 *buffer = getBits();
  574. U32 lexelindex = ((posi.y * getWidth()) + posi.x) * mBytesPerPixel;
  575. if(mBytesPerPixel == 2)
  576. {
  577. //U16 *buffer = (U16 *)lockrect->pBits;
  578. }
  579. else if(mBytesPerPixel > 2)
  580. {
  581. col.red = F32(buffer[lexelindex + 0]) / 255.0f;
  582. col.green = F32(buffer[lexelindex + 1]) / 255.0f;
  583. col.blue = F32(buffer[lexelindex + 2]) / 255.0f;
  584. if (retAlpha)
  585. {
  586. if (getHasTransparency())
  587. col.alpha = F32(buffer[lexelindex + 3]) / 255.0f;
  588. else
  589. col.alpha = 1.0f;
  590. }
  591. }
  592. return col;
  593. }
  594. //--------------------------------------------------------------------------
  595. bool GBitmap::getColor(const U32 x, const U32 y, ColorI& rColor, const U32 mipLevel, const U32 face) const
  596. {
  597. if (x >= mWidth || y >= mHeight)
  598. return false;
  599. U32 targMip = getNumMipLevels() < mipLevel ? getNumMipLevels()-1 : mipLevel;
  600. U32 targFace = getNumFaces() < face ? getNumFaces()-1 : face;
  601. const U8* p = getAddress(x, y, targMip, targFace);
  602. switch (mInternalFormat)
  603. {
  604. // --- 8-bit ---
  605. case GFXFormatA8:
  606. rColor.set(255, 255, 255, p[0]);
  607. break;
  608. case GFXFormatL8:
  609. rColor.set(p[0], p[0], p[0], 255);
  610. break;
  611. case GFXFormatA4L4:
  612. {
  613. U8 v = p[0];
  614. U8 lum = (v & 0x0F) * 17;
  615. U8 alp = ((v >> 4) & 0x0F) * 17;
  616. rColor.set(lum, lum, lum, alp);
  617. break;
  618. }
  619. // --- 16-bit ---
  620. case GFXFormatR5G6B5:
  621. {
  622. U16 c = ((U16*)p)[0];
  623. #ifdef TORQUE_BIG_ENDIAN
  624. c = convertLEndianToHost(c);
  625. #endif
  626. U8 r = (c >> 11) & 0x1F;
  627. U8 g = (c >> 5) & 0x3F;
  628. U8 b = c & 0x1F;
  629. rColor.set((r << 3) | (r >> 2),
  630. (g << 2) | (g >> 4),
  631. (b << 3) | (b >> 2),
  632. 255);
  633. break;
  634. }
  635. case GFXFormatR5G5B5A1:
  636. {
  637. U16 c = ((U16*)p)[0];
  638. #ifdef TORQUE_BIG_ENDIAN
  639. c = convertLEndianToHost(c);
  640. #endif
  641. U8 r = (c >> 11) & 0x1F;
  642. U8 g = (c >> 6) & 0x1F;
  643. U8 b = (c >> 1) & 0x1F;
  644. U8 a = (c & 0x01) ? 255 : 0;
  645. rColor.set((r << 3) | (r >> 2),
  646. (g << 3) | (g >> 2),
  647. (b << 3) | (b >> 2),
  648. a);
  649. break;
  650. }
  651. case GFXFormatA8L8:
  652. {
  653. U16 c = ((U16*)p)[0];
  654. #ifdef TORQUE_BIG_ENDIAN
  655. c = convertLEndianToHost(c);
  656. #endif
  657. U8 l = c & 0xFF;
  658. U8 a = (c >> 8) & 0xFF;
  659. rColor.set(l, l, l, a);
  660. break;
  661. }
  662. case GFXFormatL16:
  663. {
  664. U16 l = ((U16*)p)[0];
  665. #ifdef TORQUE_BIG_ENDIAN
  666. l = convertLEndianToHost(l);
  667. #endif
  668. rColor.set(convert16To8(l), convert16To8(l), convert16To8(l), 255);
  669. break;
  670. }
  671. case GFXFormatR16F:
  672. {
  673. const U16* v = (U16*)p;
  674. rColor.set(
  675. floatTo8(convertHalfToFloat(v[0])),
  676. 0,
  677. 0,
  678. 255
  679. );
  680. break;
  681. }
  682. // --- 24-bit ---
  683. case GFXFormatR8G8B8:
  684. case GFXFormatR8G8B8_SRGB:
  685. rColor.set(p[0], p[1], p[2], 255);
  686. break;
  687. // --- 32-bit ---
  688. case GFXFormatR32F:
  689. {
  690. const F32* v = (F32*)p;
  691. rColor.set(
  692. floatTo8(v[0]), // red
  693. 0, // green
  694. 0, // blue
  695. 255 // alpha
  696. );
  697. break;
  698. }
  699. case GFXFormatR16G16:
  700. {
  701. const U16* v = (U16*)p;
  702. #ifdef TORQUE_BIG_ENDIAN
  703. U16 r = convertLEndianToHost(v[0]);
  704. U16 g = convertLEndianToHost(v[1]);
  705. #else
  706. U16 r = v[0];
  707. U16 g = v[1];
  708. #endif
  709. rColor.set(
  710. convert16To8(r), // red
  711. convert16To8(g), // green
  712. 0, // blue
  713. 255 // alpha
  714. );
  715. break;
  716. }
  717. case GFXFormatR16G16F:
  718. {
  719. const U16* v = (U16*)p;
  720. rColor.set(
  721. floatTo8(convertHalfToFloat(v[0])),
  722. floatTo8(convertHalfToFloat(v[1])),
  723. 0,
  724. 255
  725. );
  726. break;
  727. }
  728. case GFXFormatR8G8B8A8:
  729. case GFXFormatR8G8B8A8_SRGB:
  730. case GFXFormatR8G8B8X8:
  731. rColor.set(p[0], p[1], p[2], (mInternalFormat == GFXFormatR8G8B8X8) ? 255 : p[3]);
  732. break;
  733. case GFXFormatB8G8R8A8:
  734. rColor.set(p[2], p[1], p[0], p[3]);
  735. break;
  736. // --- 64-bit ---
  737. case GFXFormatR16G16B16A16:
  738. {
  739. const U16* v = (U16*)p;
  740. #ifdef TORQUE_BIG_ENDIAN
  741. rColor.set(
  742. convert16To8(v[2]),
  743. convert16To8(v[1]),
  744. convert16To8(v[0]),
  745. convert16To8(v[3]));
  746. #else
  747. rColor.set(
  748. convert16To8(v[0]),
  749. convert16To8(v[1]),
  750. convert16To8(v[2]),
  751. convert16To8(v[3]));
  752. #endif
  753. break;
  754. }
  755. case GFXFormatR16G16B16A16F:
  756. {
  757. const U16* v = (const U16*)p;
  758. rColor.set(floatTo8(
  759. convertHalfToFloat(v[0])),
  760. floatTo8(convertHalfToFloat(v[1])),
  761. floatTo8(convertHalfToFloat(v[2])),
  762. floatTo8(convertHalfToFloat(v[3])));
  763. break;
  764. }
  765. // --- 128-bit ---
  766. case GFXFormatR32G32B32A32F:
  767. {
  768. const F32* v = (const F32*)p;
  769. rColor.set(
  770. floatTo8(v[0]),
  771. floatTo8(v[1]),
  772. floatTo8(v[2]),
  773. floatTo8(v[3]));
  774. break;
  775. }
  776. default:
  777. AssertFatal(false, "Bad internal format");
  778. return false;
  779. }
  780. return true;
  781. }
  782. //--------------------------------------------------------------------------
  783. bool GBitmap::setColor(const U32 x, const U32 y, const ColorI& rColor)
  784. {
  785. if (x >= mWidth || y >= mHeight)
  786. return false;
  787. U8* p = getAddress(x, y);
  788. switch (mInternalFormat)
  789. {
  790. // --- 8-bit ---
  791. case GFXFormatA8:
  792. *p = rColor.alpha;
  793. break;
  794. case GFXFormatL8:
  795. *p = rColor.red; // L = R channel
  796. break;
  797. case GFXFormatA4L4:
  798. {
  799. U8 lum = rColor.red / 17;
  800. U8 alp = rColor.alpha / 17;
  801. *p = (alp << 4) | (lum & 0x0F);
  802. break;
  803. }
  804. // --- 16-bit ---
  805. case GFXFormatR5G6B5:
  806. {
  807. U16 r = rColor.red * 31 / 255;
  808. U16 g = rColor.green * 63 / 255;
  809. U16 b = rColor.blue * 31 / 255;
  810. #ifdef TORQUE_BIG_ENDIAN
  811. * (U16*)p = (r << 11) | (g << 5) | b;
  812. #else
  813. * (U16*)p = (b) | (g << 5) | (r << 11);
  814. #endif
  815. break;
  816. }
  817. case GFXFormatR5G5B5A1:
  818. {
  819. U16 r = rColor.red * 31 / 255;
  820. U16 g = rColor.green * 31 / 255;
  821. U16 b = rColor.blue * 31 / 255;
  822. U16 a = (rColor.alpha > 0) ? 1 : 0;
  823. #ifdef TORQUE_BIG_ENDIAN
  824. * (U16*)p = (a << 15) | (b << 10) | (g << 5) | r;
  825. #else
  826. * (U16*)p = (r << 11) | (g << 6) | (b << 1) | a;
  827. #endif
  828. break;
  829. }
  830. case GFXFormatA8L8:
  831. {
  832. U16 l = rColor.red;
  833. U16 a = rColor.alpha;
  834. #ifdef TORQUE_BIG_ENDIAN
  835. * (U16*)p = (a << 8) | l;
  836. #else
  837. * (U16*)p = (l) | (a << 8);
  838. #endif
  839. break;
  840. }
  841. case GFXFormatL16:
  842. *(U16*)p = convert8To16(rColor.red);
  843. break;
  844. case GFXFormatR16F:
  845. {
  846. U16* v = (U16*)p;
  847. v[0] = convertFloatToHalf(rColor.red / 255.f);
  848. break;
  849. }
  850. // --- 24-bit ---
  851. case GFXFormatR8G8B8:
  852. case GFXFormatR8G8B8_SRGB:
  853. p[0] = rColor.red;
  854. p[1] = rColor.green;
  855. p[2] = rColor.blue;
  856. break;
  857. // --- 32-bit ---
  858. case GFXFormatR32F:
  859. {
  860. F32* v = (F32*)p;
  861. v[0] = rColor.red / 255.f;
  862. break;
  863. }
  864. case GFXFormatR16G16:
  865. {
  866. U16* v = (U16*)p;
  867. v[0] = convert8To16(rColor.red);
  868. v[1] = convert8To16(rColor.green);
  869. break;
  870. }
  871. case GFXFormatR16G16F:
  872. {
  873. U16* v = (U16*)p;
  874. v[0] = convertFloatToHalf(rColor.red / 255.f);
  875. v[1] = convertFloatToHalf(rColor.green / 255.f);
  876. break;
  877. }
  878. case GFXFormatR8G8B8A8:
  879. case GFXFormatR8G8B8A8_SRGB:
  880. case GFXFormatR8G8B8X8:
  881. p[0] = rColor.red;
  882. p[1] = rColor.green;
  883. p[2] = rColor.blue;
  884. p[3] = (mInternalFormat == GFXFormatR8G8B8X8) ? 255 : rColor.alpha;
  885. break;
  886. case GFXFormatB8G8R8A8:
  887. p[0] = rColor.blue;
  888. p[1] = rColor.green;
  889. p[2] = rColor.red;
  890. p[3] = rColor.alpha;
  891. break;
  892. // --- 64-bit ---
  893. case GFXFormatR16G16B16A16:
  894. {
  895. U16* v = (U16*)p;
  896. v[0] = convert8To16(rColor.red);
  897. v[1] = convert8To16(rColor.green);
  898. v[2] = convert8To16(rColor.blue);
  899. v[3] = convert8To16(rColor.alpha);
  900. break;
  901. }
  902. case GFXFormatR16G16B16A16F:
  903. {
  904. U16* v = (U16*)p;
  905. v[0] = convertFloatToHalf(rColor.red / 255.f);
  906. v[1] = convertFloatToHalf(rColor.green / 255.f);
  907. v[2] = convertFloatToHalf(rColor.blue / 255.f);
  908. v[3] = convertFloatToHalf(rColor.alpha / 255.f);
  909. break;
  910. }
  911. // --- 128-bit ---
  912. case GFXFormatR32G32B32A32F:
  913. {
  914. F32* v = (F32*)p;
  915. v[0] = rColor.red / 255.f;
  916. v[1] = rColor.green / 255.f;
  917. v[2] = rColor.blue / 255.f;
  918. v[3] = rColor.alpha / 255.f;
  919. break;
  920. }
  921. default:
  922. AssertFatal(false, "Bad internal format in setColor");
  923. return false;
  924. }
  925. return true;
  926. }
  927. //--------------------------------------------------------------------------
  928. U8 GBitmap::getChanelValueAt(U32 x, U32 y, U32 chan)
  929. {
  930. ColorI pixelColor = ColorI(255,255,255,255);
  931. getColor(x, y, pixelColor);
  932. if (mInternalFormat == GFXFormatL16 || mInternalFormat == GFXFormatL8)
  933. {
  934. chan = 0;
  935. }
  936. switch (chan) {
  937. case 0: return pixelColor.red;
  938. case 1: return pixelColor.green;
  939. case 2: return pixelColor.blue;
  940. default: return pixelColor.alpha;
  941. }
  942. }
  943. //-----------------------------------------------------------------------------
  944. bool GBitmap::combine( const GBitmap *bitmapA, const GBitmap *bitmapB, const TextureOp combineOp )
  945. {
  946. // Check bitmapA format
  947. switch( bitmapA->getFormat() )
  948. {
  949. case GFXFormatR8G8B8:
  950. case GFXFormatR8G8B8X8:
  951. case GFXFormatR8G8B8A8:
  952. break;
  953. default:
  954. Con::errorf( "GBitmap::combine - invalid format for bitmapA" );
  955. return false;
  956. }
  957. // Check bitmapB format
  958. switch( bitmapB->getFormat() )
  959. {
  960. case GFXFormatR8G8B8:
  961. case GFXFormatR8G8B8X8:
  962. case GFXFormatR8G8B8A8:
  963. break;
  964. default:
  965. Con::errorf( "GBitmap::combine - invalid format for bitmapB" );
  966. return false;
  967. }
  968. // Determine format of result texture
  969. // CodeReview: This is dependent on the order of the GFXFormat enum. [5/11/2007 Pat]
  970. GFXFormat resFmt = static_cast<GFXFormat>( getMax( bitmapA->getFormat(), bitmapB->getFormat() ) );
  971. U32 resWidth = getMax( bitmapA->getWidth(), bitmapB->getWidth() );
  972. U32 resHeight = getMax( bitmapA->getHeight(), bitmapB->getHeight() );
  973. // Adjust size OF bitmap based on the biggest one
  974. if( bitmapA->getWidth() != bitmapB->getWidth() ||
  975. bitmapA->getHeight() != bitmapB->getHeight() )
  976. {
  977. // Delete old bitmap
  978. deleteImage();
  979. // Allocate new one
  980. allocateBitmap( resWidth, resHeight, false, resFmt );
  981. }
  982. // Adjust format of result bitmap (if resFmt == getFormat() it will not perform the format convert)
  983. setFormat( resFmt );
  984. // Perform combine
  985. U8 *destBits = getWritableBits();
  986. const U8 *aBits = bitmapA->getBits();
  987. const U8 *bBits = bitmapB->getBits();
  988. for( S32 y = 0; y < getHeight(); y++ )
  989. {
  990. for( S32 x = 0; x < getWidth(); x++ )
  991. {
  992. for( S32 _byte = 0; _byte < mBytesPerPixel; _byte++ )
  993. {
  994. U8 pxA = 0;
  995. U8 pxB = 0;
  996. // Get contributions from A and B
  997. if( y < bitmapA->getHeight() &&
  998. x < bitmapA->getWidth() &&
  999. _byte < bitmapA->mBytesPerPixel )
  1000. pxA = *aBits++;
  1001. if( y < bitmapB->getHeight() &&
  1002. x < bitmapB->getWidth() &&
  1003. _byte < bitmapB->mBytesPerPixel )
  1004. pxB = *bBits++;
  1005. // Combine them (clamp values 0-U8_MAX)
  1006. switch( combineOp )
  1007. {
  1008. case Add:
  1009. *destBits++ = getMin( U8( pxA + pxB ), U8_MAX );
  1010. break;
  1011. case Subtract:
  1012. *destBits++ = getMax( U8( pxA - pxB ), U8( 0 ) );
  1013. break;
  1014. default:
  1015. AssertFatal(false, "GBitmap::combine - Invalid combineOp");
  1016. break;
  1017. }
  1018. }
  1019. }
  1020. }
  1021. return true;
  1022. }
  1023. void GBitmap::fill( const ColorI &rColor )
  1024. {
  1025. // Set the first pixel using the slow
  1026. // but proper method.
  1027. setColor( 0, 0, rColor );
  1028. mHasTransparency = rColor.alpha < 255;
  1029. // Now fill the first row of the bitmap by
  1030. // copying the first pixel across the row.
  1031. const U32 stride = getWidth() * mBytesPerPixel;
  1032. const U8 *src = getBits();
  1033. U8 *dest = getWritableBits() + mBytesPerPixel;
  1034. const U8 *end = src + stride;
  1035. for ( ; dest != end; dest += mBytesPerPixel )
  1036. dMemcpy( dest, src, mBytesPerPixel );
  1037. // Now copy the first row to all the others.
  1038. //
  1039. // TODO: This could adaptively size the copy
  1040. // amount to copy more rows from the source
  1041. // and reduce the total number of memcpy calls.
  1042. //
  1043. dest = getWritableBits() + stride;
  1044. end = src + ( stride * getHeight() );
  1045. for ( ; dest != end; dest += stride )
  1046. dMemcpy( dest, src, stride );
  1047. }
  1048. void GBitmap::fillWhite()
  1049. {
  1050. dMemset( getWritableBits(), 255, mByteSize );
  1051. mHasTransparency = false;
  1052. }
  1053. GBitmap* GBitmap::createPaddedBitmap() const
  1054. {
  1055. if (isPow2(getWidth()) && isPow2(getHeight()))
  1056. return NULL;
  1057. AssertFatal(getNumMipLevels() == 1,
  1058. "Cannot have non-pow2 bitmap with miplevels");
  1059. U32 width = getWidth();
  1060. U32 height = getHeight();
  1061. U32 newWidth = getNextPow2(getWidth());
  1062. U32 newHeight = getNextPow2(getHeight());
  1063. GBitmap* pReturn = new GBitmap(newWidth, newHeight, false, getFormat());
  1064. for (U32 i = 0; i < height; i++)
  1065. {
  1066. U8* pDest = (U8*)pReturn->getAddress(0, i);
  1067. const U8* pSrc = (const U8*)getAddress(0, i);
  1068. dMemcpy(pDest, pSrc, width * mBytesPerPixel);
  1069. pDest += width * mBytesPerPixel;
  1070. // set the src pixel to the last pixel in the row
  1071. const U8 *pSrcPixel = pDest - mBytesPerPixel;
  1072. for(U32 j = width; j < newWidth; j++)
  1073. for(U32 k = 0; k < mBytesPerPixel; k++)
  1074. *pDest++ = pSrcPixel[k];
  1075. }
  1076. for(U32 i = height; i < newHeight; i++)
  1077. {
  1078. U8* pDest = (U8*)pReturn->getAddress(0, i);
  1079. U8* pSrc = (U8*)pReturn->getAddress(0, height-1);
  1080. dMemcpy(pDest, pSrc, newWidth * mBytesPerPixel);
  1081. }
  1082. return pReturn;
  1083. }
  1084. GBitmap* GBitmap::createPow2Bitmap() const
  1085. {
  1086. if (isPow2(getWidth()) && isPow2(getHeight()))
  1087. return NULL;
  1088. AssertFatal(getNumMipLevels() == 1,
  1089. "Cannot have non-pow2 bitmap with miplevels");
  1090. U32 width = getWidth();
  1091. U32 height = getHeight();
  1092. U32 newWidth = getNextPow2(getWidth());
  1093. U32 newHeight = getNextPow2(getHeight());
  1094. GBitmap* pReturn = new GBitmap(newWidth, newHeight, false, getFormat());
  1095. U8* pDest = (U8*)pReturn->getAddress(0, 0);
  1096. const U8* pSrc = (const U8*)getAddress(0, 0);
  1097. F32 yCoeff = (F32) height / (F32) newHeight;
  1098. F32 xCoeff = (F32) width / (F32) newWidth;
  1099. F32 currY = 0.0f;
  1100. for (U32 y = 0; y < newHeight; y++)
  1101. {
  1102. F32 currX = 0.0f;
  1103. //U32 yDestOffset = (pReturn->mWidth * pReturn->mBytesPerPixel) * y;
  1104. //U32 xDestOffset = 0;
  1105. //U32 ySourceOffset = (U32)((mWidth * mBytesPerPixel) * currY);
  1106. //F32 xSourceOffset = 0.0f;
  1107. for (U32 x = 0; x < newWidth; x++)
  1108. {
  1109. pDest = (U8*) pReturn->getAddress(x, y);
  1110. pSrc = (U8*) getAddress((S32)currX, (S32)currY);
  1111. for (U32 p = 0; p < pReturn->mBytesPerPixel; p++)
  1112. {
  1113. pDest[p] = pSrc[p];
  1114. }
  1115. currX += xCoeff;
  1116. }
  1117. currY += yCoeff;
  1118. }
  1119. return pReturn;
  1120. }
  1121. void GBitmap::copyChannel( U32 index, GBitmap *outBitmap ) const
  1122. {
  1123. AssertFatal( index < mBytesPerPixel, "GBitmap::copyChannel() - Bad channel offset!" );
  1124. AssertFatal( outBitmap, "GBitmap::copyChannel() - Null output bitmap!" );
  1125. AssertFatal( outBitmap->getWidth() == getWidth(), "GBitmap::copyChannel() - Width mismatch!" );
  1126. AssertFatal( outBitmap->getHeight() == getHeight(), "GBitmap::copyChannel() - Height mismatch!" );
  1127. U8 *outBits = outBitmap->getWritableBits();
  1128. const U32 outBytesPerPixel = outBitmap->getBytesPerPixel();
  1129. const U8 *srcBits = getBits() + index;
  1130. const U8 *endBits = getBits() + mByteSize;
  1131. for ( ; srcBits < endBits; )
  1132. {
  1133. *outBits = *srcBits;
  1134. outBits += outBytesPerPixel;
  1135. srcBits += mBytesPerPixel;
  1136. }
  1137. }
  1138. //------------------------------------------------------------------------------
  1139. bool GBitmap::read(Stream& io_rStream)
  1140. {
  1141. PROFILE_SCOPE(GBitmap_Read);
  1142. // Handle versioning
  1143. U32 version;
  1144. io_rStream.read(&version);
  1145. AssertFatal(version == csFileVersion, "Bitmap::read: incorrect file version");
  1146. //-------------------------------------- Read the object
  1147. U32 fmt;
  1148. io_rStream.read(&fmt);
  1149. mInternalFormat = GFXFormat(fmt);
  1150. mBytesPerPixel = getFormatBytesPerPixel(mInternalFormat);
  1151. io_rStream.read(&mByteSize);
  1152. mBits = new U8[mByteSize];
  1153. io_rStream.read(mByteSize, mBits);
  1154. io_rStream.read(&mWidth);
  1155. io_rStream.read(&mHeight);
  1156. io_rStream.read(&mNumMipLevels);
  1157. for (U32 i = 0; i < c_maxMipLevels; i++)
  1158. io_rStream.read(&mMipLevelOffsets[i]);
  1159. checkForTransparency();
  1160. return (io_rStream.getStatus() == Stream::Ok);
  1161. }
  1162. bool GBitmap::write(Stream& io_rStream) const
  1163. {
  1164. PROFILE_SCOPE(GBitmap_Write);
  1165. // Handle versioning
  1166. io_rStream.write(csFileVersion);
  1167. //-------------------------------------- Write the object
  1168. io_rStream.write(U32(mInternalFormat));
  1169. io_rStream.write(mByteSize);
  1170. io_rStream.write(mByteSize, mBits);
  1171. io_rStream.write(mWidth);
  1172. io_rStream.write(mHeight);
  1173. io_rStream.write(mNumMipLevels);
  1174. for (U32 i = 0; i < c_maxMipLevels; i++)
  1175. io_rStream.write(mMipLevelOffsets[i]);
  1176. return (io_rStream.getStatus() == Stream::Ok);
  1177. }
  1178. //------------------------------------------------------------------------------
  1179. //-------------------------------------- Persistent I/O
  1180. //
  1181. bool GBitmap::readBitmap(const String& bmType, const Torque::Path& path)
  1182. {
  1183. PROFILE_SCOPE(ResourceGBitmap_readBitmap);
  1184. const GBitmap::Registration *regInfo = GBitmap::sFindRegInfo( bmType );
  1185. if ( regInfo == NULL )
  1186. {
  1187. Con::errorf( "[GBitmap::readBitmap] unable to find registration for extension [%s]", bmType.c_str() );
  1188. return false;
  1189. }
  1190. return regInfo->readFunc(path, this);
  1191. }
  1192. bool GBitmap::readBitmapStream(const String& bmType, Stream& ioStream, U32 len)
  1193. {
  1194. PROFILE_SCOPE(ResourceGBitmap_readBitmapStream);
  1195. const GBitmap::Registration* regInfo = GBitmap::sFindRegInfo(bmType);
  1196. if (regInfo == NULL)
  1197. {
  1198. Con::errorf("[GBitmap::readBitmap] unable to find registration for extension [%s]", bmType.c_str());
  1199. return false;
  1200. }
  1201. return regInfo->readStreamFunc(ioStream, this, len);
  1202. }
  1203. bool GBitmap::writeBitmap( const String &bmType, const Torque::Path& path, U32 compressionLevel )
  1204. {
  1205. FileStream stream;
  1206. if (!stream.open(path, Torque::FS::File::Write))
  1207. {
  1208. Con::errorf("GBitmap::writeBitmap failed to open path %s", path.getFullFileName().c_str());
  1209. stream.close();
  1210. return false;
  1211. }
  1212. // free file for stb
  1213. stream.close();
  1214. const GBitmap::Registration *regInfo = GBitmap::sFindRegInfo( bmType );
  1215. if ( regInfo == NULL )
  1216. {
  1217. Con::errorf( "[GBitmap::writeBitmap] unable to find registration for extension [%s]", bmType.c_str() );
  1218. return false;
  1219. }
  1220. return regInfo->writeFunc(path, this, (compressionLevel == U32_MAX) ? regInfo->defaultCompression : compressionLevel );
  1221. }
  1222. bool GBitmap::writeBitmapStream(const String& bmType, Stream& ioStream, U32 compressionLevel)
  1223. {
  1224. const GBitmap::Registration* regInfo = GBitmap::sFindRegInfo(bmType);
  1225. if (regInfo == NULL)
  1226. {
  1227. Con::errorf("[GBitmap::writeBitmap] unable to find registration for extension [%s]", bmType.c_str());
  1228. return false;
  1229. }
  1230. return regInfo->writeStreamFunc(bmType, ioStream, this, (compressionLevel == U32_MAX) ? regInfo->defaultCompression : compressionLevel);
  1231. }
  1232. template<> void *Resource<GBitmap>::create(const Torque::Path &path)
  1233. {
  1234. PROFILE_SCOPE( ResourceGBitmap_create );
  1235. #ifdef TORQUE_DEBUG_RES_MANAGER
  1236. Con::printf( "Resource<GBitmap>::create - [%s]", path.getFullPath().c_str() );
  1237. #endif
  1238. GBitmap* bmp = new GBitmap;
  1239. FileStream stream;
  1240. Torque::Path dbm = path;
  1241. dbm.setExtension("dbm");
  1242. if (Torque::FS::IsFile(dbm))
  1243. {
  1244. Torque::FS::FileNodeRef assetFile = Torque::FS::GetFileNode(path);
  1245. Torque::FS::FileNodeRef compiledFile = Torque::FS::GetFileNode(dbm);
  1246. if (assetFile != NULL && compiledFile != NULL)
  1247. {
  1248. if (compiledFile->getModifiedTime() >= assetFile->getModifiedTime())
  1249. {
  1250. #ifdef TORQUE_DEBUG_RES_MANAGER
  1251. Con::printf("Resource<GBitmap>::create - Loading cached image file: %s", dbm.getFullPath().c_str());
  1252. #endif
  1253. stream.open(dbm.getFullPath(), Torque::FS::File::Read);
  1254. bmp->read(stream);
  1255. return bmp;
  1256. }
  1257. }
  1258. }
  1259. stream.open( path.getFullPath(), Torque::FS::File::Read );
  1260. if ( stream.getStatus() != Stream::Ok )
  1261. {
  1262. Con::errorf( "Resource<GBitmap>::create - failed to open '%s'", path.getFullPath().c_str() );
  1263. return NULL;
  1264. }
  1265. const String extension = path.getExtension();
  1266. if( !bmp->readBitmap( extension, path ) )
  1267. {
  1268. // we can only get here if the stream was successful, so attempt to read the stream.
  1269. Con::warnf("Was unable to load as file, going to try the stream instead.");
  1270. if (!bmp->readBitmapStream(extension, stream, stream.getStreamSize()))
  1271. {
  1272. Con::errorf("Resource<GBitmap>::create - error reading '%s'", path.getFullPath().c_str());
  1273. delete bmp;
  1274. bmp = NULL;
  1275. }
  1276. }
  1277. return bmp;
  1278. }
  1279. template<> ResourceBase::Signature Resource<GBitmap>::signature()
  1280. {
  1281. return MakeFourCC('b','i','t','m');
  1282. }
  1283. Resource<GBitmap> GBitmap::load(const Torque::Path &path)
  1284. {
  1285. Resource<GBitmap> ret = _load( path );
  1286. if ( ret != NULL )
  1287. return ret;
  1288. // Do a recursive search.
  1289. return _search( path );
  1290. }
  1291. Resource<GBitmap> GBitmap::_load(const Torque::Path &path)
  1292. {
  1293. PROFILE_SCOPE( GBitmap_load );
  1294. if ( Torque::FS::IsFile( path ) )
  1295. return ResourceManager::get().load( path );
  1296. Path foundPath;
  1297. if ( GBitmap::sFindFile( path, &foundPath ) )
  1298. {
  1299. Resource<GBitmap> ret = ResourceManager::get().load( foundPath );
  1300. if ( ret != NULL )
  1301. return ret;
  1302. }
  1303. return Resource< GBitmap >( NULL );
  1304. }
  1305. Resource<GBitmap> GBitmap::_search(const Torque::Path &path)
  1306. {
  1307. PROFILE_SCOPE( GBitmap_search );
  1308. // If unable to load texture in current directory
  1309. // look in the parent directory. But never look in the root.
  1310. Path newPath( path );
  1311. while ( true )
  1312. {
  1313. String filePath = newPath.getPath();
  1314. String::SizeType slash = filePath.find( '/', filePath.length(), String::Right );
  1315. if ( slash == String::NPos )
  1316. break;
  1317. slash = filePath.find( '/', filePath.length(), String::Right );
  1318. if ( slash == String::NPos )
  1319. break;
  1320. String truncPath = filePath.substr( 0, slash );
  1321. newPath.setPath( truncPath );
  1322. Resource<GBitmap> ret = _load( newPath );
  1323. if ( ret != NULL )
  1324. return ret;
  1325. }
  1326. return Resource< GBitmap >( NULL );
  1327. }
  1328. U32 GBitmap::getSurfaceSize(const U32 mipLevel) const
  1329. {
  1330. // Bump by the mip level.
  1331. U32 height = getMax(U32(1), mHeight >> mipLevel);
  1332. U32 width = getMax(U32(1), mWidth >> mipLevel);
  1333. if (mInternalFormat >= GFXFormatBC1 && mInternalFormat <= GFXFormatBC3)
  1334. {
  1335. // From the directX docs:
  1336. // max(1, width / 4) x max(1, height / 4) x 8(DXT1) or 16(DXT2-5)
  1337. U32 sizeMultiple = 0;
  1338. switch (mInternalFormat)
  1339. {
  1340. case GFXFormatBC1:
  1341. sizeMultiple = 8;
  1342. break;
  1343. case GFXFormatBC2:
  1344. case GFXFormatBC3:
  1345. sizeMultiple = 16;
  1346. break;
  1347. default:
  1348. AssertISV(false, "DDSFile::getSurfaceSize - invalid compressed texture format, we only support DXT1-5 right now.");
  1349. break;
  1350. }
  1351. return getMax(U32(1), width / 4) * getMax(U32(1), height / 4) * sizeMultiple;
  1352. }
  1353. else
  1354. {
  1355. return height * width* mBytesPerPixel;
  1356. }
  1357. }
  1358. DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),,
  1359. "Returns image info in the following format: width TAB height TAB bytesPerPixel TAB format. "
  1360. "It will return an empty string if the file is not found.\n"
  1361. "@ingroup Rendering\n" )
  1362. {
  1363. Resource<GBitmap> image = GBitmap::load( filename );
  1364. if ( !image )
  1365. return String::EmptyString;
  1366. return String::ToString( "%d\t%d\t%d\t%d", image->getWidth(),
  1367. image->getHeight(),
  1368. image->getBytesPerPixel(),
  1369. image->getFormat());
  1370. }
  1371. DefineEngineFunction(saveScaledImage, bool, (const char* bitmapSource, const char* bitmapDest, S32 resolutionSize), ("", "", 256),
  1372. "Loads an image from the source path, and scales it down to the target resolution before"
  1373. "Saving it out to the destination path.\n")
  1374. {
  1375. bool isDDS = false;
  1376. bool isHDR = false;
  1377. if (bitmapSource == 0 || bitmapSource[0] == '\0' || bitmapDest == 0 || bitmapDest[0] == '\0')
  1378. {
  1379. return false;
  1380. }
  1381. if (!Platform::isFile(bitmapSource))
  1382. {
  1383. return false;
  1384. }
  1385. //First, gotta check the extension, as we have some extra work to do if it's
  1386. //a DDS file
  1387. const char* ret = dStrrchr(bitmapSource, '.');
  1388. if (ret)
  1389. {
  1390. if (String::ToLower(ret) == String(".dds"))
  1391. isDDS = true;
  1392. if (String::ToLower(ret) == String(".hdr"))
  1393. isHDR = true;
  1394. }
  1395. else
  1396. {
  1397. return false; //no extension? bail out
  1398. }
  1399. GBitmap* image = NULL;
  1400. if (isDDS)
  1401. {
  1402. Resource<DDSFile> dds = DDSFile::load(bitmapSource, 0);
  1403. if (dds != NULL)
  1404. {
  1405. image = new GBitmap();
  1406. if (!dds->decompressToGBitmap(image))
  1407. {
  1408. delete image;
  1409. image = NULL;
  1410. }
  1411. }
  1412. }
  1413. else
  1414. {
  1415. Resource<GBitmap> resImage = GBitmap::load(bitmapSource);
  1416. image = new GBitmap(*resImage);
  1417. }
  1418. if (!image)
  1419. return false;
  1420. Torque::Path sourcePath = Torque::Path(bitmapSource);
  1421. if (isPow2(image->getWidth()) && isPow2(image->getHeight()))
  1422. image->extrudeMipLevels();
  1423. image->setFormat(GFXFormatR8G8B8A8);
  1424. U32 mipCount = image->getNumMipLevels();
  1425. U32 targetMips = mFloor(mLog2((F32)(resolutionSize ? resolutionSize : 256))) + 1;
  1426. if (mipCount > targetMips)
  1427. {
  1428. image->chopTopMips(mipCount - targetMips);
  1429. }
  1430. //TODO: support different format targets, for now we just force
  1431. //to png for simplicity
  1432. Torque::Path destinationPath = Torque::Path(bitmapDest);
  1433. destinationPath.setExtension("png");
  1434. if(!image->writeBitmap("png", destinationPath.getFullPath()))
  1435. {
  1436. Con::errorf("saveScaledImage() - Error writing %s !", bitmapDest);
  1437. delete image;
  1438. return false;
  1439. }
  1440. delete image;
  1441. return true;
  1442. }