StitchSurfaceBoxBaseRenderer.cs 14 KB

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