PixelData.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.CompilerServices;
  5. using System.Runtime.InteropServices;
  6. using System.Text;
  7. namespace BansheeEngine
  8. {
  9. /// <summary>
  10. /// Pixel formats usable by images, textures and render surfaces.
  11. /// </summary>
  12. public enum PixelFormat // Note: Must match C++ enum PixelFormat
  13. {
  14. /// <summary>
  15. /// 8-bit pixel format, all bits red.
  16. /// </summary>
  17. R8 = 1,
  18. /// <summary>
  19. /// 2 byte pixel format, 1 byte red, 1 byte green.
  20. /// </summary>
  21. R8G8 = 2,
  22. /// <summary>
  23. /// 24-bit pixel format, 8 bits for red, green and blue.
  24. /// </summary>
  25. R8G8B8 = 3,
  26. /// <summary>
  27. /// 32-bit pixel format, 8 bits for red, green, blue and alpha.
  28. /// </summary>
  29. R8G8B8A8 = 8,
  30. /// <summary>
  31. /// DXT1/BC1 format containing opaque RGB or 1-bit alpha RGB. 4 bits per pixel.
  32. /// </summary>
  33. BC1 = 13,
  34. /// <summary>
  35. /// DXT3/BC2 format containing RGB with premultiplied alpha. 4 bits per pixel.
  36. /// </summary>
  37. BC1a = 14,
  38. /// <summary>
  39. /// DXT3/BC2 format containing RGB with explicit alpha. 8 bits per pixel.
  40. /// </summary>
  41. BC2 = 15,
  42. /// <summary>
  43. /// DXT5/BC2 format containing RGB with explicit alpha. 8 bits per pixel. Better alpha gradients than BC2.
  44. /// </summary>
  45. BC3 = 16,
  46. /// <summary>
  47. /// One channel compressed format. 4 bits per pixel.
  48. /// </summary>
  49. BC4 = 17,
  50. /// <summary>
  51. /// Two channel compressed format. 8 bits per pixel.
  52. /// </summary>
  53. BC5 = 18,
  54. /// <summary>
  55. /// Format storing RGB in half (16-bit) floating point format usable for HDR. 8 bits per pixel.
  56. /// </summary>
  57. BC6H = 19,
  58. /// <summary>
  59. /// Format storing RGB with optional alpha channel. Similar to BC1/BC2/BC3 formats but with higher quality and
  60. /// higher decompress overhead. 8 bits per pixel.
  61. /// </summary>
  62. BC7 = 20,
  63. /// <summary>
  64. /// 16-bit pixel format, 16 bits (float) for red.
  65. /// </summary>
  66. Float16_R = 21,
  67. /// <summary>
  68. /// 32-bit, 2-channel s10e5 floating point pixel format, 16-bit red, 16-bit green.
  69. /// </summary>
  70. Float16_RG = 22,
  71. /// <summary>
  72. /// 48-bit pixel format, 16 bits (float) for red, 16 bits (float) for green, 16 bits (float) for blue.
  73. /// </summary>
  74. Float16_RGB = 23,
  75. /// <summary>
  76. /// 64-bit pixel format, 16 bits (float) for red, 16 bits (float) for green, 16 bits (float) for blue, 16 bits
  77. /// (float) for alpha.
  78. /// </summary>
  79. Float16_RGBA = 24,
  80. /// <summary>
  81. /// 32-bit pixel format, 32 bits (float) for red.
  82. /// </summary>
  83. Float32_R = 25,
  84. /// <summary>
  85. /// 64-bit, 2-channel floating point pixel format, 32-bit red, 32-bit green.
  86. /// </summary>
  87. Float32_RG = 26,
  88. /// <summary>
  89. /// 96-bit pixel format, 32 bits (float) for red, 32 bits (float) for green, 32 bits (float) for blue.
  90. /// </summary>
  91. Float32_RGB = 27,
  92. /// <summary>
  93. /// 128-bit pixel format, 32 bits (float) for red, 32 bits (float) for green, 32 bits (float) for blue,
  94. /// 32 bits (float) for alpha.
  95. /// </summary>
  96. Float32_RGBA = 28,
  97. /// <summary>
  98. /// Depth stencil format, 32bit depth, 8bit stencil + 24 unused.
  99. /// </summary>
  100. D32_S8X24 = 29,
  101. /// <summary>
  102. /// Depth stencil fomrat, 24bit depth + 8bit stencil.
  103. /// </summary>
  104. D24S8 = 30,
  105. /// <summary>
  106. /// Depth format, 32bits.
  107. /// </summary>
  108. D32 = 31,
  109. /// <summary>
  110. /// Depth format, 16bits.
  111. /// </summary>
  112. D16 = 32
  113. };
  114. /// <summary>
  115. /// A buffer describing a volume (3D), image (2D) or line (1D) of pixels in memory. Pixels are stored as a succession
  116. /// of "depth" slices, each containing "height" rows of "width" pixels.
  117. /// </summary>
  118. public sealed class PixelData : ScriptObject
  119. {
  120. /// <summary>
  121. /// Width, height and depth of the pixels this object is capable of holding.
  122. /// </summary>
  123. public PixelVolume Extents
  124. {
  125. get
  126. {
  127. PixelVolume volume;
  128. Internal_GetExtents(mCachedPtr, out volume);
  129. return volume;
  130. }
  131. }
  132. /// <summary>
  133. /// Format of the pixels in the buffer.
  134. /// </summary>
  135. public PixelFormat Format
  136. {
  137. get
  138. {
  139. PixelFormat format;
  140. Internal_GetFormat(mCachedPtr, out format);
  141. return format;
  142. }
  143. }
  144. /// <summary>
  145. /// Returns number of bytes per a row of pixels.
  146. /// </summary>
  147. public int RawRowPitch
  148. {
  149. get
  150. {
  151. int rowPitch;
  152. Internal_GetRowPitch(mCachedPtr, out rowPitch);
  153. return rowPitch;
  154. }
  155. }
  156. /// <summary>
  157. /// Returns number of bytes per a 2D slice/plane of pixels.
  158. /// </summary>
  159. public int RawSlicePitch
  160. {
  161. get
  162. {
  163. int slicePitch;
  164. Internal_GetSlicePitch(mCachedPtr, out slicePitch);
  165. return slicePitch;
  166. }
  167. }
  168. /// <summary>
  169. /// Returns total number of bytes used by all the pixels.
  170. /// </summary>
  171. public int RawSize
  172. {
  173. get
  174. {
  175. int size;
  176. Internal_GetSize(mCachedPtr, out size);
  177. return size;
  178. }
  179. }
  180. /// <summary>
  181. /// Checks are the pixels in the buffer consecutive. If this is false then the buffer has padding and you should
  182. /// check <see cref="RawRowPitch"/> and <see cref="RawSlicePitch"/> when accessing it directly.
  183. /// </summary>
  184. public bool RawIsConsecutive
  185. {
  186. get
  187. {
  188. bool isConsecutive;
  189. Internal_GetIsConsecutive(mCachedPtr, out isConsecutive);
  190. return isConsecutive;
  191. }
  192. }
  193. /// <summary>
  194. /// Constructor for internal use by the runtime.
  195. /// </summary>
  196. private PixelData()
  197. { }
  198. /// <summary>
  199. /// Creates a new pixel data buffer capable of storing the specified amount of pixels.
  200. /// </summary>
  201. /// <param name="volume">Width, height and depth determining number of pixels to store.</param>
  202. /// <param name="format">Format of individual pixels.</param>
  203. public PixelData(PixelVolume volume, PixelFormat format = PixelFormat.R8G8B8A8)
  204. {
  205. Internal_CreateInstance(this, volume, format);
  206. }
  207. /// <summary>
  208. /// Creates a new 2D pixel data buffer capable of storing the specified amount of pixels.
  209. /// </summary>
  210. /// <param name="width">Number of pixels in each row.</param>
  211. /// <param name="height">Number of pixels in each column.</param>
  212. /// <param name="format">Format of individual pixels.</param>
  213. public PixelData(int width, int height, PixelFormat format = PixelFormat.R8G8B8A8)
  214. {
  215. Internal_CreateInstance(this, new PixelVolume(0, 0, width, height), format);
  216. }
  217. /// <summary>
  218. /// Creates a new 3D pixel data buffer capable of storing the specified amount of pixels.
  219. /// </summary>
  220. /// <param name="width">Number of pixels in each row.</param>
  221. /// <param name="height">Number of pixels in each column.</param>
  222. /// <param name="depth">Number of 2D slices.</param>
  223. /// <param name="format">Format of individual pixels.</param>
  224. public PixelData(int width, int height, int depth, PixelFormat format = PixelFormat.R8G8B8A8)
  225. {
  226. Internal_CreateInstance(this, new PixelVolume(0, 0, 0, width, height, depth), format);
  227. }
  228. /// <summary>
  229. /// Returns a pixel at the specified location in the buffer.
  230. /// </summary>
  231. /// <param name="x">X coordinate of the pixel.</param>
  232. /// <param name="y">Y coordinate of the pixel.</param>
  233. /// <param name="z">Z coordinate of the pixel.</param>
  234. /// <returns>Value of the pixel, or undefined value if coordinates are out of range.</returns>
  235. public Color GetPixel(int x, int y, int z = 0)
  236. {
  237. Color pixel;
  238. Internal_GetPixel(mCachedPtr, x, y, z, out pixel);
  239. return pixel;
  240. }
  241. /// <summary>
  242. /// Sets a pixel at the specified location in the buffer.
  243. /// </summary>
  244. /// <param name="color">Color of the pixel to set.</param>
  245. /// <param name="x">X coordinate of the pixel.</param>
  246. /// <param name="y">Y coordinate of the pixel.</param>
  247. /// <param name="z">Z coordinate of the pixel.</param>
  248. public void SetPixel(Color color, int x, int y, int z = 0)
  249. {
  250. Internal_SetPixel(mCachedPtr, x, y, z, color);
  251. }
  252. /// <summary>
  253. /// Returns values of all pixels.
  254. /// </summary>
  255. /// <returns>All pixels in the buffer ordered consecutively. Pixels are stored as a succession of "depth" slices,
  256. /// each containing "height" rows of "width" pixels.</returns>
  257. public Color[] GetPixels()
  258. {
  259. Color[] pixels;
  260. Internal_GetPixels(mCachedPtr, out pixels);
  261. return pixels;
  262. }
  263. /// <summary>
  264. /// Sets all pixels in the buffer. Caller must ensure that number of pixels match the extends of the buffer.
  265. /// </summary>
  266. /// <param name="pixels">All pixels to set ordered consecutively. Pixels are stored as a succession of "depth"
  267. /// slices, each containing "height" rows of "width" pixels.</param>
  268. public void SetPixels(Color[] pixels)
  269. {
  270. Internal_SetPixels(mCachedPtr, pixels);
  271. }
  272. /// <summary>
  273. /// Returns all pixels in the buffer as raw bytes.
  274. /// </summary>
  275. /// <returns>Raw pixel bytes. It is up to the caller to interpret the pixel format and account for potential
  276. /// row and slice pitch values.</returns>
  277. public byte[] GetRawPixels()
  278. {
  279. byte[] pixels;
  280. Internal_GetRawPixels(mCachedPtr, out pixels);
  281. return pixels;
  282. }
  283. /// <summary>
  284. /// Sets all pixels in the buffer as raw bytes.
  285. /// </summary>
  286. /// <param name="pixels">Raw pixel bytes. It is up to the caller to set the proper pixel format and account for
  287. /// potential row and slice pitch values.</param>
  288. public void SetRawPixels(byte[] pixels)
  289. {
  290. Internal_SetRawPixels(mCachedPtr, pixels);
  291. }
  292. [MethodImpl(MethodImplOptions.InternalCall)]
  293. private static extern void Internal_CreateInstance(PixelData instance, PixelVolume volume, PixelFormat format);
  294. [MethodImpl(MethodImplOptions.InternalCall)]
  295. private static extern void Internal_GetPixel(IntPtr thisPtr, int x, int y, int z, out Color value);
  296. [MethodImpl(MethodImplOptions.InternalCall)]
  297. private static extern void Internal_SetPixel(IntPtr thisPtr, int x, int y, int z, Color value);
  298. [MethodImpl(MethodImplOptions.InternalCall)]
  299. private static extern void Internal_GetPixels(IntPtr thisPtr, out Color[] value);
  300. [MethodImpl(MethodImplOptions.InternalCall)]
  301. private static extern void Internal_SetPixels(IntPtr thisPtr, Color[] value);
  302. [MethodImpl(MethodImplOptions.InternalCall)]
  303. private static extern void Internal_GetRawPixels(IntPtr thisPtr, out byte[] value);
  304. [MethodImpl(MethodImplOptions.InternalCall)]
  305. private static extern void Internal_SetRawPixels(IntPtr thisPtr, byte[] value);
  306. [MethodImpl(MethodImplOptions.InternalCall)]
  307. private static extern void Internal_GetExtents(IntPtr thisPtr, out PixelVolume value);
  308. [MethodImpl(MethodImplOptions.InternalCall)]
  309. private static extern void Internal_GetFormat(IntPtr thisPtr, out PixelFormat value);
  310. [MethodImpl(MethodImplOptions.InternalCall)]
  311. private static extern void Internal_GetRowPitch(IntPtr thisPtr, out int value);
  312. [MethodImpl(MethodImplOptions.InternalCall)]
  313. private static extern void Internal_GetSlicePitch(IntPtr thisPtr, out int value);
  314. [MethodImpl(MethodImplOptions.InternalCall)]
  315. private static extern void Internal_GetSize(IntPtr thisPtr, out int value);
  316. [MethodImpl(MethodImplOptions.InternalCall)]
  317. private static extern void Internal_GetIsConsecutive(IntPtr thisPtr, out bool value);
  318. }
  319. /// <summary>
  320. /// Represents a 3D region of pixels used for referencing pixel data.
  321. /// </summary>
  322. [StructLayout(LayoutKind.Sequential)]
  323. public struct PixelVolume // Note: Must match C++ class PixelVolume
  324. {
  325. private int left, top, right, bottom, front, back;
  326. /// <summary>
  327. /// Returns the left border of the pixel region (minimal X).
  328. /// </summary>
  329. public int Left { get { return left; } }
  330. /// <summary>
  331. /// Returns the right border of the pixel region (maximal X).
  332. /// </summary>
  333. public int Right { get { return right; } }
  334. /// <summary>
  335. /// Returns the top border of the pixel region (minimal Y).
  336. /// </summary>
  337. public int Top { get { return top; } }
  338. /// <summary>
  339. /// Returns the bottom border of the pixel region (maximal Y).
  340. /// </summary>
  341. public int Bottom { get { return bottom; } }
  342. /// <summary>
  343. /// Returns the front border of the pixel region (minimal Z).
  344. /// </summary>
  345. public int Front { get { return front; } }
  346. /// <summary>
  347. /// Returns the back border of the pixel region (maximal Z).
  348. /// </summary>
  349. public int Back { get { return back; } }
  350. /// <summary>
  351. /// Returns the number of pixels between right and left borders of the volume.
  352. /// </summary>
  353. public int Width { get { return right - left; } }
  354. /// <summary>
  355. /// Returns the number of pixels between bottom and top borders of the volume.
  356. /// </summary>
  357. public int Height { get { return bottom - top; } }
  358. /// <summary>
  359. /// Returns the number of pixels between back and front borders of the volume.
  360. /// </summary>
  361. public int Depth { get { return back - front; } }
  362. /// <summary>
  363. /// Creates a new 2D region.
  364. /// </summary>
  365. /// <param name="left">Left border of the region.</param>
  366. /// <param name="top">Top border of the region.</param>
  367. /// <param name="right">Right border of the region. Must be larger than left border.</param>
  368. /// <param name="bottom">Bottom border of the region. Must be larger than top border.</param>
  369. public PixelVolume(int left, int top, int right, int bottom)
  370. {
  371. this.left = left;
  372. this.right = right;
  373. this.top = top;
  374. this.bottom = bottom;
  375. this.front = 0;
  376. this.back = 1;
  377. }
  378. /// <summary>
  379. /// Creates a new 3D region.
  380. /// </summary>
  381. /// <param name="left">Left border of the region.</param>
  382. /// <param name="top">Top border of the region.</param>
  383. /// <param name="front">Front border of the region.</param>
  384. /// <param name="right">Right border of the region. Must be larger than left border.</param>
  385. /// <param name="bottom">Bottom border of the region. Must be larger than top border.</param>
  386. /// <param name="back">Back border of the region. Must be larger than back border.</param>
  387. public PixelVolume(int left, int top, int front, int right, int bottom, int back)
  388. {
  389. this.left = left;
  390. this.right = right;
  391. this.top = top;
  392. this.bottom = bottom;
  393. this.front = front;
  394. this.back = back;
  395. }
  396. };
  397. }