public void Render(IStateOwner pOwner, SKCanvas pRenderTarget, FieldLineActionGameState Source, GameStateSkiaDrawParameters Element) { var Bounds = Element.Bounds; float BlockWidth = Bounds.Width / Source.PlayField.ColCount; float BlockHeight = Bounds.Height / Source.PlayField.VisibleRows; //remember, we don't draw the top two rows- we start the drawing at row index 2, skipping 0 and 1 when drawing. bool FoundAnimated = false; if (Source._BaseState != null) { var newElement = new GameStateSkiaDrawParameters(Element.Bounds); newElement.TagData = new GamePlayGameStateDataTagInfo() { SkipParticlePaint = true }; RenderingProvider.Static.DrawElement(pOwner, pRenderTarget, Source._BaseState, newElement); } if (Source.ClearRowInfo != null) { foreach (var iterate in Source.ClearRowInfo) { int currentRow = iterate.Key; NominoBlock[] RowData = iterate.Value; for (int drawCol = 0; drawCol < RowData.Length; drawCol++) { float YPos = (currentRow - Source.PlayField.HIDDENROWS) * BlockHeight; float XPos = drawCol * BlockWidth; var TetBlock = RowData[drawCol]; if (TetBlock != null) { SKRect BlockBounds = new SKRect(XPos, YPos, XPos + BlockWidth, YPos + BlockHeight); TetrisBlockDrawSkiaParameters tbd = new TetrisBlockDrawSkiaParameters(pRenderTarget, BlockBounds, null, pOwner.Settings); RenderingProvider.Static.DrawElement(pOwner, tbd.g, TetBlock, tbd); } else { ; } } } } //we told the main state not to paint particles, so we should paint them now. RenderingProvider.Static.DrawElement(pOwner, pRenderTarget, Source.GetComposite().Particles, Element); RenderingProvider.Static.DrawElement(pOwner, pRenderTarget, Source.GetComposite().TopParticles, Element); if (Source is FieldLineActionGameState linestate) { if (linestate.FlashState) { pRenderTarget.DrawRect(Element.Bounds, FlashBrush); } } }
public bool DrawFieldContents(IStateOwner pState, TetrisField Source, TetrisFieldDrawSkiaParameters Element, SKCanvas g, SKRect Bounds, bool animated) { float BlockWidth = Bounds.Width / Element.COLCOUNT; float BlockHeight = Bounds.Height / (Element.VISIBLEROWS); //remember, we don't draw the top two rows- we start the drawing at row index 2, skipping 0 and 1 when drawing. bool FoundAnimated = false; for (int drawRow = Element.HIDDENROWS; drawRow < Element.ROWCOUNT; drawRow++) { float YPos = (drawRow - Element.HIDDENROWS) * BlockHeight; var currRow = Source.Contents[drawRow]; //also, is there a hotline here? /* * if (Source.Flags.HasFlag(TetrisField.GameFlags.Flags_Hotline) && Source.HotLines.ContainsKey(drawRow)) * { * RectangleF RowBounds = new RectangleF(0, YPos, BlockWidth * Element.COLCOUNT, BlockHeight); * Brush useFillBrush = null; * var HotLine = Source.HotLines[drawRow]; * if (HotLine.LineBrush != null) useFillBrush = HotLine.LineBrush; * else * { * useFillBrush = GetHotLineTexture((int)RowBounds.Height + 1, HotLines[drawRow].Color); * } * if (useFillBrush is TextureBrush tb1) * { * tb1.TranslateTransform(0, YPos); * } * g.FillRectangle(useFillBrush, RowBounds); * if (useFillBrush is TextureBrush tb2) * { * tb2.ResetTransform(); * } * }*///hotline drawing needs to be reworked for the rendering providers... //for each Tetris Row... for (int drawCol = 0; drawCol < Element.COLCOUNT; drawCol++) { float XPos = drawCol * BlockWidth; var TetBlock = currRow[drawCol]; bool isAnim = false; if (TetBlock != null) { if (TetBlock is LineSeriesBlock && !(TetBlock is LineSeriesPrimaryBlock)) { ; } isAnim = Source.Theme.IsAnimated(TetBlock); if (isAnim == animated) { SKRect BlockBounds = new SKRect(XPos, YPos, XPos + BlockWidth, YPos + BlockHeight); TetrisBlockDrawSkiaParameters tbd = new TetrisBlockDrawSkiaParameters(g, BlockBounds, null, pState.Settings); RenderingProvider.Static.DrawElement(pState, tbd.g, TetBlock, tbd); } } FoundAnimated |= isAnim; } } if (FoundAnimated) { ; } return(FoundAnimated); }
public void Draw(TetrisField Source, TetrisFieldDrawSkiaParameters parms, IStateOwner pState, SKCanvas g, SKRect Bounds) { Stopwatch sw = new Stopwatch(); sw.Start(); //first how big is each block? float BlockWidth = Bounds.Width / parms.COLCOUNT; float BlockHeight = Bounds.Height / (parms.VISIBLEROWS); //remember, we don't draw the top two rows- we start the drawing at row index 2, skipping 0 and 1 when drawing. lock (Source) { if (parms.FieldBitmap == null || !parms.LastFieldSave.Equals(Bounds) || Source.HasChanged) { Debug.Print("Beginning Field Paint:" + sw.Elapsed.ToString()); SKImageInfo info = new SKImageInfo((int)Bounds.Width, (int)Bounds.Height, SKColorType.Bgra8888); //Note: what we want to do here is actually allocate the field bitmap using a Surface texture. doing it this way paints more slowly, //because it is backed by a bitmap and drawn largely by the CPU. //(nmote using the surface we can retrieve an image snapshot). if (bitmapMode) { using (SKBitmap BuildField = new SKBitmap(info, SKBitmapAllocFlags.None)) { using (SKCanvas gfield = new SKCanvas(BuildField)) { gfield.Clear(SKColors.Transparent); hadAnimated = DrawFieldContents(pState, Source, parms, gfield, Bounds, false); if (parms.FieldBitmap != null) { parms.FieldBitmap.Dispose(); } parms.FieldBitmap = SKImage.FromBitmap(BuildField); } } } else { using (var CreateContext = GRContext.Create(GRBackend.OpenGL, GlobalResources.OpenGLInterface)) { SKCanvas gfield = null; if (FieldSurface == null) { FieldSurface = SKSurface.Create(CreateContext, GlobalResources.CreateRenderTarget((int)Bounds.Width, (int)Bounds.Height), GRSurfaceOrigin.BottomLeft, GlobalResources.DefaultColorType); } var FieldCanvas = FieldSurface.Canvas; FieldCanvas.Flush(); gfield = FieldCanvas; gfield.Clear(SKColors.Transparent); hadAnimated = DrawFieldContents(pState, Source, parms, gfield, Bounds, false); if (parms.FieldBitmap != null) { parms.FieldBitmap.Dispose(); } parms.FieldBitmap = FieldSurface.Snapshot(); } } parms.LastFieldSave = Bounds; Source.HasChanged = false; Debug.Print("Finished Field Paint:" + sw.Elapsed.ToString()); } } Debug.Print("Drawing Field Bitmap" + sw.Elapsed.ToString()); g.DrawImage(parms.FieldBitmap, new SKPoint(0, 0)); //g.DrawBitmap(parms.FieldBitmap,new SKPoint(0,0)); Debug.Print("Field Bitmap finished" + sw.Elapsed.ToString()); if (hadAnimated) { Debug.Print("Animated Field blocks found"); DrawFieldContents(pState, Source, parms, g, Bounds, true); } var activegroups = Source.GetActiveBlockGroups(); Debug.Print("Painting Active Groups:" + sw.Elapsed.ToString()); lock (activegroups) { foreach (Nomino bg in activegroups) { int BaseXPos = bg.X; int BaseYPos = bg.Y; const float RotationTime = 150; double useAngle = 0; TimeSpan tsRotate = DateTime.Now - bg.GetLastRotation(); if (tsRotate.TotalMilliseconds > 0 && tsRotate.TotalMilliseconds < RotationTime) { if (!bg.LastRotateCCW) { useAngle = -90 + ((tsRotate.TotalMilliseconds / RotationTime) * 90); } else { useAngle = 90 - ((tsRotate.TotalMilliseconds / RotationTime) * 90); } } var translation = bg.GetHeightTranslation(pState, BlockHeight); float BlockPercent = translation / BlockHeight; float CalcValue = BlockPercent + (float)bg.Y; if (CalcValue > bg.HighestHeightValue) { bg.HighestHeightValue = CalcValue; } else { translation = (bg.HighestHeightValue - (float)bg.Y) * BlockHeight; } PointF doTranslate = new PointF(0, translation); if (!pState.Settings.std.SmoothFall) { doTranslate = new PointF(0, 0); } //if (Settings.SmoothFall) g.TranslateTransform(doTranslate.X, -BlockHeight + doTranslate.Y); if (pState.Settings.std.SmoothFall) { g.Translate(doTranslate.X, -BlockHeight + doTranslate.Y); } if (useAngle != 0 && pState.Settings.std.SmoothRotate) { int MaxXBlock = (from p in bg select p.X).Max(); int MaxYBlock = (from p in bg select p.Y).Max(); int MinXBlock = (from p in bg select p.X).Min(); int MinYBlock = (from p in bg select p.Y).Min(); int BlocksWidth = MaxXBlock - MinXBlock + 1; int BlocksHeight = MaxYBlock - MinYBlock + 1; PointF UsePosition = new PointF((bg.X + MinXBlock) * BlockWidth, (bg.Y - parms.HIDDENROWS + MinYBlock) * BlockHeight); SizeF tetronimosize = new Size((int)BlockWidth * (BlocksWidth), (int)BlockHeight * (BlocksHeight)); PointF useCenter = new PointF(UsePosition.X + tetronimosize.Width / 2, UsePosition.Y + tetronimosize.Height / 2); g.RotateDegrees((float)useAngle, useCenter.X, useCenter.Y); //g.TranslateTransform(useCenter.X, useCenter.Y); //g.RotateTransform((float)useAngle); //g.TranslateTransform(-useCenter.X, -useCenter.Y); } foreach (NominoElement bge in bg) { int DrawX = BaseXPos + bge.X; int DrawY = BaseYPos + bge.Y - parms.HIDDENROWS; if (DrawX >= 0 && DrawY >= 0 && DrawX < parms.COLCOUNT && DrawY < parms.ROWCOUNT) { float DrawXPx = DrawX * BlockWidth; float DrawYPx = DrawY * BlockHeight; SKRect BlockBounds = new SKRect(DrawXPx, DrawYPx, DrawXPx + BlockWidth, DrawYPx + BlockHeight); TetrisBlockDrawParameters tbd = new TetrisBlockDrawSkiaParameters(g, BlockBounds, bg, pState.Settings); RenderingProvider.Static.DrawElement(pState, g, bge.Block, tbd); } } g.ResetMatrix(); if (!bg.NoGhost) { var GrabGhost = Source.GetGhostDrop(pState, bg, out int dl); if (GrabGhost != null) { foreach (var iterateblock in bg) { float drawGhostX = BlockWidth * (GrabGhost.X + iterateblock.X); float drawGhostY = BlockHeight * (GrabGhost.Y + iterateblock.Y - 2); SKRect BlockBounds = new SKRect(drawGhostX, drawGhostY, drawGhostX + BlockWidth, drawGhostY + BlockHeight); TetrisBlockDrawSkiaParameters tbd = new TetrisBlockDrawSkiaParameters(g, BlockBounds, GrabGhost, pState.Settings); //ImageAttributes Shade = new ImageAttributes(); //SKColorMatrices.GetFader //Shade.SetColorMatrix(ColorMatrices.GetFader(0.5f)); //tbd.ApplyAttributes = Shade; //tbd.OverrideBrush = GhostBrush; tbd.ColorFilter = SKColorMatrices.GetFader(0.5f); var GetHandler = RenderingProvider.Static.GetHandler(typeof(SKCanvas), iterateblock.Block.GetType(), typeof(TetrisBlockDrawSkiaParameters)); GetHandler.Render(pState, tbd.g, iterateblock.Block, tbd); //iterateblock.Block.DrawBlock(tbd); } } } } } Debug.Print("Painting Active Groups Finished:" + sw.Elapsed.ToString()); }