SurfaceBoxBaseRenderer.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. using System.Diagnostics;
  2. using System.Drawing;
  3. namespace PaintDotNet
  4. {
  5. public sealed class SurfaceBoxBaseRenderer : SurfaceBoxRenderer
  6. {
  7. private Surface source;
  8. private RenderDelegate renderDelegate;
  9. public Surface Source
  10. {
  11. get
  12. {
  13. return this.source;
  14. }
  15. set
  16. {
  17. this.source = value;
  18. Flush();
  19. }
  20. }
  21. private void Flush()
  22. {
  23. this.renderDelegate = null;
  24. }
  25. protected override void OnVisibleChanged()
  26. {
  27. Invalidate();
  28. }
  29. private void ChooseRenderDelegate()
  30. {
  31. if (SourceSize.Width > DestinationSize.Width)
  32. {
  33. // zoom out
  34. this.renderDelegate = new RenderDelegate(RenderZoomOutRotatedGridMultisampling);
  35. }
  36. else if (SourceSize == DestinationSize)
  37. {
  38. // zoom 100%
  39. this.renderDelegate = new RenderDelegate(RenderOneToOne);
  40. }
  41. else if (SourceSize.Width < DestinationSize.Width)
  42. {
  43. // zoom in
  44. this.renderDelegate = new RenderDelegate(RenderZoomInNearestNeighbor);
  45. }
  46. }
  47. public override void OnDestinationSizeChanged()
  48. {
  49. ChooseRenderDelegate();
  50. this.OwnerList.InvalidateLookups();
  51. base.OnDestinationSizeChanged();
  52. }
  53. public override void OnSourceSizeChanged()
  54. {
  55. ChooseRenderDelegate();
  56. this.OwnerList.InvalidateLookups();
  57. base.OnSourceSizeChanged();
  58. }
  59. public static void RenderOneToOne(Surface dst, Surface source, Point offset)
  60. {
  61. unsafe
  62. {
  63. if (source == null) return;
  64. Rectangle srcRect = new Rectangle(offset, dst.Size);
  65. srcRect.Intersect(source.Bounds);
  66. for (int dstRow = 0; dstRow < srcRect.Height; ++dstRow)
  67. {
  68. ColorBgra* dstRowPtr = dst.GetRowAddressUnchecked(dstRow);
  69. ColorBgra* srcRowPtr = source.GetPointAddressUnchecked(offset.X, dstRow + offset.Y);
  70. int dstCol = offset.X;
  71. int dstColEnd = offset.X + srcRect.Width;
  72. int checkerY = dstRow + offset.Y;
  73. while (dstCol < dstColEnd)
  74. {
  75. int b = srcRowPtr->B;
  76. int g = srcRowPtr->G;
  77. int r = srcRowPtr->R;
  78. int a = srcRowPtr->A;
  79. // Blend it over the checkerboard background
  80. int v = (((dstCol ^ checkerY) & 8) << 3) + 191;
  81. a = a + (a >> 7);
  82. int vmia = v * (256 - a);
  83. r = ((r * a) + vmia) >> 8;
  84. g = ((g * a) + vmia) >> 8;
  85. b = ((b * a) + vmia) >> 8;
  86. dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)(a > 0 ? 255 : 0) << 24);
  87. //dstRowPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);
  88. ++dstRowPtr;
  89. ++srcRowPtr;
  90. ++dstCol;
  91. }
  92. }
  93. }
  94. }
  95. private void RenderOneToOne(Surface dst, Point offset)
  96. {
  97. try
  98. {
  99. RenderOneToOne(dst, this.source, offset);
  100. }
  101. catch {}
  102. }
  103. private void RenderZoomInNearestNeighbor(Surface dst, Point offset)
  104. {
  105. unsafe
  106. {
  107. if (this.source == null) return;
  108. int[] d2SLookupY = OwnerList.Dst2SrcLookupY;
  109. int[] d2SLookupX = OwnerList.Dst2SrcLookupX;
  110. for (int dstRow = 0; dstRow < dst.Height; ++dstRow)
  111. {
  112. int nnY = dstRow + offset.Y;
  113. int srcY = d2SLookupY[nnY];
  114. ColorBgra* dstPtr = dst.GetRowAddressUnchecked(dstRow);
  115. ColorBgra* srcRow = this.source.GetRowAddressUnchecked(srcY);
  116. for (int dstCol = 0; dstCol < dst.Width; ++dstCol)
  117. {
  118. int nnX = dstCol + offset.X;
  119. int srcX = d2SLookupX[nnX];
  120. ColorBgra src = *(srcRow + srcX);
  121. int b = src.B;
  122. int g = src.G;
  123. int r = src.R;
  124. int a = src.A;
  125. // Blend it over the checkerboard background
  126. int v = (((dstCol + offset.X) ^ (dstRow + offset.Y)) & 8) * 8 + 191;
  127. a = a + (a >> 7);
  128. int vmia = v * (256 - a);
  129. r = ((r * a) + vmia) >> 8;
  130. g = ((g * a) + vmia) >> 8;
  131. b = ((b * a) + vmia) >> 8;
  132. dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)(a > 0 ? 255 : 0)/*255*/ << 24);
  133. //dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)255 << 24);
  134. ++dstPtr;
  135. }
  136. }
  137. }
  138. }
  139. public static void RenderZoomOutRotatedGridMultisampling(Surface dst, Surface source, Point offset, Size destinationSize)
  140. {
  141. unsafe
  142. {
  143. if (source == null) return;
  144. const int fpShift = 12;
  145. const int fpFactor = (1 << fpShift);
  146. Size sourceSize = source.Size;
  147. long fDstLeftLong = ((long)offset.X * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
  148. long fDstTopLong = ((long)offset.Y * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
  149. long fDstRightLong = ((long)(offset.X + dst.Width) * fpFactor * (long)sourceSize.Width) / (long)destinationSize.Width;
  150. long fDstBottomLong = ((long)(offset.Y + dst.Height) * fpFactor * (long)sourceSize.Height) / (long)destinationSize.Height;
  151. int fDstLeft = (int)fDstLeftLong;
  152. int fDstTop = (int)fDstTopLong;
  153. int fDstRight = (int)fDstRightLong;
  154. int fDstBottom = (int)fDstBottomLong;
  155. int dx = (fDstRight - fDstLeft) / dst.Width;
  156. int dy = (fDstBottom - fDstTop) / dst.Height;
  157. for (int dstRow = 0, fDstY = fDstTop;
  158. dstRow < dst.Height && fDstY < fDstBottom;
  159. ++dstRow, fDstY += dy)
  160. {
  161. int srcY1 = fDstY >> fpShift; // y
  162. int srcY2 = (fDstY + (dy >> 2)) >> fpShift; // y + 0.25
  163. int srcY3 = (fDstY + (dy >> 1)) >> fpShift; // y + 0.50
  164. int srcY4 = (fDstY + (dy >> 1) + (dy >> 2)) >> fpShift; // y + 0.75
  165. #if DEBUG
  166. Debug.Assert(source.IsRowVisible(srcY1));
  167. Debug.Assert(source.IsRowVisible(srcY2));
  168. Debug.Assert(source.IsRowVisible(srcY3));
  169. Debug.Assert(source.IsRowVisible(srcY4));
  170. Debug.Assert(dst.IsRowVisible(dstRow));
  171. #endif
  172. ColorBgra* src1 = source.GetRowAddressUnchecked(srcY1);
  173. ColorBgra* src2 = source.GetRowAddressUnchecked(srcY2);
  174. ColorBgra* src3 = source.GetRowAddressUnchecked(srcY3);
  175. ColorBgra* src4 = source.GetRowAddressUnchecked(srcY4);
  176. ColorBgra* dstPtr = dst.GetRowAddressUnchecked(dstRow);
  177. int checkerY = dstRow + offset.Y;
  178. int checkerX = offset.X;
  179. int maxCheckerX = checkerX + dst.Width;
  180. for (int fDstX = fDstLeft;
  181. checkerX < maxCheckerX && fDstX < fDstRight;
  182. ++checkerX, fDstX += dx)
  183. {
  184. int srcX1 = (fDstX + (dx >> 2)) >> fpShift; // x + 0.25
  185. int srcX2 = (fDstX + (dx >> 1) + (dx >> 2)) >> fpShift; // x + 0.75
  186. int srcX3 = fDstX >> fpShift; // x
  187. int srcX4 = (fDstX + (dx >> 1)) >> fpShift; // x + 0.50
  188. #if DEBUG
  189. Debug.Assert(source.IsColumnVisible(srcX1));
  190. Debug.Assert(source.IsColumnVisible(srcX2));
  191. Debug.Assert(source.IsColumnVisible(srcX3));
  192. Debug.Assert(source.IsColumnVisible(srcX4));
  193. #endif
  194. ColorBgra* p1 = src1 + srcX1;
  195. ColorBgra* p2 = src2 + srcX2;
  196. ColorBgra* p3 = src3 + srcX3;
  197. ColorBgra* p4 = src4 + srcX4;
  198. int r = (2 + p1->R + p2->R + p3->R + p4->R) >> 2;
  199. int g = (2 + p1->G + p2->G + p3->G + p4->G) >> 2;
  200. int b = (2 + p1->B + p2->B + p3->B + p4->B) >> 2;
  201. int a = (2 + p1->A + p2->A + p3->A + p4->A) >> 2;
  202. //int apopacity = a;
  203. //// Blend it over the checkerboard background
  204. //int v = ((checkerX ^ checkerY) & 8) * 8 + 191;
  205. //a = a + (a >> 7);
  206. //int vmia = v * (256 - a);
  207. //r = ((r * a) + vmia) >> 8;
  208. //g = ((g * a) + vmia) >> 8;
  209. //b = ((b * a) + vmia) >> 8;
  210. dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + ((uint)(a/* > 0 ? 255 : 0*/) << 24);
  211. //dstPtr->Bgra = (uint)b + ((uint)g << 8) + ((uint)r << 16) + 0xff000000;
  212. ++dstPtr;
  213. }
  214. }
  215. }
  216. }
  217. private void RenderZoomOutRotatedGridMultisampling(Surface dst, Point offset)
  218. {
  219. RenderZoomOutRotatedGridMultisampling(dst, this.source, offset, this.DestinationSize);
  220. }
  221. public override void Render(Surface dst, Point offset)
  222. {
  223. if (this.renderDelegate == null)
  224. {
  225. ChooseRenderDelegate();
  226. }
  227. this.renderDelegate(dst, offset);
  228. }
  229. public SurfaceBoxBaseRenderer(SurfaceBoxRendererList ownerList, Surface source)
  230. : base(ownerList)
  231. {
  232. this.source = source;
  233. ChooseRenderDelegate();
  234. }
  235. }
  236. }