gBitmap.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449
  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. {
  47. std::fill_n(mMipLevelOffsets, c_maxMipLevels, 0xffffffff);
  48. }
  49. GBitmap::GBitmap(const GBitmap& rCopy)
  50. {
  51. mInternalFormat = rCopy.mInternalFormat;
  52. mByteSize = rCopy.mByteSize;
  53. mBits = new U8[mByteSize];
  54. dMemcpy(mBits, rCopy.mBits, mByteSize);
  55. mWidth = rCopy.mWidth;
  56. mHeight = rCopy.mHeight;
  57. mBytesPerPixel = rCopy.mBytesPerPixel;
  58. mNumMipLevels = rCopy.mNumMipLevels;
  59. dMemcpy(mMipLevelOffsets, rCopy.mMipLevelOffsets, sizeof(mMipLevelOffsets));
  60. mHasTransparency = rCopy.mHasTransparency;
  61. }
  62. GBitmap::GBitmap(const U32 in_width,
  63. const U32 in_height,
  64. const bool in_extrudeMipLevels,
  65. const GFXFormat in_format)
  66. : mBits(NULL),
  67. mByteSize(0)
  68. {
  69. for (U32 i = 0; i < c_maxMipLevels; i++)
  70. mMipLevelOffsets[i] = 0xffffffff;
  71. allocateBitmap(in_width, in_height, in_extrudeMipLevels, in_format);
  72. mHasTransparency = false;
  73. }
  74. GBitmap::GBitmap(const U32 in_width,
  75. const U32 in_height,
  76. const U8* data )
  77. : mBits(NULL),
  78. mByteSize(0)
  79. {
  80. allocateBitmap(in_width, in_height, false, GFXFormatR8G8B8A8);
  81. mHasTransparency = false;
  82. for (U32 x = 0; x < in_width; x++)
  83. {
  84. for (U32 y = 0; y < in_height; y++)
  85. {
  86. U32 offset = (x + y * in_width) * 4;
  87. ColorI color(data[offset],
  88. data[offset + 1],
  89. data[offset + 2],
  90. data[offset + 3]);
  91. if (color.alpha < 255)
  92. mHasTransparency = true;
  93. setColor(x, y, color);
  94. }
  95. }
  96. }
  97. //--------------------------------------------------------------------------
  98. GBitmap::~GBitmap()
  99. {
  100. deleteImage();
  101. }
  102. //--------------------------------------------------------------------------
  103. void GBitmap::sRegisterFormat( const GBitmap::Registration &reg )
  104. {
  105. U32 insert = sRegistrations.size();
  106. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  107. {
  108. if ( sRegistrations[i].priority <= reg.priority )
  109. {
  110. insert = i;
  111. break;
  112. }
  113. }
  114. sRegistrations.insert( insert, reg );
  115. }
  116. const GBitmap::Registration *GBitmap::sFindRegInfo( const String &extension )
  117. {
  118. for ( U32 i = 0; i < GBitmap::sRegistrations.size(); i++ )
  119. {
  120. const GBitmap::Registration &reg = GBitmap::sRegistrations[i];
  121. const Vector<String> &extensions = reg.extensions;
  122. for ( U32 j = 0; j < extensions.size(); ++j )
  123. {
  124. if ( extensions[j].equal( extension, String::NoCase ) )
  125. return &reg;
  126. }
  127. }
  128. return NULL;
  129. }
  130. bool GBitmap::sFindFile( const Path &path, Path *outPath )
  131. {
  132. PROFILE_SCOPE( GBitmap_sFindFile );
  133. const String origExt( String::ToLower( path.getExtension() ) );
  134. Path tryPath( path );
  135. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  136. {
  137. const Registration &reg = sRegistrations[i];
  138. const Vector<String> &extensions = reg.extensions;
  139. for ( U32 j = 0; j < extensions.size(); ++j )
  140. {
  141. // We've already tried this one.
  142. if ( extensions[j] == origExt )
  143. continue;
  144. tryPath.setExtension( extensions[j] );
  145. if ( !Torque::FS::IsFile( tryPath ) )
  146. continue;
  147. if ( outPath )
  148. *outPath = tryPath;
  149. return true;
  150. }
  151. }
  152. return false;
  153. }
  154. bool GBitmap::sFindFiles( const Path &path, Vector<Path> *outFoundPaths )
  155. {
  156. PROFILE_SCOPE( GBitmap_sFindFiles );
  157. Path tryPath( path );
  158. for ( U32 i = 0; i < GBitmap::sRegistrations.size(); i++ )
  159. {
  160. const GBitmap::Registration &reg = GBitmap::sRegistrations[i];
  161. const Vector<String> &extensions = reg.extensions;
  162. for ( U32 j = 0; j < extensions.size(); ++j )
  163. {
  164. tryPath.setExtension( extensions[j] );
  165. if ( Torque::FS::IsFile( tryPath ) )
  166. {
  167. if ( outFoundPaths )
  168. outFoundPaths->push_back( tryPath );
  169. else
  170. return true;
  171. }
  172. }
  173. }
  174. return outFoundPaths ? outFoundPaths->size() > 0 : false;
  175. }
  176. String GBitmap::sGetExtensionList()
  177. {
  178. String list;
  179. for ( U32 i = 0; i < sRegistrations.size(); i++ )
  180. {
  181. const Registration &reg = sRegistrations[i];
  182. for ( U32 j = 0; j < reg.extensions.size(); j++ )
  183. {
  184. list += reg.extensions[j];
  185. list += " ";
  186. }
  187. }
  188. return list;
  189. }
  190. //--------------------------------------------------------------------------
  191. void GBitmap::deleteImage()
  192. {
  193. delete [] mBits;
  194. mBits = NULL;
  195. mByteSize = 0;
  196. mWidth = 0;
  197. mHeight = 0;
  198. mNumMipLevels = 0;
  199. }
  200. //--------------------------------------------------------------------------
  201. void GBitmap::copyRect(const GBitmap *src, const RectI &srcRect, const Point2I &dstPt, const U32 srcMipLevel, const U32 dstMipLevel)
  202. {
  203. if(src->getFormat() != getFormat())
  204. return;
  205. if(srcRect.extent.x + srcRect.point.x > src->getWidth(srcMipLevel) || srcRect.extent.y + srcRect.point.y > src->getHeight(srcMipLevel))
  206. return;
  207. if(srcRect.extent.x + dstPt.x > getWidth(dstMipLevel) || srcRect.extent.y + dstPt.y > getHeight(dstMipLevel))
  208. return;
  209. for(U32 i = 0; i < srcRect.extent.y; i++)
  210. {
  211. dMemcpy(getAddress(dstPt.x, dstPt.y + i, dstMipLevel),
  212. src->getAddress(srcRect.point.x, srcRect.point.y + i, srcMipLevel),
  213. mBytesPerPixel * srcRect.extent.x);
  214. }
  215. }
  216. //--------------------------------------------------------------------------
  217. void GBitmap::allocateBitmap(const U32 in_width, const U32 in_height, const bool in_extrudeMipLevels, const GFXFormat in_format )
  218. {
  219. //-------------------------------------- Some debug checks...
  220. U32 svByteSize = mByteSize;
  221. U8 *svBits = mBits;
  222. AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
  223. if (in_extrudeMipLevels == true)
  224. {
  225. AssertFatal(isPow2(in_width) == true && isPow2(in_height) == true, "GBitmap::GBitmap: in order to extrude mip levels, bitmap w/h must be pow2");
  226. }
  227. mInternalFormat = in_format;
  228. mWidth = in_width;
  229. mHeight = in_height;
  230. mBytesPerPixel = 1;
  231. switch (mInternalFormat)
  232. {
  233. case GFXFormatA8:
  234. case GFXFormatL8: mBytesPerPixel = 1;
  235. break;
  236. case GFXFormatR8G8B8: mBytesPerPixel = 3;
  237. break;
  238. case GFXFormatR8G8B8A8_LINEAR_FORCE:
  239. case GFXFormatR8G8B8X8:
  240. case GFXFormatR8G8B8A8: mBytesPerPixel = 4;
  241. break;
  242. case GFXFormatL16:
  243. case GFXFormatR5G6B5:
  244. case GFXFormatR5G5B5A1: mBytesPerPixel = 2;
  245. break;
  246. case GFXFormatR16G16B16A16F:
  247. case GFXFormatR16G16B16A16: mBytesPerPixel = 8;
  248. break;
  249. default:
  250. AssertFatal(false, "GBitmap::GBitmap: misunderstood format specifier");
  251. break;
  252. }
  253. // Set up the mip levels, if necessary...
  254. mNumMipLevels = 1;
  255. U32 allocPixels = in_width * in_height * mBytesPerPixel;
  256. mMipLevelOffsets[0] = 0;
  257. if (in_extrudeMipLevels == true)
  258. {
  259. U32 currWidth = in_width;
  260. U32 currHeight = in_height;
  261. while (currWidth != 1 || currHeight != 1)
  262. {
  263. mMipLevelOffsets[mNumMipLevels] = mMipLevelOffsets[mNumMipLevels - 1] +
  264. (currWidth * currHeight * mBytesPerPixel);
  265. currWidth >>= 1;
  266. currHeight >>= 1;
  267. if (currWidth == 0) currWidth = 1;
  268. if (currHeight == 0) currHeight = 1;
  269. mNumMipLevels++;
  270. allocPixels += currWidth * currHeight * mBytesPerPixel;
  271. }
  272. U32 expectedMips = mFloor(mLog2(mMax(in_width, in_height))) + 1;
  273. AssertFatal(mNumMipLevels == expectedMips, "GBitmap::allocateBitmap: mipmap count wrong");
  274. }
  275. AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
  276. // Set up the memory...
  277. mByteSize = allocPixels;
  278. mBits = new U8[mByteSize];
  279. dMemset(mBits, 0xFF, mByteSize);
  280. if(svBits != NULL)
  281. {
  282. dMemcpy(mBits, svBits, getMin(mByteSize, svByteSize));
  283. delete[] svBits;
  284. }
  285. }
  286. //--------------------------------------------------------------------------
  287. void GBitmap::allocateBitmapWithMips(const U32 in_width, const U32 in_height, const U32 in_numMips, const GFXFormat in_format)
  288. {
  289. //-------------------------------------- Some debug checks...
  290. U32 svByteSize = mByteSize;
  291. U8 *svBits = mBits;
  292. AssertFatal(in_width != 0 && in_height != 0, "GBitmap::allocateBitmap: width or height is 0");
  293. mInternalFormat = in_format;
  294. mWidth = in_width;
  295. mHeight = in_height;
  296. mBytesPerPixel = 1;
  297. switch (mInternalFormat)
  298. {
  299. case GFXFormatA8:
  300. case GFXFormatL8: mBytesPerPixel = 1;
  301. break;
  302. case GFXFormatR8G8B8: mBytesPerPixel = 3;
  303. break;
  304. case GFXFormatR8G8B8X8:
  305. case GFXFormatR8G8B8A8: mBytesPerPixel = 4;
  306. break;
  307. case GFXFormatL16:
  308. case GFXFormatR5G6B5:
  309. case GFXFormatR5G5B5A1: mBytesPerPixel = 2;
  310. break;
  311. case GFXFormatR16G16B16A16F:
  312. case GFXFormatR16G16B16A16: mBytesPerPixel = 8;
  313. break;
  314. default:
  315. AssertFatal(false, "GBitmap::GBitmap: misunderstood format specifier");
  316. break;
  317. }
  318. // Set up the mip levels, if necessary...
  319. mNumMipLevels = 1;
  320. U32 allocPixels = in_width * in_height * mBytesPerPixel;
  321. mMipLevelOffsets[0] = 0;
  322. if (in_numMips != 0)
  323. {
  324. U32 currWidth = in_width;
  325. U32 currHeight = in_height;
  326. do
  327. {
  328. mMipLevelOffsets[mNumMipLevels] = mMipLevelOffsets[mNumMipLevels - 1] +
  329. (currWidth * currHeight * mBytesPerPixel);
  330. currWidth >>= 1;
  331. currHeight >>= 1;
  332. if (currWidth == 0) currWidth = 1;
  333. if (currHeight == 0) currHeight = 1;
  334. mNumMipLevels++;
  335. allocPixels += currWidth * currHeight * mBytesPerPixel;
  336. } while (currWidth != 1 || currHeight != 1 && mNumMipLevels != in_numMips);
  337. }
  338. AssertFatal(mNumMipLevels <= c_maxMipLevels, "GBitmap::allocateBitmap: too many miplevels");
  339. // Set up the memory...
  340. mByteSize = allocPixels;
  341. mBits = new U8[mByteSize];
  342. dMemset(mBits, 0xFF, mByteSize);
  343. if (svBits != NULL)
  344. {
  345. dMemcpy(mBits, svBits, getMin(mByteSize, svByteSize));
  346. delete[] svBits;
  347. }
  348. }
  349. //--------------------------------------------------------------------------
  350. void GBitmap::extrudeMipLevels(bool clearBorders)
  351. {
  352. if(mNumMipLevels == 1)
  353. allocateBitmap(getWidth(), getHeight(), true, getFormat());
  354. switch (getFormat())
  355. {
  356. case GFXFormatR5G5B5A1:
  357. {
  358. for(U32 i = 1; i < mNumMipLevels; i++)
  359. bitmapExtrude5551(getBits(i - 1), getWritableBits(i), getHeight(i), getWidth(i));
  360. break;
  361. }
  362. case GFXFormatR8G8B8:
  363. {
  364. for(U32 i = 1; i < mNumMipLevels; i++)
  365. bitmapExtrudeRGB(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
  366. break;
  367. }
  368. case GFXFormatR8G8B8A8:
  369. case GFXFormatR8G8B8X8:
  370. {
  371. for(U32 i = 1; i < mNumMipLevels; i++)
  372. bitmapExtrudeRGBA(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
  373. break;
  374. }
  375. case GFXFormatR16G16B16A16F:
  376. {
  377. for (U32 i = 1; i < mNumMipLevels; i++)
  378. bitmapExtrudeFPRGBA(getBits(i - 1), getWritableBits(i), getHeight(i - 1), getWidth(i - 1));
  379. break;
  380. }
  381. default:
  382. break;
  383. }
  384. if (clearBorders)
  385. {
  386. for (U32 i = 1; i<mNumMipLevels; i++)
  387. {
  388. U32 width = getWidth(i);
  389. U32 height = getHeight(i);
  390. if (height<3 || width<3)
  391. // bmp is all borders at this mip level
  392. dMemset(getWritableBits(i),0,width*height*mBytesPerPixel);
  393. else
  394. {
  395. width *= mBytesPerPixel;
  396. U8 * bytes = getWritableBits(i);
  397. U8 * end = bytes + (height-1)*width - mBytesPerPixel; // end = last row, 2nd column
  398. // clear first row sans the last pixel
  399. dMemset(bytes,0,width-mBytesPerPixel);
  400. bytes -= mBytesPerPixel;
  401. while (bytes<end)
  402. {
  403. // clear last pixel of row N-1 and first pixel of row N
  404. bytes += width;
  405. dMemset(bytes,0,mBytesPerPixel*2);
  406. }
  407. // clear last row sans the first pixel
  408. dMemset(bytes+2*mBytesPerPixel,0,width-mBytesPerPixel);
  409. }
  410. }
  411. }
  412. }
  413. //--------------------------------------------------------------------------
  414. void GBitmap::chopTopMips(U32 mipsToChop)
  415. {
  416. U32 scalePower = getMin(mipsToChop, getNumMipLevels() - 1);
  417. U32 newMipCount = getNumMipLevels() - scalePower;
  418. U32 realWidth = getMax((U32)1, getWidth() >> scalePower);
  419. U32 realHeight = getMax((U32)1, getHeight() >> scalePower);
  420. U8 *destBits = mBits;
  421. U32 destOffsets[c_maxMipLevels];
  422. for (U32 i = scalePower; i<mNumMipLevels; i++)
  423. {
  424. // Copy to the new bitmap...
  425. dMemcpy(destBits,
  426. getWritableBits(i),
  427. getSurfaceSize(i));
  428. destOffsets[i - scalePower] = destBits - mBits;
  429. destBits += getSurfaceSize(i);
  430. }
  431. dMemcpy(mMipLevelOffsets, destOffsets, sizeof(destOffsets));
  432. mWidth = realWidth;
  433. mHeight = realHeight;
  434. mByteSize = destBits - mBits;
  435. mNumMipLevels = newMipCount;
  436. }
  437. //--------------------------------------------------------------------------
  438. void GBitmap::extrudeMipLevelsDetail()
  439. {
  440. AssertFatal(getFormat() == GFXFormatR8G8B8, "Error, only handles RGB for now...");
  441. U32 i,j;
  442. if(mNumMipLevels == 1)
  443. allocateBitmap(getWidth(), getHeight(), true, getFormat());
  444. for (i = 1; i < mNumMipLevels; i++) {
  445. bitmapExtrudeRGB(getBits(i - 1), getWritableBits(i), getHeight(i-1), getWidth(i-1));
  446. }
  447. // Ok, now that we have the levels extruded, we need to move the lower miplevels
  448. // closer to 0.5.
  449. for (i = 1; i < mNumMipLevels - 1; i++) {
  450. U8* pMipBits = (U8*)getWritableBits(i);
  451. U32 numBytes = getWidth(i) * getHeight(i) * 3;
  452. U32 shift = i;
  453. U32 start = ((1 << i) - 1) * 0x80;
  454. for (j = 0; j < numBytes; j++) {
  455. U32 newVal = (start + pMipBits[j]) >> shift;
  456. AssertFatal(newVal <= 255, "Error, oob");
  457. pMipBits[j] = U8(newVal);
  458. }
  459. }
  460. AssertFatal(getWidth(mNumMipLevels - 1) == 1 && getHeight(mNumMipLevels - 1) == 1,
  461. "Error, last miplevel should be 1x1!");
  462. ((U8*)getWritableBits(mNumMipLevels - 1))[0] = 0x80;
  463. ((U8*)getWritableBits(mNumMipLevels - 1))[1] = 0x80;
  464. ((U8*)getWritableBits(mNumMipLevels - 1))[2] = 0x80;
  465. }
  466. //--------------------------------------------------------------------------
  467. bool GBitmap::setFormat(GFXFormat fmt)
  468. {
  469. if (getFormat() == fmt)
  470. return true;
  471. PROFILE_SCOPE(GBitmap_setFormat);
  472. // this is a nasty pointer math hack
  473. // is there a quick way to calc pixels of a fully mipped bitmap?
  474. U32 pixels = 0;
  475. for (U32 i=0; i < mNumMipLevels; i++)
  476. pixels += getHeight(i) * getWidth(i);
  477. switch( getFormat() )
  478. {
  479. case GFXFormatR8G8B8:
  480. switch ( fmt )
  481. {
  482. case GFXFormatR5G5B5A1:
  483. #ifdef _XBOX
  484. bitmapConvertRGB_to_1555(mBits, pixels);
  485. #else
  486. bitmapConvertRGB_to_5551(mBits, pixels);
  487. #endif
  488. mInternalFormat = GFXFormatR5G5B5A1;
  489. mBytesPerPixel = 2;
  490. break;
  491. case GFXFormatR8G8B8A8:
  492. case GFXFormatR8G8B8X8:
  493. // Took this out, it may crash -patw
  494. //AssertFatal( mNumMipLevels == 1, "Do the mip-mapping in hardware." );
  495. bitmapConvertRGB_to_RGBX( &mBits, pixels );
  496. mInternalFormat = fmt;
  497. mBytesPerPixel = 4;
  498. mByteSize = pixels * 4;
  499. break;
  500. default:
  501. AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
  502. return false;
  503. }
  504. break;
  505. case GFXFormatR8G8B8X8:
  506. switch( fmt )
  507. {
  508. // No change needed for this
  509. case GFXFormatR8G8B8A8:
  510. mInternalFormat = GFXFormatR8G8B8A8;
  511. break;
  512. case GFXFormatR8G8B8:
  513. bitmapConvertRGBX_to_RGB( &mBits, pixels );
  514. mInternalFormat = GFXFormatR8G8B8;
  515. mBytesPerPixel = 3;
  516. mByteSize = pixels * 3;
  517. break;
  518. default:
  519. AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
  520. return false;
  521. }
  522. break;
  523. case GFXFormatR8G8B8A8:
  524. switch( fmt )
  525. {
  526. // No change needed for this
  527. case GFXFormatR8G8B8X8:
  528. mInternalFormat = GFXFormatR8G8B8X8;
  529. break;
  530. case GFXFormatR8G8B8:
  531. bitmapConvertRGBX_to_RGB( &mBits, pixels );
  532. mInternalFormat = GFXFormatR8G8B8;
  533. mBytesPerPixel = 3;
  534. mByteSize = pixels * 3;
  535. break;
  536. default:
  537. AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
  538. return false;
  539. }
  540. break;
  541. case GFXFormatA8:
  542. switch( fmt )
  543. {
  544. case GFXFormatR8G8B8A8:
  545. mInternalFormat = GFXFormatR8G8B8A8;
  546. bitmapConvertA8_to_RGBA( &mBits, pixels );
  547. mBytesPerPixel = 4;
  548. mByteSize = pixels * 4;
  549. break;
  550. default:
  551. AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
  552. return false;
  553. }
  554. break;
  555. default:
  556. AssertWarn(0, "GBitmap::setFormat: unable to convert bitmap to requested format.");
  557. return false;
  558. }
  559. U32 offset = 0;
  560. for (U32 j=0; j < mNumMipLevels; j++)
  561. {
  562. mMipLevelOffsets[j] = offset;
  563. offset += getHeight(j) * getWidth(j) * mBytesPerPixel;
  564. }
  565. return true;
  566. }
  567. //------------------------------------------------------------------------------
  568. bool GBitmap::checkForTransparency()
  569. {
  570. mHasTransparency = false;
  571. ColorI pixel(255, 255, 255, 255);
  572. switch (mInternalFormat)
  573. {
  574. // Non-transparent formats
  575. case GFXFormatL8:
  576. case GFXFormatL16:
  577. case GFXFormatR8G8B8:
  578. case GFXFormatR5G6B5:
  579. break;
  580. // Transparent formats
  581. case GFXFormatA8:
  582. case GFXFormatR8G8B8A8:
  583. case GFXFormatR5G5B5A1:
  584. // Let getColor() do the heavy lifting
  585. for (U32 x = 0; x < mWidth; x++)
  586. {
  587. for (U32 y = 0; y < mHeight; y++)
  588. {
  589. if (getColor(x, y, pixel))
  590. {
  591. if (pixel.alpha < 255)
  592. {
  593. mHasTransparency = true;
  594. break;
  595. }
  596. }
  597. }
  598. }
  599. break;
  600. default:
  601. AssertFatal(false, "GBitmap::checkForTransparency: misunderstood format specifier");
  602. break;
  603. }
  604. return mHasTransparency;
  605. }
  606. //------------------------------------------------------------------------------
  607. LinearColorF GBitmap::sampleTexel(F32 u, F32 v, bool retAlpha) const
  608. {
  609. LinearColorF col(0.5f, 0.5f, 0.5f);
  610. // normally sampling wraps all the way around at 1.0,
  611. // but locking doesn't support this, and we seem to calc
  612. // the uv based on a clamped 0 - 1...
  613. Point2F max((F32)(getWidth()-1), (F32)(getHeight()-1));
  614. Point2F posf;
  615. posf.x = mClampF(((u) * max.x), 0.0f, max.x);
  616. posf.y = mClampF(((v) * max.y), 0.0f, max.y);
  617. Point2I posi((S32)posf.x, (S32)posf.y);
  618. const U8 *buffer = getBits();
  619. U32 lexelindex = ((posi.y * getWidth()) + posi.x) * mBytesPerPixel;
  620. if(mBytesPerPixel == 2)
  621. {
  622. //U16 *buffer = (U16 *)lockrect->pBits;
  623. }
  624. else if(mBytesPerPixel > 2)
  625. {
  626. col.red = F32(buffer[lexelindex + 0]) / 255.0f;
  627. col.green = F32(buffer[lexelindex + 1]) / 255.0f;
  628. col.blue = F32(buffer[lexelindex + 2]) / 255.0f;
  629. if (retAlpha)
  630. {
  631. if (getHasTransparency())
  632. col.alpha = F32(buffer[lexelindex + 3]) / 255.0f;
  633. else
  634. col.alpha = 1.0f;
  635. }
  636. }
  637. return col;
  638. }
  639. //--------------------------------------------------------------------------
  640. bool GBitmap::getColor(const U32 x, const U32 y, ColorI& rColor) const
  641. {
  642. if (x >= mWidth || y >= mHeight)
  643. return false;
  644. const U8* pLoc = getAddress(x, y);
  645. switch (mInternalFormat) {
  646. case GFXFormatA8:
  647. case GFXFormatL8:
  648. rColor.set( *pLoc, *pLoc, *pLoc, *pLoc );
  649. break;
  650. case GFXFormatL16:
  651. rColor.set(U8(U16((pLoc[0] << 8) + pLoc[1])), 0, 0, 0);
  652. case GFXFormatR8G8B8:
  653. case GFXFormatR8G8B8X8:
  654. rColor.set( pLoc[0], pLoc[1], pLoc[2], 255 );
  655. break;
  656. case GFXFormatR8G8B8A8:
  657. rColor.set( pLoc[0], pLoc[1], pLoc[2], pLoc[3] );
  658. break;
  659. case GFXFormatR5G5B5A1:
  660. #if defined(TORQUE_OS_MAC)
  661. rColor.set( (*((U16*)pLoc) >> 0) & 0x1F,
  662. (*((U16*)pLoc) >> 5) & 0x1F,
  663. (*((U16*)pLoc) >> 10) & 0x1F,
  664. ((*((U16*)pLoc) >> 15) & 0x01) ? 255 : 0 );
  665. #else
  666. rColor.set( *((U16*)pLoc) >> 11,
  667. (*((U16*)pLoc) >> 6) & 0x1f,
  668. (*((U16*)pLoc) >> 1) & 0x1f,
  669. (*((U16*)pLoc) & 1) ? 255 : 0 );
  670. #endif
  671. break;
  672. default:
  673. AssertFatal(false, "Bad internal format");
  674. return false;
  675. }
  676. return true;
  677. }
  678. //--------------------------------------------------------------------------
  679. bool GBitmap::setColor(const U32 x, const U32 y, const ColorI& rColor)
  680. {
  681. if (x >= mWidth || y >= mHeight)
  682. return false;
  683. U8* pLoc = getAddress(x, y);
  684. switch (mInternalFormat) {
  685. case GFXFormatA8:
  686. case GFXFormatL8:
  687. *pLoc = rColor.alpha;
  688. break;
  689. case GFXFormatL16:
  690. dMemcpy(pLoc, &rColor, 2 * sizeof(U8));
  691. break;
  692. case GFXFormatR8G8B8:
  693. dMemcpy( pLoc, &rColor, 3 * sizeof( U8 ) );
  694. break;
  695. case GFXFormatR8G8B8A8:
  696. case GFXFormatR8G8B8X8:
  697. dMemcpy( pLoc, &rColor, 4 * sizeof( U8 ) );
  698. break;
  699. case GFXFormatR5G6B5:
  700. #ifdef TORQUE_OS_MAC
  701. *((U16*)pLoc) = (rColor.red << 11) | (rColor.green << 5) | (rColor.blue << 0) ;
  702. #else
  703. *((U16*)pLoc) = (rColor.blue << 0) | (rColor.green << 5) | (rColor.red << 11);
  704. #endif
  705. break;
  706. case GFXFormatR5G5B5A1:
  707. #ifdef TORQUE_OS_MAC
  708. *((U16*)pLoc) = (((rColor.alpha>0) ? 1 : 0)<<15) | (rColor.blue << 10) | (rColor.green << 5) | (rColor.red << 0);
  709. #else
  710. *((U16*)pLoc) = (rColor.blue << 1) | (rColor.green << 6) | (rColor.red << 11) | ((rColor.alpha>0) ? 1 : 0);
  711. #endif
  712. break;
  713. default:
  714. AssertFatal(false, "Bad internal format");
  715. return false;
  716. }
  717. return true;
  718. }
  719. //--------------------------------------------------------------------------
  720. U8 GBitmap::getChanelValueAt(U32 x, U32 y, U32 chan)
  721. {
  722. ColorI pixelColor = ColorI(255,255,255,255);
  723. getColor(x, y, pixelColor);
  724. if (mInternalFormat == GFXFormatL16)
  725. {
  726. chan = 0;
  727. }
  728. switch (chan) {
  729. case 0: return pixelColor.red;
  730. case 1: return pixelColor.green;
  731. case 2: return pixelColor.blue;
  732. default: return pixelColor.alpha;
  733. }
  734. }
  735. //-----------------------------------------------------------------------------
  736. bool GBitmap::combine( const GBitmap *bitmapA, const GBitmap *bitmapB, const TextureOp combineOp )
  737. {
  738. // Check bitmapA format
  739. switch( bitmapA->getFormat() )
  740. {
  741. case GFXFormatR8G8B8:
  742. case GFXFormatR8G8B8X8:
  743. case GFXFormatR8G8B8A8:
  744. break;
  745. default:
  746. Con::errorf( "GBitmap::combine - invalid format for bitmapA" );
  747. return false;
  748. }
  749. // Check bitmapB format
  750. switch( bitmapB->getFormat() )
  751. {
  752. case GFXFormatR8G8B8:
  753. case GFXFormatR8G8B8X8:
  754. case GFXFormatR8G8B8A8:
  755. break;
  756. default:
  757. Con::errorf( "GBitmap::combine - invalid format for bitmapB" );
  758. return false;
  759. }
  760. // Determine format of result texture
  761. // CodeReview: This is dependent on the order of the GFXFormat enum. [5/11/2007 Pat]
  762. GFXFormat resFmt = static_cast<GFXFormat>( getMax( bitmapA->getFormat(), bitmapB->getFormat() ) );
  763. U32 resWidth = getMax( bitmapA->getWidth(), bitmapB->getWidth() );
  764. U32 resHeight = getMax( bitmapA->getHeight(), bitmapB->getHeight() );
  765. // Adjust size OF bitmap based on the biggest one
  766. if( bitmapA->getWidth() != bitmapB->getWidth() ||
  767. bitmapA->getHeight() != bitmapB->getHeight() )
  768. {
  769. // Delete old bitmap
  770. deleteImage();
  771. // Allocate new one
  772. allocateBitmap( resWidth, resHeight, false, resFmt );
  773. }
  774. // Adjust format of result bitmap (if resFmt == getFormat() it will not perform the format convert)
  775. setFormat( resFmt );
  776. // Perform combine
  777. U8 *destBits = getWritableBits();
  778. const U8 *aBits = bitmapA->getBits();
  779. const U8 *bBits = bitmapB->getBits();
  780. for( S32 y = 0; y < getHeight(); y++ )
  781. {
  782. for( S32 x = 0; x < getWidth(); x++ )
  783. {
  784. for( S32 _byte = 0; _byte < mBytesPerPixel; _byte++ )
  785. {
  786. U8 pxA = 0;
  787. U8 pxB = 0;
  788. // Get contributions from A and B
  789. if( y < bitmapA->getHeight() &&
  790. x < bitmapA->getWidth() &&
  791. _byte < bitmapA->mBytesPerPixel )
  792. pxA = *aBits++;
  793. if( y < bitmapB->getHeight() &&
  794. x < bitmapB->getWidth() &&
  795. _byte < bitmapB->mBytesPerPixel )
  796. pxB = *bBits++;
  797. // Combine them (clamp values 0-U8_MAX)
  798. switch( combineOp )
  799. {
  800. case Add:
  801. *destBits++ = getMin( U8( pxA + pxB ), U8_MAX );
  802. break;
  803. case Subtract:
  804. *destBits++ = getMax( U8( pxA - pxB ), U8( 0 ) );
  805. break;
  806. default:
  807. AssertFatal(false, "GBitmap::combine - Invalid combineOp");
  808. break;
  809. }
  810. }
  811. }
  812. }
  813. return true;
  814. }
  815. void GBitmap::fill( const ColorI &rColor )
  816. {
  817. // Set the first pixel using the slow
  818. // but proper method.
  819. setColor( 0, 0, rColor );
  820. mHasTransparency = rColor.alpha < 255;
  821. // Now fill the first row of the bitmap by
  822. // copying the first pixel across the row.
  823. const U32 stride = getWidth() * mBytesPerPixel;
  824. const U8 *src = getBits();
  825. U8 *dest = getWritableBits() + mBytesPerPixel;
  826. const U8 *end = src + stride;
  827. for ( ; dest != end; dest += mBytesPerPixel )
  828. dMemcpy( dest, src, mBytesPerPixel );
  829. // Now copy the first row to all the others.
  830. //
  831. // TODO: This could adaptively size the copy
  832. // amount to copy more rows from the source
  833. // and reduce the total number of memcpy calls.
  834. //
  835. dest = getWritableBits() + stride;
  836. end = src + ( stride * getHeight() );
  837. for ( ; dest != end; dest += stride )
  838. dMemcpy( dest, src, stride );
  839. }
  840. void GBitmap::fillWhite()
  841. {
  842. dMemset( getWritableBits(), 255, mByteSize );
  843. mHasTransparency = false;
  844. }
  845. GBitmap* GBitmap::createPaddedBitmap() const
  846. {
  847. if (isPow2(getWidth()) && isPow2(getHeight()))
  848. return NULL;
  849. AssertFatal(getNumMipLevels() == 1,
  850. "Cannot have non-pow2 bitmap with miplevels");
  851. U32 width = getWidth();
  852. U32 height = getHeight();
  853. U32 newWidth = getNextPow2(getWidth());
  854. U32 newHeight = getNextPow2(getHeight());
  855. GBitmap* pReturn = new GBitmap(newWidth, newHeight, false, getFormat());
  856. for (U32 i = 0; i < height; i++)
  857. {
  858. U8* pDest = (U8*)pReturn->getAddress(0, i);
  859. const U8* pSrc = (const U8*)getAddress(0, i);
  860. dMemcpy(pDest, pSrc, width * mBytesPerPixel);
  861. pDest += width * mBytesPerPixel;
  862. // set the src pixel to the last pixel in the row
  863. const U8 *pSrcPixel = pDest - mBytesPerPixel;
  864. for(U32 j = width; j < newWidth; j++)
  865. for(U32 k = 0; k < mBytesPerPixel; k++)
  866. *pDest++ = pSrcPixel[k];
  867. }
  868. for(U32 i = height; i < newHeight; i++)
  869. {
  870. U8* pDest = (U8*)pReturn->getAddress(0, i);
  871. U8* pSrc = (U8*)pReturn->getAddress(0, height-1);
  872. dMemcpy(pDest, pSrc, newWidth * mBytesPerPixel);
  873. }
  874. return pReturn;
  875. }
  876. GBitmap* GBitmap::createPow2Bitmap() const
  877. {
  878. if (isPow2(getWidth()) && isPow2(getHeight()))
  879. return NULL;
  880. AssertFatal(getNumMipLevels() == 1,
  881. "Cannot have non-pow2 bitmap with miplevels");
  882. U32 width = getWidth();
  883. U32 height = getHeight();
  884. U32 newWidth = getNextPow2(getWidth());
  885. U32 newHeight = getNextPow2(getHeight());
  886. GBitmap* pReturn = new GBitmap(newWidth, newHeight, false, getFormat());
  887. U8* pDest = (U8*)pReturn->getAddress(0, 0);
  888. const U8* pSrc = (const U8*)getAddress(0, 0);
  889. F32 yCoeff = (F32) height / (F32) newHeight;
  890. F32 xCoeff = (F32) width / (F32) newWidth;
  891. F32 currY = 0.0f;
  892. for (U32 y = 0; y < newHeight; y++)
  893. {
  894. F32 currX = 0.0f;
  895. //U32 yDestOffset = (pReturn->mWidth * pReturn->mBytesPerPixel) * y;
  896. //U32 xDestOffset = 0;
  897. //U32 ySourceOffset = (U32)((mWidth * mBytesPerPixel) * currY);
  898. //F32 xSourceOffset = 0.0f;
  899. for (U32 x = 0; x < newWidth; x++)
  900. {
  901. pDest = (U8*) pReturn->getAddress(x, y);
  902. pSrc = (U8*) getAddress((S32)currX, (S32)currY);
  903. for (U32 p = 0; p < pReturn->mBytesPerPixel; p++)
  904. {
  905. pDest[p] = pSrc[p];
  906. }
  907. currX += xCoeff;
  908. }
  909. currY += yCoeff;
  910. }
  911. return pReturn;
  912. }
  913. void GBitmap::copyChannel( U32 index, GBitmap *outBitmap ) const
  914. {
  915. AssertFatal( index < mBytesPerPixel, "GBitmap::copyChannel() - Bad channel offset!" );
  916. AssertFatal( outBitmap, "GBitmap::copyChannel() - Null output bitmap!" );
  917. AssertFatal( outBitmap->getWidth() == getWidth(), "GBitmap::copyChannel() - Width mismatch!" );
  918. AssertFatal( outBitmap->getHeight() == getHeight(), "GBitmap::copyChannel() - Height mismatch!" );
  919. U8 *outBits = outBitmap->getWritableBits();
  920. const U32 outBytesPerPixel = outBitmap->getBytesPerPixel();
  921. const U8 *srcBits = getBits() + index;
  922. const U8 *endBits = getBits() + mByteSize;
  923. for ( ; srcBits < endBits; )
  924. {
  925. *outBits = *srcBits;
  926. outBits += outBytesPerPixel;
  927. srcBits += mBytesPerPixel;
  928. }
  929. }
  930. //------------------------------------------------------------------------------
  931. bool GBitmap::read(Stream& io_rStream)
  932. {
  933. // Handle versioning
  934. U32 version;
  935. io_rStream.read(&version);
  936. AssertFatal(version == csFileVersion, "Bitmap::read: incorrect file version");
  937. //-------------------------------------- Read the object
  938. U32 fmt;
  939. io_rStream.read(&fmt);
  940. mInternalFormat = GFXFormat(fmt);
  941. mBytesPerPixel = 1;
  942. switch (mInternalFormat) {
  943. case GFXFormatA8:
  944. case GFXFormatL8: mBytesPerPixel = 1;
  945. break;
  946. case GFXFormatR8G8B8: mBytesPerPixel = 3;
  947. break;
  948. case GFXFormatR8G8B8A8: mBytesPerPixel = 4;
  949. break;
  950. case GFXFormatL16:
  951. case GFXFormatR5G6B5:
  952. case GFXFormatR5G5B5A1: mBytesPerPixel = 2;
  953. break;
  954. default:
  955. AssertFatal(false, "GBitmap::read: misunderstood format specifier");
  956. break;
  957. }
  958. io_rStream.read(&mByteSize);
  959. mBits = new U8[mByteSize];
  960. io_rStream.read(mByteSize, mBits);
  961. io_rStream.read(&mWidth);
  962. io_rStream.read(&mHeight);
  963. io_rStream.read(&mNumMipLevels);
  964. for (U32 i = 0; i < c_maxMipLevels; i++)
  965. io_rStream.read(&mMipLevelOffsets[i]);
  966. checkForTransparency();
  967. return (io_rStream.getStatus() == Stream::Ok);
  968. }
  969. bool GBitmap::write(Stream& io_rStream) const
  970. {
  971. // Handle versioning
  972. io_rStream.write(csFileVersion);
  973. //-------------------------------------- Write the object
  974. io_rStream.write(U32(mInternalFormat));
  975. io_rStream.write(mByteSize);
  976. io_rStream.write(mByteSize, mBits);
  977. io_rStream.write(mWidth);
  978. io_rStream.write(mHeight);
  979. io_rStream.write(mNumMipLevels);
  980. for (U32 i = 0; i < c_maxMipLevels; i++)
  981. io_rStream.write(mMipLevelOffsets[i]);
  982. return (io_rStream.getStatus() == Stream::Ok);
  983. }
  984. //------------------------------------------------------------------------------
  985. //-------------------------------------- Persistent I/O
  986. //
  987. bool GBitmap::readBitmap( const String &bmType, Stream &ioStream )
  988. {
  989. PROFILE_SCOPE(ResourceGBitmap_readBitmap);
  990. const GBitmap::Registration *regInfo = GBitmap::sFindRegInfo( bmType );
  991. if ( regInfo == NULL )
  992. {
  993. Con::errorf( "[GBitmap::readBitmap] unable to find registration for extension [%s]", bmType.c_str() );
  994. return false;
  995. }
  996. return regInfo->readFunc( ioStream, this );
  997. }
  998. bool GBitmap::writeBitmap( const String &bmType, Stream &ioStream, U32 compressionLevel )
  999. {
  1000. const GBitmap::Registration *regInfo = GBitmap::sFindRegInfo( bmType );
  1001. if ( regInfo == NULL )
  1002. {
  1003. Con::errorf( "[GBitmap::writeBitmap] unable to find registration for extension [%s]", bmType.c_str() );
  1004. return false;
  1005. }
  1006. return regInfo->writeFunc( this, ioStream, (compressionLevel == U32_MAX) ? regInfo->defaultCompression : compressionLevel );
  1007. }
  1008. template<> void *Resource<GBitmap>::create(const Torque::Path &path)
  1009. {
  1010. PROFILE_SCOPE( ResourceGBitmap_create );
  1011. #ifdef TORQUE_DEBUG_RES_MANAGER
  1012. Con::printf( "Resource<GBitmap>::create - [%s]", path.getFullPath().c_str() );
  1013. #endif
  1014. FileStream stream;
  1015. stream.open( path.getFullPath(), Torque::FS::File::Read );
  1016. if ( stream.getStatus() != Stream::Ok )
  1017. {
  1018. Con::errorf( "Resource<GBitmap>::create - failed to open '%s'", path.getFullPath().c_str() );
  1019. return NULL;
  1020. }
  1021. GBitmap *bmp = new GBitmap;
  1022. const String extension = path.getExtension();
  1023. if( !bmp->readBitmap( extension, stream ) )
  1024. {
  1025. Con::errorf( "Resource<GBitmap>::create - error reading '%s'", path.getFullPath().c_str() );
  1026. delete bmp;
  1027. bmp = NULL;
  1028. }
  1029. return bmp;
  1030. }
  1031. template<> ResourceBase::Signature Resource<GBitmap>::signature()
  1032. {
  1033. return MakeFourCC('b','i','t','m');
  1034. }
  1035. Resource<GBitmap> GBitmap::load(const Torque::Path &path)
  1036. {
  1037. Resource<GBitmap> ret = _load( path );
  1038. if ( ret != NULL )
  1039. return ret;
  1040. // Do a recursive search.
  1041. return _search( path );
  1042. }
  1043. Resource<GBitmap> GBitmap::_load(const Torque::Path &path)
  1044. {
  1045. PROFILE_SCOPE( GBitmap_load );
  1046. if ( Torque::FS::IsFile( path ) )
  1047. return ResourceManager::get().load( path );
  1048. Path foundPath;
  1049. if ( GBitmap::sFindFile( path, &foundPath ) )
  1050. {
  1051. Resource<GBitmap> ret = ResourceManager::get().load( foundPath );
  1052. if ( ret != NULL )
  1053. return ret;
  1054. }
  1055. return Resource< GBitmap >( NULL );
  1056. }
  1057. Resource<GBitmap> GBitmap::_search(const Torque::Path &path)
  1058. {
  1059. PROFILE_SCOPE( GBitmap_search );
  1060. // If unable to load texture in current directory
  1061. // look in the parent directory. But never look in the root.
  1062. Path newPath( path );
  1063. while ( true )
  1064. {
  1065. String filePath = newPath.getPath();
  1066. String::SizeType slash = filePath.find( '/', filePath.length(), String::Right );
  1067. if ( slash == String::NPos )
  1068. break;
  1069. slash = filePath.find( '/', filePath.length(), String::Right );
  1070. if ( slash == String::NPos )
  1071. break;
  1072. String truncPath = filePath.substr( 0, slash );
  1073. newPath.setPath( truncPath );
  1074. Resource<GBitmap> ret = _load( newPath );
  1075. if ( ret != NULL )
  1076. return ret;
  1077. }
  1078. return Resource< GBitmap >( NULL );
  1079. }
  1080. U32 GBitmap::getSurfaceSize(const U32 mipLevel) const
  1081. {
  1082. // Bump by the mip level.
  1083. U32 height = getMax(U32(1), mHeight >> mipLevel);
  1084. U32 width = getMax(U32(1), mWidth >> mipLevel);
  1085. if (mInternalFormat >= GFXFormatBC1 && mInternalFormat <= GFXFormatBC3)
  1086. {
  1087. // From the directX docs:
  1088. // max(1, width ÷ 4) x max(1, height ÷ 4) x 8(DXT1) or 16(DXT2-5)
  1089. U32 sizeMultiple = 0;
  1090. switch (mInternalFormat)
  1091. {
  1092. case GFXFormatBC1:
  1093. sizeMultiple = 8;
  1094. break;
  1095. case GFXFormatBC2:
  1096. case GFXFormatBC3:
  1097. sizeMultiple = 16;
  1098. break;
  1099. default:
  1100. AssertISV(false, "DDSFile::getSurfaceSize - invalid compressed texture format, we only support DXT1-5 right now.");
  1101. break;
  1102. }
  1103. return getMax(U32(1), width / 4) * getMax(U32(1), height / 4) * sizeMultiple;
  1104. }
  1105. else
  1106. {
  1107. return height * width* mBytesPerPixel;
  1108. }
  1109. }
  1110. DefineEngineFunction( getBitmapInfo, String, ( const char *filename ),,
  1111. "Returns image info in the following format: width TAB height TAB bytesPerPixel TAB format. "
  1112. "It will return an empty string if the file is not found.\n"
  1113. "@ingroup Rendering\n" )
  1114. {
  1115. Resource<GBitmap> image = GBitmap::load( filename );
  1116. if ( !image )
  1117. return String::EmptyString;
  1118. return String::ToString( "%d\t%d\t%d\t%d", image->getWidth(),
  1119. image->getHeight(),
  1120. image->getBytesPerPixel(),
  1121. image->getFormat());
  1122. }
  1123. DefineEngineFunction(saveScaledImage, bool, (const char* bitmapSource, const char* bitmapDest, S32 resolutionSize), ("", "", 256),
  1124. "Loads an image from the source path, and scales it down to the target resolution before"
  1125. "Saving it out to the destination path.\n")
  1126. {
  1127. bool isDDS = false;
  1128. if (bitmapSource == 0 || bitmapSource[0] == '\0' || bitmapDest == 0 || bitmapDest[0] == '\0')
  1129. {
  1130. return false;
  1131. }
  1132. if (!Platform::isFile(bitmapSource))
  1133. {
  1134. return false;
  1135. }
  1136. //First, gotta check the extension, as we have some extra work to do if it's
  1137. //a DDS file
  1138. const char* ret = dStrrchr(bitmapSource, '.');
  1139. if (ret)
  1140. {
  1141. if (String::ToLower(ret) == String(".dds"))
  1142. isDDS = true;
  1143. }
  1144. else
  1145. {
  1146. return false; //no extension? bail out
  1147. }
  1148. GBitmap* image = NULL;
  1149. if (isDDS)
  1150. {
  1151. Resource<DDSFile> dds = DDSFile::load(bitmapSource, 0);
  1152. if (dds != NULL)
  1153. {
  1154. image = new GBitmap();
  1155. if (!dds->decompressToGBitmap(image))
  1156. {
  1157. delete image;
  1158. image = NULL;
  1159. }
  1160. }
  1161. }
  1162. else
  1163. {
  1164. Resource<GBitmap> resImage = GBitmap::load(bitmapSource);
  1165. image = new GBitmap(*resImage);
  1166. }
  1167. if (!image)
  1168. return false;
  1169. Torque::Path sourcePath = Torque::Path(bitmapSource);
  1170. if (isPow2(image->getWidth()) && isPow2(image->getHeight()))
  1171. image->extrudeMipLevels();
  1172. U32 mipCount = image->getNumMipLevels();
  1173. U32 targetMips = mFloor(mLog2((F32)(resolutionSize ? resolutionSize : 256))) + 1;
  1174. if (mipCount > targetMips)
  1175. {
  1176. image->chopTopMips(mipCount - targetMips);
  1177. }
  1178. //TODO: support different format targets, for now we just force
  1179. //to png for simplicity
  1180. Torque::Path destinationPath = Torque::Path(bitmapDest);
  1181. destinationPath.setExtension("png");
  1182. // Open up the file on disk.
  1183. FileStream fs;
  1184. if (!fs.open(destinationPath.getFullPath(), Torque::FS::File::Write))
  1185. {
  1186. Con::errorf("saveScaledImage() - Failed to open output file '%s'!", bitmapDest);
  1187. return false;
  1188. }
  1189. else
  1190. {
  1191. image->writeBitmap("png", fs);
  1192. fs.close();
  1193. }
  1194. return true;
  1195. }