llimagedxt.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:13k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llimagedxt.cpp
  3.  *
  4.  * $LicenseInfo:firstyear=2001&license=viewergpl$
  5.  * 
  6.  * Copyright (c) 2001-2010, Linden Research, Inc.
  7.  * 
  8.  * Second Life Viewer Source Code
  9.  * The source code in this file ("Source Code") is provided by Linden Lab
  10.  * to you under the terms of the GNU General Public License, version 2.0
  11.  * ("GPL"), unless you have obtained a separate licensing agreement
  12.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  13.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15.  * 
  16.  * There are special exceptions to the terms and conditions of the GPL as
  17.  * it is applied to this Source Code. View the full text of the exception
  18.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  19.  * online at
  20.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21.  * 
  22.  * By copying, modifying or distributing this software, you acknowledge
  23.  * that you have read and understood your obligations described above,
  24.  * and agree to abide by those obligations.
  25.  * 
  26.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28.  * COMPLETENESS OR PERFORMANCE.
  29.  * $/LicenseInfo$
  30.  */
  31. #include "linden_common.h"
  32. #include "llimagedxt.h"
  33. //static
  34. void LLImageDXT::checkMinWidthHeight(EFileFormat format, S32& width, S32& height)
  35. {
  36. S32 mindim = (format >= FORMAT_DXT1 && format <= FORMAT_DXR5) ? 4 : 1;
  37. width = llmax(width, mindim);
  38. height = llmax(height, mindim);
  39. }
  40. //static
  41. S32 LLImageDXT::formatBits(EFileFormat format)
  42. {
  43. switch (format)
  44. {
  45.     case FORMAT_DXT1:  return 4;
  46.   case FORMAT_DXR1:  return 4;
  47.   case FORMAT_I8: return 8;
  48.   case FORMAT_A8: return 8;
  49.     case FORMAT_DXT3: return 8;
  50.   case FORMAT_DXR3: return 8;
  51.     case FORMAT_DXR5: return 8;
  52.     case FORMAT_DXT5: return 8;
  53.   case FORMAT_RGB8: return 24;
  54.   case FORMAT_RGBA8: return 32;
  55.   default:
  56. llerrs << "LLImageDXT::Unknown format: " << format << llendl;
  57. return 0;
  58. }
  59. };
  60. //static
  61. S32 LLImageDXT::formatBytes(EFileFormat format, S32 width, S32 height)
  62. {
  63. checkMinWidthHeight(format, width, height);
  64. S32 bytes = ((width*height*formatBits(format)+7)>>3);
  65. S32 aligned = (bytes+3)&~3;
  66. return aligned;
  67. }
  68. //static
  69. S32 LLImageDXT::formatComponents(EFileFormat format)
  70. {
  71. switch (format)
  72. {
  73.     case FORMAT_DXT1:  return 3;
  74.   case FORMAT_DXR1:  return 3;
  75.   case FORMAT_I8: return 1;
  76.   case FORMAT_A8: return 1;
  77.     case FORMAT_DXT3: return 4;
  78.   case FORMAT_DXR3: return 4;
  79.     case FORMAT_DXT5: return 4;
  80.     case FORMAT_DXR5: return 4;
  81.   case FORMAT_RGB8: return 3;
  82.   case FORMAT_RGBA8: return 4;
  83.   default:
  84. llerrs << "LLImageDXT::Unknown format: " << format << llendl;
  85. return 0;
  86. }
  87. };
  88. // static 
  89. LLImageDXT::EFileFormat LLImageDXT::getFormat(S32 fourcc)
  90. {
  91. switch(fourcc)
  92. {
  93. case 0x20203849: return FORMAT_I8;
  94. case 0x20203841: return FORMAT_A8;
  95. case 0x20424752: return FORMAT_RGB8;
  96. case 0x41424752: return FORMAT_RGBA8;
  97. case 0x31525844: return FORMAT_DXR1;
  98. case 0x32525844: return FORMAT_DXR2;
  99. case 0x33525844: return FORMAT_DXR3;
  100. case 0x34525844: return FORMAT_DXR4;
  101. case 0x35525844: return FORMAT_DXR5;
  102. case 0x31545844: return FORMAT_DXT1;
  103. case 0x32545844: return FORMAT_DXT2;
  104. case 0x33545844: return FORMAT_DXT3;
  105. case 0x34545844: return FORMAT_DXT4;
  106. case 0x35545844: return FORMAT_DXT5;
  107. default: return FORMAT_UNKNOWN;
  108. }
  109. }
  110. //static
  111. S32 LLImageDXT::getFourCC(EFileFormat format)
  112. {
  113. switch(format)
  114. {
  115. case FORMAT_I8: return 0x20203849;
  116. case FORMAT_A8: return 0x20203841;
  117. case FORMAT_RGB8: return 0x20424752;
  118. case FORMAT_RGBA8: return 0x41424752;
  119. case FORMAT_DXR1: return 0x31525844;
  120. case FORMAT_DXR2: return 0x32525844;
  121. case FORMAT_DXR3: return 0x33525844;
  122. case FORMAT_DXR4: return 0x34525844;
  123. case FORMAT_DXR5: return 0x35525844;
  124. case FORMAT_DXT1: return 0x31545844;
  125. case FORMAT_DXT2: return 0x32545844;
  126. case FORMAT_DXT3: return 0x33545844;
  127. case FORMAT_DXT4: return 0x34545844;
  128. case FORMAT_DXT5: return 0x35545844;
  129. default: return 0x00000000;
  130. }
  131. }
  132. //static
  133. void LLImageDXT::calcDiscardWidthHeight(S32 discard_level, EFileFormat format, S32& width, S32& height)
  134. {
  135. while (discard_level > 0 && width > 1 && height > 1)
  136. {
  137. discard_level--;
  138. width >>= 1;
  139. height >>= 1;
  140. }
  141. checkMinWidthHeight(format, width, height);
  142. }
  143. //static
  144. S32 LLImageDXT::calcNumMips(S32 width, S32 height)
  145. {
  146. S32 nmips = 0;
  147. while (width > 0 && height > 0)
  148. {
  149. width >>= 1;
  150. height >>= 1;
  151. nmips++;
  152. }
  153. return nmips;
  154. }
  155. //============================================================================
  156. LLImageDXT::LLImageDXT()
  157. : LLImageFormatted(IMG_CODEC_DXT),
  158.   mFileFormat(FORMAT_UNKNOWN),
  159.   mHeaderSize(0)
  160. {
  161. }
  162. LLImageDXT::~LLImageDXT()
  163. {
  164. }
  165. // virtual
  166. BOOL LLImageDXT::updateData()
  167. {
  168. resetLastError();
  169. U8* data = getData();
  170. S32 data_size = getDataSize();
  171. if (!data || !data_size)
  172. {
  173. setLastError("LLImageDXT uninitialized");
  174. return FALSE;
  175. }
  176. S32 width, height, miplevelmax;
  177. dxtfile_header_t* header = (dxtfile_header_t*)data;
  178. if (header->fourcc != 0x20534444)
  179. {
  180. dxtfile_header_old_t* oldheader = (dxtfile_header_old_t*)header;
  181. mHeaderSize = sizeof(dxtfile_header_old_t);
  182. mFileFormat = EFileFormat(oldheader->format);
  183. miplevelmax = llmin(oldheader->maxlevel,MAX_IMAGE_MIP);
  184. width = oldheader->maxwidth;
  185. height = oldheader->maxheight;
  186. }
  187. else
  188. {
  189. mHeaderSize = sizeof(dxtfile_header_t);
  190. mFileFormat = getFormat(header->pixel_fmt.fourcc);
  191. miplevelmax = llmin(header->num_mips-1,MAX_IMAGE_MIP);
  192. width = header->maxwidth;
  193. height = header->maxheight;
  194. }
  195. if (data_size < mHeaderSize)
  196. {
  197. llerrs << "LLImageDXT: not enough data" << llendl;
  198. }
  199. S32 ncomponents = formatComponents(mFileFormat);
  200. setSize(width, height, ncomponents);
  201. S32 discard = calcDiscardLevelBytes(data_size);
  202. discard = llmin(discard, miplevelmax);
  203. setDiscardLevel(discard);
  204. return TRUE;
  205. }
  206. // discard: 0 = largest (last) mip
  207. S32 LLImageDXT::getMipOffset(S32 discard)
  208. {
  209. if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXT5)
  210. {
  211. llerrs << "getMipOffset called with old (unsupported) format" << llendl;
  212. }
  213. S32 width = getWidth(), height = getHeight();
  214. S32 num_mips = calcNumMips(width, height);
  215. discard = llclamp(discard, 0, num_mips-1);
  216. S32 last_mip = num_mips-1-discard;
  217. llassert(mHeaderSize > 0);
  218. S32 offset = mHeaderSize;
  219. for (S32 mipidx = num_mips-1; mipidx >= 0; mipidx--)
  220. {
  221. if (mipidx < last_mip)
  222. {
  223. offset += formatBytes(mFileFormat, width, height);
  224. }
  225. width >>= 1;
  226. height >>= 1;
  227. }
  228. return offset;
  229. }
  230. void LLImageDXT::setFormat()
  231. {
  232. S32 ncomponents = getComponents();
  233. switch (ncomponents)
  234. {
  235.   case 3: mFileFormat = FORMAT_DXR1; break;
  236.   case 4: mFileFormat = FORMAT_DXR3; break;
  237.   default: llerrs << "LLImageDXT::setFormat called with ncomponents = " << ncomponents << llendl;
  238. }
  239. mHeaderSize = calcHeaderSize();
  240. }
  241. // virtual
  242. BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
  243. {
  244. // *TODO: Test! This has been tweaked since its intial inception,
  245. //  but we don't use it any more!
  246. llassert_always(raw_image);
  247. if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
  248. {
  249. llwarns << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << llendl;
  250. return FALSE;
  251. }
  252. S32 width = getWidth(), height = getHeight();
  253. S32 ncomponents = getComponents();
  254. U8* data = NULL;
  255. if (mDiscardLevel >= 0)
  256. {
  257. data = getData() + getMipOffset(mDiscardLevel);
  258. calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
  259. }
  260. else
  261. {
  262. data = getData() + getMipOffset(0);
  263. }
  264. S32 image_size = formatBytes(mFileFormat, width, height);
  265. if ((!getData()) || (data + image_size > getData() + getDataSize()))
  266. {
  267. setLastError("LLImageDXT trying to decode an image with not enough data!");
  268. return FALSE;
  269. }
  270. raw_image->resize(width, height, ncomponents);
  271. memcpy(raw_image->getData(), data, image_size); /* Flawfinder: ignore */
  272. return TRUE;
  273. }
  274. BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
  275. {
  276. if (discard < 0)
  277. {
  278. discard = mDiscardLevel;
  279. }
  280. else if (discard < mDiscardLevel)
  281. {
  282. llerrs << "Request for invalid discard level" << llendl;
  283. }
  284. U8* data = getData() + getMipOffset(discard);
  285. S32 width = 0;
  286. S32 height = 0;
  287. calcDiscardWidthHeight(discard, mFileFormat, width, height);
  288. raw = new LLImageRaw(data, width, height, getComponents());
  289. return TRUE;
  290. }
  291. BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips)
  292. {
  293. llassert_always(raw_image);
  294. S32 ncomponents = raw_image->getComponents();
  295. EFileFormat format;
  296. switch (ncomponents)
  297. {
  298.   case 1:
  299. format = FORMAT_A8;
  300. break;
  301.   case 3:
  302. format = FORMAT_RGB8;
  303. break;
  304.   case 4:
  305. format = FORMAT_RGBA8;
  306. break;
  307.   default:
  308. llerrs << "LLImageDXT::encode: Unhandled channel number: " << ncomponents << llendl;
  309. return 0;
  310. }
  311. S32 width = raw_image->getWidth();
  312. S32 height = raw_image->getHeight();
  313. if (explicit_mips)
  314. {
  315. height = (height/3)*2;
  316. }
  317. setSize(width, height, ncomponents);
  318. mHeaderSize = sizeof(dxtfile_header_t);
  319. mFileFormat = format;
  320. S32 nmips = calcNumMips(width, height);
  321. S32 w = width;
  322. S32 h = height;
  323. S32 totbytes = mHeaderSize;
  324. for (S32 mip=0; mip<nmips; mip++)
  325. {
  326. totbytes += formatBytes(format,w,h);
  327. w >>= 1;
  328. h >>= 1;
  329. }
  330. allocateData(totbytes);
  331. U8* data = getData();
  332. dxtfile_header_t* header = (dxtfile_header_t*)data;
  333. llassert(mHeaderSize > 0);
  334. memset(header, 0, mHeaderSize);
  335. header->fourcc = 0x20534444;
  336. header->pixel_fmt.fourcc = getFourCC(format);
  337. header->num_mips = nmips;
  338. header->maxwidth = width;
  339. header->maxheight = height;
  340. U8* prev_mipdata = 0;
  341. w = width, h = height;
  342. for (S32 mip=0; mip<nmips; mip++)
  343. {
  344. U8* mipdata = data + getMipOffset(mip);
  345. S32 bytes = formatBytes(format, w, h);
  346. if (mip==0)
  347. {
  348. memcpy(mipdata, raw_image->getData(), bytes); /* Flawfinder: ignore */
  349. }
  350. else if (explicit_mips)
  351. {
  352. extractMip(raw_image->getData(), mipdata, width, height, w, h, format);
  353. }
  354. else
  355. {
  356. generateMip(prev_mipdata, mipdata, w, h, ncomponents);
  357. }
  358. w >>= 1;
  359. h >>= 1;
  360. checkMinWidthHeight(format, w, h);
  361. prev_mipdata = mipdata;
  362. }
  363. return TRUE;
  364. }
  365. // virtual
  366. BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time)
  367. {
  368. return encodeDXT(raw_image, time, false);
  369. }
  370. // virtual
  371. bool LLImageDXT::convertToDXR()
  372. {
  373. EFileFormat newformat = FORMAT_UNKNOWN;
  374. switch (mFileFormat)
  375. {
  376.   case FORMAT_DXR1:
  377.   case FORMAT_DXR2:
  378.   case FORMAT_DXR3:
  379.   case FORMAT_DXR4:
  380.   case FORMAT_DXR5:
  381. return false; // nothing to do
  382.   case FORMAT_DXT1: newformat = FORMAT_DXR1; break;
  383.   case FORMAT_DXT2: newformat = FORMAT_DXR2; break;
  384.   case FORMAT_DXT3: newformat = FORMAT_DXR3; break;
  385.   case FORMAT_DXT4: newformat = FORMAT_DXR4; break;
  386.   case FORMAT_DXT5: newformat = FORMAT_DXR5; break;
  387.   default:
  388. llwarns << "convertToDXR: can not convert format: " << llformat("0x%08x",getFourCC(mFileFormat)) << llendl;
  389. return false;
  390. }
  391. mFileFormat = newformat;
  392. S32 width = getWidth(), height = getHeight();
  393. S32 nmips = calcNumMips(width,height);
  394. S32 total_bytes = getDataSize();
  395. U8* olddata = getData();
  396. U8* newdata = new U8[total_bytes];
  397. if (!newdata)
  398. {
  399. llerrs << "Out of memory in LLImageDXT::convertToDXR()" << llendl;
  400. return false;
  401. }
  402. llassert(total_bytes > 0);
  403. memset(newdata, 0, total_bytes);
  404. memcpy(newdata, olddata, mHeaderSize); /* Flawfinder: ignore */
  405. for (S32 mip=0; mip<nmips; mip++)
  406. {
  407. S32 bytes = formatBytes(mFileFormat, width, height);
  408. S32 newoffset = getMipOffset(mip);
  409. S32 oldoffset = mHeaderSize + (total_bytes - newoffset - bytes);
  410. memcpy(newdata + newoffset, olddata + oldoffset, bytes); /* Flawfinder: ignore */
  411. width >>= 1;
  412. height >>= 1;
  413. }
  414. dxtfile_header_t* header = (dxtfile_header_t*)newdata;
  415. header->pixel_fmt.fourcc = getFourCC(newformat);
  416. setData(newdata, total_bytes);
  417. updateData();
  418. return true;
  419. }
  420. // virtual
  421. S32 LLImageDXT::calcHeaderSize()
  422. {
  423. return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t));
  424. }
  425. // virtual
  426. S32 LLImageDXT::calcDataSize(S32 discard_level)
  427. {
  428. if (mFileFormat == FORMAT_UNKNOWN)
  429. {
  430. llerrs << "calcDataSize called with unloaded LLImageDXT" << llendl;
  431. return 0;
  432. }
  433. if (discard_level < 0)
  434. {
  435. discard_level = mDiscardLevel;
  436. }
  437. S32 bytes = getMipOffset(discard_level); // size of header + previous mips
  438. S32 w = getWidth() >> discard_level;
  439. S32 h = getHeight() >> discard_level;
  440. bytes += formatBytes(mFileFormat,w,h);
  441. return bytes;
  442. }
  443. //============================================================================
  444. //static
  445. void LLImageDXT::extractMip(const U8 *indata, U8* mipdata, int width, int height,
  446. int mip_width, int mip_height, EFileFormat format)
  447. {
  448. int initial_offset = formatBytes(format, width, height);
  449. int line_width = formatBytes(format, width, 1);
  450. int mip_line_width = formatBytes(format, mip_width, 1);
  451. int line_offset = 0;
  452. for (int ww=width>>1; ww>mip_width; ww>>=1)
  453. {
  454. line_offset += formatBytes(format, ww, 1);
  455. }
  456. for (int h=0;h<mip_height;++h)
  457. {
  458. int start_offset = initial_offset + line_width * h + line_offset;
  459. memcpy(mipdata + mip_line_width*h, indata + start_offset, mip_line_width); /* Flawfinder: ignore */
  460. }
  461. }
  462. //============================================================================