/// <summary> /// Converts this image to an RGBA image with the palette provided. /// </summary> /// <param name="palette">The palette to convert with.</param> /// <returns>The RGBA image.</returns> public RgbaImage ToColor(Palette palette) { PaletteLayer paletteLayer = palette.Default; Color[] pixels = new Color[Area]; for (int i = 0; i < Area; i++) { // TODO: Could we extend the palette by 1 and set it to be transparent to avoid branching *every* pixel? short index = Indices[i]; Color color = index == TransparentIndex ? RgbaImage.Transparent : paletteLayer[index]; pixels[i] = color; } RgbaImage image = RgbaImage.From(Width, Height, pixels).Value; image.Namespace = Namespace; image.Offset = Offset; return(image); }
/// <summary> /// Takes the image given and draws it on top of the current image. /// Does not draw a pixel if the alpha is not fully opaque (as in /// alpha must be >= 1.0f). /// </summary> /// <param name="image">The image to draw on top.</param> /// <param name="topLeft">The top left corner to start drawing the /// image from.</param> /// <returns>True on success, false if it could not be written due to /// bounding issues (ex: image would write outside the bounds). /// </returns> public bool DrawOntoThis(RgbaImage image, Vec2I topLeft) { // We want to find the area we draw. This is effectively finding // the rectangle overlap. If there is none, we exit early. Vec2I drawStart = new Vec2I(Math.Max(0, topLeft.X), Math.Max(0, topLeft.Y)); Vec2I drawEnd = new Vec2I(Math.Min(topLeft.X + image.Width, Width), Math.Min(topLeft.Y + image.Height, Height)); Vec2I drawRange = drawEnd - drawStart; if (drawRange.X <= 0 || drawRange.Y <= 0) { return(false); } // The starting coordinate from the source image is usually from // the top left corner, but if the offset is negative then we are // going to have to draw from the insides of the source image. Vec2I srcStart = Vec2I.Zero; if (topLeft.X < 0) { srcStart = srcStart.WithX(-topLeft.X); } if (topLeft.Y < 0) { srcStart = srcStart.WithY(-topLeft.Y); } // The destination coordinate is usually at the top left coordinate // provided, but if the top left is negative then we will start our // drawing at the zero index for that axis. If we have no drawing // overlap we'd have exited early before reaching this, so starting // at zero is okay. Vec2I destStart = topLeft; if (destStart.X < 0) { destStart = destStart.WithX(0); } if (destStart.Y < 0) { destStart = destStart.WithY(0); } // Now we have enough info to draw. RgbaImage src = image; RgbaImage dest = this; int srcOffset = (srcStart.Y * src.Width) + srcStart.X; int destOffset = (destStart.Y * dest.Width) + destStart.X; try { for (int y = 0; y < drawRange.Y; y++) { int srcIndex = srcOffset; int destIndex = destOffset; for (int x = 0; x < drawRange.X; x++) { // For now, only draw the pixel if it is opaque. In the // future we can do alpha blending. Color srcColor = src.Pixels[srcIndex]; if (srcColor.a >= 1.0f) { dest.Pixels[destIndex] = srcColor; } srcIndex++; destIndex++; } srcOffset += src.Width; destOffset += dest.Width; } return(true); } catch { return(false); } }