SpriteBatch.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Numerics;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace Veldrid.Common
  9. {
  10. /// <summary>
  11. /// A class for drawing sprites in one or more optimized batches.
  12. /// </summary>
  13. /// <typeparam name="TTexture">The texture type to renderer.</typeparam>
  14. public abstract class SpriteBatch<TTexture> : ISpriteBatch<TTexture> where TTexture : notnull, ITexture2D
  15. {
  16. /// <summary>
  17. /// The batcher with all entities to renderer.
  18. /// </summary>
  19. protected readonly Batcher<TTexture> _batcher;
  20. private bool _beginCalled;
  21. /// <summary>
  22. /// Creates a new <see cref="SpriteBatch{TTexture}"/>.
  23. /// </summary>
  24. public SpriteBatch()
  25. {
  26. _batcher = new Batcher<TTexture>();
  27. _beginCalled = false;
  28. IsDisposed = false;
  29. ResetScissor();
  30. }
  31. /// <summary>
  32. /// Deconstructor of <see cref="SpriteBatch{TTexture}"/>.
  33. /// </summary>
  34. ~SpriteBatch()
  35. {
  36. CoreDispose(false);
  37. }
  38. /// <summary>
  39. /// The view matrix to use to renderer.
  40. /// </summary>
  41. public Matrix4x4 ViewMatrix { get; set; }
  42. /// <inheritdoc/>
  43. public bool IsDisposed { get; protected set; }
  44. /// <inheritdoc/>
  45. public RectangleF Scissor { get; set; }
  46. /// <summary>
  47. /// Begins the sprite branch.
  48. /// </summary>
  49. /// <exception cref="InvalidOperationException">Thrown if <see cref="Begin"/> is called next time without previous <see cref="End"/>.</exception>
  50. public void Begin()
  51. {
  52. if (_beginCalled)
  53. throw new InvalidOperationException("Begin cannot be called again until End has been successfully called.");
  54. ViewMatrix = Matrix4x4.Identity;
  55. _beginCalled = true;
  56. _batcher.Clear();
  57. }
  58. /// <summary>
  59. /// Flushes all batched text and sprites to the screen.
  60. /// </summary>
  61. /// <exception cref="InvalidOperationException">This command should be called after <see cref="Begin"/> and drawing commands.</exception>
  62. public void End()
  63. {
  64. if (!_beginCalled)
  65. throw new InvalidOperationException("Begin must be called before calling End.");
  66. _beginCalled = false;
  67. }
  68. /// <inheritdoc/>
  69. public void Draw(ITexture2D texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth) =>
  70. Draw(SpriteBatch<TTexture>.Cast(texture), destinationRectangle, sourceRectangle, color, rotation, origin, options, layerDepth);
  71. /// <inheritdoc/>
  72. public void Draw(ITexture2D texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth) =>
  73. Draw(SpriteBatch<TTexture>.Cast(texture), position, sourceRectangle, color, rotation, origin, scale, options, layerDepth);
  74. /// <inheritdoc/>
  75. public void Draw(TTexture texture, RectangleF destinationRectangle, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, SpriteOptions options, float layerDepth)
  76. {
  77. CheckValid(texture);
  78. ref var item = ref _batcher.Add(texture);
  79. var size =new Vector2(texture.Size.Width,texture.Size.Height);
  80. item = new BatchItem(size, destinationRectangle, sourceRectangle, color, rotation, origin, layerDepth, Transform(Scissor, ViewMatrix), options);
  81. }
  82. /// <inheritdoc/>
  83. public void Draw(TTexture texture, PointF position, RectangleF sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteOptions options, float layerDepth)
  84. {
  85. CheckValid(texture);
  86. ref var item = ref _batcher.Add(texture);
  87. var size = new Vector2(texture.Size.Width, texture.Size.Height);
  88. item = new BatchItem(size, position, sourceRectangle, color, rotation, origin, scale, layerDepth, Transform(Scissor, ViewMatrix), options);
  89. }
  90. /// <inheritdoc/>
  91. public void Dispose()
  92. {
  93. CoreDispose(true);
  94. GC.SuppressFinalize(this);
  95. }
  96. private void CoreDispose(bool disposing)
  97. {
  98. if (IsDisposed)
  99. return;
  100. IsDisposed = true;
  101. Dispose(disposing);
  102. }
  103. /// <summary>
  104. /// Disposes resources.
  105. /// </summary>
  106. /// <param name="disposing">If called by <see cref="Dispose()"/></param>
  107. protected abstract void Dispose(bool disposing);
  108. private void CheckValid(ITexture2D texture)
  109. {
  110. if (texture == null)
  111. throw new ArgumentNullException(nameof(texture));
  112. if (!_beginCalled)
  113. throw new InvalidOperationException("Draw was called, but Begin has not yet been called. Begin must be called successfully before you can call Draw.");
  114. }
  115. private static TTexture Cast(ITexture2D texture)
  116. {
  117. if (texture is TTexture tt)
  118. return tt;
  119. throw new InvalidCastException($"The {texture} is not supported by this implementation.");
  120. }
  121. /// <inheritdoc/>
  122. public void ResetScissor()
  123. {
  124. const float v = 1 << 23;
  125. const float s = -(1 << 22);
  126. Scissor = new RectangleF(s, s, v, v);
  127. }
  128. /// <inheritdoc/>
  129. public void IntersectScissor(RectangleF clip)
  130. {
  131. var scissor = Scissor;
  132. scissor.Intersect(clip);
  133. Scissor = scissor;
  134. }
  135. private static RectangleF Transform(RectangleF rect, Matrix4x4 matrix)
  136. {
  137. var pos = Vector4.Transform(new Vector4(rect.X, rect.Y, 0, 1), matrix);
  138. var size = Vector4.Transform(new Vector4(rect.X + rect.Width, rect.Y + rect.Height, 0, 1), matrix);
  139. return new RectangleF(pos.X, pos.Y, size.X - pos.X, size.Y - pos.Y);
  140. }
  141. #region ISpriteBatch
  142. /// <inheritdoc/>
  143. public void Draw(ITexture2D texture,
  144. RectangleF destinationRectangle,
  145. RectangleF sourceRectangle,
  146. Color color,
  147. float rotation,
  148. Vector2 origin,
  149. float layerDepth)
  150. {
  151. Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth);
  152. }
  153. /// <inheritdoc/>
  154. public void Draw(ITexture2D texture,
  155. PointF position,
  156. RectangleF sourceRectangle,
  157. Color color,
  158. float rotation,
  159. Vector2 origin,
  160. Vector2 scale,
  161. float layerDepth)
  162. {
  163. Draw(texture, position, sourceRectangle, color, rotation, origin, scale, SpriteOptions.None, layerDepth);
  164. }
  165. /// <inheritdoc/>
  166. public void Draw(ITexture2D texture,
  167. RectangleF destinationRectangle,
  168. RectangleF? sourceRectangle,
  169. Color color,
  170. float rotation,
  171. Vector2 origin,
  172. SpriteOptions options,
  173. float layerDepth)
  174. {
  175. var srcRect = sourceRectangle ?? new RectangleF(0, 0, texture.Size.Width, texture.Size.Height);
  176. Draw(texture, destinationRectangle, srcRect, color, rotation, origin, options, layerDepth);
  177. }
  178. /// <inheritdoc/>
  179. public void Draw(ITexture2D texture,
  180. RectangleF destinationRectangle,
  181. RectangleF? sourceRectangle,
  182. Color color,
  183. float rotation,
  184. Vector2 origin,
  185. float layerDepth)
  186. {
  187. Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth);
  188. }
  189. /// <inheritdoc/>
  190. public void Draw(ITexture2D texture,
  191. PointF position,
  192. RectangleF? sourceRectangle,
  193. Color color,
  194. float rotation,
  195. Vector2 origin,
  196. Vector2 scale,
  197. SpriteOptions options,
  198. float layerDepth)
  199. {
  200. Draw(texture: texture,
  201. position: position,
  202. sourceRectangle: sourceRectangle ?? new RectangleF()
  203. {
  204. X = 0,
  205. Y = 0,
  206. Width = texture.Size.Width,
  207. Height = texture.Size.Height,
  208. },
  209. color: color,
  210. rotation: rotation,
  211. origin: origin,
  212. scale: scale,
  213. options: options,
  214. layerDepth: layerDepth);
  215. }
  216. /// <inheritdoc/>
  217. public void Draw(ITexture2D texture,
  218. PointF position,
  219. RectangleF? sourceRectangle,
  220. Color color,
  221. float rotation,
  222. Vector2 origin,
  223. Vector2 scale,
  224. float layerDepth)
  225. {
  226. Draw(texture: texture,
  227. position: position,
  228. sourceRectangle: sourceRectangle,
  229. color: color,
  230. rotation: rotation,
  231. origin: origin,
  232. scale: scale,
  233. options: SpriteOptions.None,
  234. layerDepth: layerDepth);
  235. }
  236. /// <inheritdoc/>
  237. public void Draw(ITexture2D texture,
  238. PointF position,
  239. RectangleF? sourceRectangle,
  240. Color color,
  241. float rotation,
  242. Vector2 origin,
  243. float scale,
  244. SpriteOptions options,
  245. float layerDepth)
  246. {
  247. Draw(texture: texture,
  248. position: position,
  249. sourceRectangle: sourceRectangle,
  250. color: color,
  251. rotation: rotation,
  252. origin: origin,
  253. scale: new Vector2(scale),
  254. options: options,
  255. layerDepth: layerDepth);
  256. }
  257. /// <inheritdoc/>
  258. public void Draw(ITexture2D texture,
  259. PointF position,
  260. RectangleF? sourceRectangle,
  261. Color color,
  262. float rotation,
  263. Vector2 origin,
  264. float scale,
  265. float layerDepth)
  266. {
  267. Draw(texture: texture,
  268. position: position,
  269. sourceRectangle: sourceRectangle,
  270. color: color,
  271. rotation: rotation,
  272. origin: origin,
  273. scale: scale,
  274. options: SpriteOptions.None,
  275. layerDepth: layerDepth);
  276. }
  277. /// <inheritdoc/>
  278. public void Draw(ITexture2D texture,
  279. PointF position,
  280. RectangleF? sourceRectangle,
  281. Color color,
  282. SpriteOptions options,
  283. float layerDepth)
  284. {
  285. Draw(texture: texture,
  286. position: position,
  287. sourceRectangle: sourceRectangle,
  288. color: color,
  289. rotation: 0f,
  290. origin: default,
  291. scale: 0f,
  292. options: options,
  293. layerDepth: layerDepth);
  294. }
  295. /// <inheritdoc/>
  296. public void Draw(ITexture2D texture,
  297. PointF position,
  298. RectangleF? sourceRectangle,
  299. Color color,
  300. float layerDepth)
  301. {
  302. Draw(texture: texture,
  303. position: position,
  304. sourceRectangle: sourceRectangle,
  305. color: color,
  306. options: SpriteOptions.None,
  307. layerDepth: layerDepth);
  308. }
  309. /// <inheritdoc/>
  310. public void Draw(ITexture2D texture,
  311. RectangleF destinationRectangle,
  312. RectangleF? sourceRectangle,
  313. Color color,
  314. SpriteOptions options,
  315. float layerDepth)
  316. {
  317. Draw(texture: texture,
  318. destinationRectangle: destinationRectangle,
  319. sourceRectangle: sourceRectangle,
  320. color: color,
  321. rotation: 0,
  322. origin: default,
  323. options: options,
  324. layerDepth: layerDepth);
  325. }
  326. /// <inheritdoc/>
  327. public void Draw(ITexture2D texture,RectangleF destinationRectangle,
  328. RectangleF? sourceRectangle,
  329. Color color,
  330. float layerDepth)
  331. {
  332. Draw(texture: texture,
  333. destinationRectangle:destinationRectangle,
  334. sourceRectangle: sourceRectangle,
  335. color: color,
  336. options: SpriteOptions.None,
  337. layerDepth: layerDepth);
  338. }
  339. /// <inheritdoc/>
  340. public void Draw(ITexture2D texture,
  341. PointF position,
  342. Color color,
  343. SpriteOptions options,
  344. float layerDepth)
  345. {
  346. Draw(texture: texture,
  347. position: position,
  348. sourceRectangle: new RectangleF(default, texture.Size),
  349. color: color,
  350. rotation: 0,
  351. origin: default,
  352. scale: default,
  353. options: options,
  354. layerDepth: layerDepth);
  355. }
  356. /// <inheritdoc/>
  357. public void Draw(ITexture2D texture,
  358. PointF position,
  359. Color color,
  360. float layerDepth)
  361. {
  362. Draw(texture: texture,
  363. position: position,
  364. color: color,
  365. options: SpriteOptions.None,
  366. layerDepth: layerDepth);
  367. }
  368. /// <inheritdoc/>
  369. public void Draw(ITexture2D texture,
  370. RectangleF destinationRectangle,
  371. Color color,
  372. SpriteOptions options,
  373. float layerDepth)
  374. {
  375. Draw(texture: texture,
  376. destinationRectangle: destinationRectangle,
  377. sourceRectangle: new RectangleF(default, texture.Size),
  378. color: color,
  379. rotation: 0,
  380. origin: default,
  381. options: options,
  382. layerDepth: layerDepth);
  383. }
  384. /// <inheritdoc/>
  385. public void Draw(ITexture2D texture,
  386. RectangleF destinationRectangle,
  387. Color color,
  388. float layerDepth)
  389. {
  390. Draw(texture: texture,
  391. destinationRectangle: destinationRectangle,
  392. color: color,
  393. options: SpriteOptions.None,
  394. layerDepth: layerDepth);
  395. }
  396. #endregion
  397. #region ISpriteBatch<TTexture>
  398. /// <inheritdoc/>
  399. public void Draw(TTexture texture,
  400. RectangleF destinationRectangle,
  401. RectangleF sourceRectangle,
  402. Color color,
  403. float rotation,
  404. Vector2 origin,
  405. float layerDepth)
  406. {
  407. Draw(texture: texture,
  408. destinationRectangle: destinationRectangle,
  409. sourceRectangle: sourceRectangle,
  410. color: color,
  411. rotation: rotation,
  412. origin: origin,
  413. options: SpriteOptions.None,
  414. layerDepth: layerDepth);
  415. }
  416. /// <inheritdoc/>
  417. public void Draw(TTexture texture,
  418. PointF position,
  419. RectangleF sourceRectangle,
  420. Color color,
  421. float rotation,
  422. Vector2 origin,
  423. Vector2 scale,
  424. float layerDepth)
  425. {
  426. Draw(texture: texture,
  427. position: position,
  428. sourceRectangle: sourceRectangle,
  429. color: color,
  430. rotation: rotation,
  431. origin: origin,
  432. scale: scale,
  433. options: SpriteOptions.None,
  434. layerDepth: layerDepth);
  435. }
  436. /// <inheritdoc/>
  437. public void Draw(TTexture texture,
  438. RectangleF destinationRectangle,
  439. RectangleF? sourceRectangle,
  440. Color color,
  441. float rotation,
  442. Vector2 origin,
  443. SpriteOptions options,
  444. float layerDepth)
  445. {
  446. //var srcRect = sourceRectangleF ?? new(0, 0, texture.Size.Width, texture.Size.Height);
  447. Draw(texture: texture,
  448. destinationRectangle: destinationRectangle,
  449. sourceRectangle: sourceRectangle ?? new RectangleF()
  450. {
  451. X = 0,
  452. Y = 0,
  453. Width = texture.Size.Width,
  454. Height = texture.Size.Height,
  455. },
  456. color: color,
  457. rotation: rotation,
  458. origin: origin,
  459. options: options,
  460. layerDepth: layerDepth);
  461. }
  462. /// <inheritdoc/>
  463. public void Draw(TTexture texture,
  464. RectangleF destinationRectangle,
  465. RectangleF? sourceRectangle,
  466. Color color,
  467. float rotation,
  468. Vector2 origin,
  469. float layerDepth)
  470. {
  471. Draw(texture, destinationRectangle, sourceRectangle, color, rotation, origin, SpriteOptions.None, layerDepth);
  472. }
  473. /// <inheritdoc/>
  474. public void Draw(TTexture texture,
  475. PointF position,
  476. RectangleF? sourceRectangle,
  477. Color color,
  478. float rotation,
  479. Vector2 origin,
  480. Vector2 scale,
  481. SpriteOptions options,
  482. float layerDepth)
  483. {
  484. //var srcRect = sourceRectangleF ?? new(0, 0, texture.Size.Width, texture.Size.Height);
  485. Draw(texture: texture,
  486. position: position,
  487. sourceRectangle: sourceRectangle ?? new RectangleF()
  488. {
  489. X = 0,
  490. Y = 0,
  491. Width = texture.Size.Width,
  492. Height = texture.Size.Height,
  493. },
  494. color: color,
  495. rotation: rotation,
  496. origin: origin,
  497. scale: scale,
  498. options: options,
  499. layerDepth: layerDepth);
  500. }
  501. /// <inheritdoc/>
  502. public void Draw(TTexture texture,
  503. PointF position,
  504. RectangleF? sourceRectangle,
  505. Color color,
  506. float rotation,
  507. Vector2 origin,
  508. Vector2 scale,
  509. float layerDepth)
  510. {
  511. Draw(texture: texture,
  512. position: position,
  513. sourceRectangle: sourceRectangle,
  514. color: color,
  515. rotation: rotation,
  516. origin: origin,
  517. scale: scale,
  518. options: SpriteOptions.None,
  519. layerDepth: layerDepth);
  520. }
  521. /// <inheritdoc/>
  522. public void Draw(TTexture texture,
  523. PointF position,
  524. RectangleF? sourceRectangle,
  525. Color color,
  526. float rotation,
  527. Vector2 origin,
  528. float scale,
  529. SpriteOptions options,
  530. float layerDepth)
  531. {
  532. Draw(texture, position, sourceRectangle, color, rotation, origin, new Vector2(scale), options, layerDepth);
  533. }
  534. /// <inheritdoc/>
  535. public void Draw(TTexture texture,
  536. PointF position,
  537. RectangleF? sourceRectangle,
  538. Color color,
  539. float rotation,
  540. Vector2 origin,
  541. float scale,
  542. float layerDepth)
  543. {
  544. Draw(texture, position, sourceRectangle, color, rotation, origin, scale, SpriteOptions.None, layerDepth);
  545. }
  546. /// <inheritdoc/>
  547. public void Draw(TTexture texture,
  548. PointF position,
  549. RectangleF? sourceRectangle,
  550. Color color,
  551. SpriteOptions options,
  552. float layerDepth)
  553. {
  554. Draw(texture, position, sourceRectangle, color, 0f, default, 0f, options, layerDepth);
  555. }
  556. /// <inheritdoc/>
  557. public void Draw(TTexture texture,
  558. PointF position,
  559. RectangleF? sourceRectangle,
  560. Color color,
  561. float layerDepth)
  562. {
  563. Draw(texture, position, sourceRectangle, color, SpriteOptions.None, layerDepth);
  564. }
  565. /// <inheritdoc/>
  566. public void Draw(TTexture texture,
  567. RectangleF destinationRectangle,
  568. RectangleF? sourceRectangle,
  569. Color color,
  570. SpriteOptions options,
  571. float layerDepth)
  572. {
  573. Draw(texture, destinationRectangle, sourceRectangle, color, 0, default, options, layerDepth);
  574. }
  575. /// <inheritdoc/>
  576. public void Draw(TTexture texture,
  577. RectangleF destinationRectangle,
  578. RectangleF? sourceRectangle,
  579. Color color,
  580. float layerDepth)
  581. {
  582. Draw(texture, destinationRectangle, sourceRectangle, color, SpriteOptions.None, layerDepth);
  583. }
  584. /// <inheritdoc/>
  585. public void Draw(TTexture texture,
  586. PointF position,
  587. Color color,
  588. SpriteOptions options,
  589. float layerDepth)
  590. {
  591. Draw(texture, position, new System.Drawing.Rectangle(default,texture.Size), color, 0, default, default, options, layerDepth);
  592. }
  593. /// <inheritdoc/>
  594. public void Draw(TTexture texture,
  595. PointF position,
  596. Color color,
  597. float layerDepth)
  598. {
  599. Draw(texture, position, new System.Drawing.Rectangle(default,texture.Size), color, 0, default, default, SpriteOptions.None, layerDepth);
  600. }
  601. /// <inheritdoc/>
  602. public void Draw(TTexture texture,
  603. RectangleF destinationRectangle,
  604. Color color,
  605. SpriteOptions options,
  606. float layerDepth)
  607. {
  608. Draw(texture, destinationRectangle, new System.Drawing.Rectangle(default, texture.Size), color, 0, default, options, layerDepth);
  609. }
  610. /// <inheritdoc/>
  611. public void Draw(TTexture texture,
  612. RectangleF destinationRectangle,
  613. Color color,
  614. float layerDepth)
  615. {
  616. Draw(texture, destinationRectangle, color, SpriteOptions.None, layerDepth);
  617. }
  618. #endregion
  619. }
  620. }