using Age.Engine.Model; namespace Age.Engine.Sys4; /// Platform-neutral software publication of retained gfx objects into an AGE surface. /// Native scripts use the same object list for the backbuffer and selected offscreen render targets. public static class RetainedSurfaceRasterizer { public static int CompositeRange( RgbaImage destination, IReadOnlyList visible, long firstHandle, long count, Func resolveSource) { ArgumentNullException.ThrowIfNull(destination); ArgumentNullException.ThrowIfNull(visible); ArgumentNullException.ThrowIfNull(resolveSource); if (destination.Width <= 0 || destination.Height <= 0 || destination.Pixels.Length != checked(destination.Width * destination.Height * 4) || count <= 0) return 0; int rendered = 0; foreach (RenderObject item in visible) { if (item.Handle < firstHandle || item.Handle - firstHandle >= count) continue; TransformState transform = item.Transform; Affine2D localToDestination = Transform2DMath.Build(transform, item.Rotation).FromLocalOrigin(item.DstX, item.DstY); if (item.RangeTransform is { } rangeTransform) localToDestination = localToDestination.Then(rangeTransform); RgbaImage? source = resolveSource(item); float opacity = item.Alpha / 255f; float tintStrength = item.TintStrength / 255f; if (source == null) { if (item.SurfaceResId != 0 || item.Blend == BlendKind.Opaque) continue; int width = item.W > 0 ? item.W : 800; int height = item.H > 0 ? item.H : 600; float fillOpacity = item.MultiplyTint ? opacity : opacity * tintStrength; SoftwareAffineRasterizer.FillRgba( destination.Pixels, destination.Width, destination.Height, width, height, localToDestination, item.Tint, fillOpacity); rendered++; continue; } if (item.W <= 0 || item.H <= 0 || item.SrcX < 0 || item.SrcY < 0) continue; int widthToDraw = System.Math.Min(item.W, source.Width - item.SrcX); int heightToDraw = System.Math.Min(item.H, source.Height - item.SrcY); if (widthToDraw <= 0 || heightToDraw <= 0) continue; SoftwareAffineRasterizer.BlitRgba( destination.Pixels, destination.Width, destination.Height, source.Pixels, source.Width, source.Height, item.SrcX, item.SrcY, widthToDraw, heightToDraw, localToDestination, item.Tint, tintStrength, opacity, item.MultiplyTint, item.Blend); rendered++; } return rendered; } }