/// <summary>Loads a texture from the specified file.</summary> /// <param name="file">The file that holds the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> internal bool Parse(string file, out Texture texture) { /* * Read the bitmap. This will be a bitmap of just * any format, not necessarily the one that allows * us to extract the bitmap data easily. * */ System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(file); Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); /* * If the bitmap format is not already 32-bit BGRA, * then convert it to 32-bit BGRA. * */ if (bitmap.PixelFormat != PixelFormat.Format32bppArgb) { Bitmap compatibleBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(compatibleBitmap); graphics.DrawImage(bitmap, rect, rect, GraphicsUnit.Pixel); graphics.Dispose(); bitmap.Dispose(); bitmap = compatibleBitmap; } /* * Extract the raw bitmap data. * */ BitmapData data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); if (data.Stride == 4 * data.Width) { /* * Copy the data from the bitmap * to the array in BGRA format. * */ byte[] raw = new byte[data.Stride * data.Height]; System.Runtime.InteropServices.Marshal.Copy(data.Scan0, raw, 0, data.Stride * data.Height); bitmap.UnlockBits(data); int width = bitmap.Width; int height = bitmap.Height; bitmap.Dispose(); /* * Change the byte order from BGRA to RGBA. * */ for (int i = 0; i < raw.Length; i += 4) { byte temp = raw[i]; raw[i] = raw[i + 2]; raw[i + 2] = temp; } texture = new Texture(width, height, 32, raw); return true; } else { /* * The stride is invalid. This indicates that the * CLI either does not implement the conversion to * 32-bit BGRA correctly, or that the CLI has * applied additional padding that we do not * support. * */ bitmap.UnlockBits(data); bitmap.Dispose(); CurrentHost.ReportProblem(ProblemType.InvalidOperation, "Invalid stride encountered."); texture = null; return false; } }
/// <summary>Loads the specified texture.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public override bool LoadTexture(string path, out OpenBveApi.Textures.Texture texture) { byte[] b = System.IO.File.ReadAllBytes(path); DDSImage d = new DDSImage(b); texture = d.myTexture; return(true); }
/// <summary>Registers a texture and returns a handle to the texture.</summary> /// <param name="texture">The texture data.</param> /// <returns>The handle to the texture.</returns> internal static Texture RegisterTexture(OpenBveApi.Textures.Texture texture) { /* * Register the texture and return the newly created handle. * */ int idx = GetNextFreeTexture(); RegisteredTextures[idx] = new Texture(texture); RegisteredTexturesCount++; return(RegisteredTextures[idx]); }
// --- apply parameters --- /// <summary>Applies parameters onto a texture.</summary> /// <param name="texture">The original texture.</param> /// <param name="parameters">The parameters, or a null reference.</param> /// <returns>The texture with the parameters applied.</returns> /// <exception cref="System.ArgumentException">Raised when the clip region is outside the texture bounds.</exception> /// <exception cref="System.NotSupportedException">Raised when the bits per pixel in the texture is other than 32.</exception> internal static Texture ApplyParameters(Texture texture, TextureParameters parameters) { Texture result = texture; if (parameters != null) { if (parameters.ClipRegion != null) { result = ExtractClipRegion(result, parameters.ClipRegion); } if (parameters.TransparentColor != null) { result = ApplyTransparentColor(result, parameters.TransparentColor); } } return result; }
// --- extract clip region --- /// <summary>Extracts a clip region from a texture.</summary> /// <param name="texture">The original texture.</param> /// <param name="region">The clip region, or a null reference.</param> /// <returns>The texture with the extracted clip region.</returns> /// <exception cref="System.ArgumentException">Raised when the clip region is outside the texture bounds.</exception> /// <exception cref="System.NotSupportedException">Raised when the number of bits per pixel in the texture is not supported.</exception> internal static Texture ExtractClipRegion(Texture texture, TextureClipRegion region) { if (region == null || region.Left == 0 && region.Top == 0 && region.Width == texture.Width && region.Height == texture.Height) { return texture; } if (region.Left < 0 || region.Top < 0 || region.Width <= 0 || region.Height <= 0 || region.Left + region.Width > texture.Width || region.Top + region.Height > texture.Height) { throw new ArgumentException(); } if (texture.BitsPerPixel == 24 | texture.BitsPerPixel == 32) { int width = texture.Width; int height = texture.Height; byte[] bytes = texture.Bytes; int clipLeft = region.Left; int clipTop = region.Top; int clipWidth = region.Width; int clipHeight = region.Height; if (texture.BitsPerPixel == 24) { byte[] newBytes = new byte[3 * clipWidth * clipHeight]; int i = 0; for (int y = 0; y < clipHeight; y++) { int j = 3 * width * (clipTop + y) + 3 * clipLeft; for (int x = 0; x < clipWidth; x++) { newBytes[i + 0] = bytes[j + 0]; newBytes[i + 1] = bytes[j + 1]; newBytes[i + 2] = bytes[j + 2]; i += 3; j += 3; } } return new Texture(clipWidth, clipHeight, 24, newBytes); } else { byte[] newBytes = new byte[4 * clipWidth * clipHeight]; int i = 0; for (int y = 0; y < clipHeight; y++) { int j = 4 * width * (clipTop + y) + 4 * clipLeft; for (int x = 0; x < clipWidth; x++) { newBytes[i + 0] = bytes[j + 0]; newBytes[i + 1] = bytes[j + 1]; newBytes[i + 2] = bytes[j + 2]; newBytes[i + 3] = bytes[j + 3]; i += 4; j += 4; } } return new Texture(clipWidth, clipHeight, 32, newBytes); } } throw new NotSupportedException(); }
// --- upsize texture --- /// <summary>Resizes the specified texture to a power of two size and returns the result.</summary> /// <param name="texture">The texture.</param> /// <returns>The upsized texture, or the original if already a power of two size.</returns> /// <exception cref="System.NotSupportedException">The bits per pixel in the texture is not supported.</exception> internal static OpenBveApi.Textures.Texture ResizeToPowerOfTwo(OpenBveApi.Textures.Texture texture) { int width = RoundUpToPowerOfTwo(texture.Width); int height = RoundUpToPowerOfTwo(texture.Height); //HACK: Some routes use non-power of two textures which upscale to stupid numbers //At least round down if we're over 1024 px.... if (width != texture.Width && width > 1024) { width /= 2; } if (height != texture.Height && height > 1024) { height /= 2; } return(Resize(texture, width, height)); }
// --- save texture --- /// <summary>Saves a texture to a file.</summary> /// <param name="file">The file.</param> /// <param name="texture">The texture.</param> /// <remarks>The texture is always saved in PNG format.</remarks> internal static void SaveTexture(string file, OpenBveApi.Textures.Texture texture) { Bitmap bitmap = new Bitmap(texture.Width, texture.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); BitmapData data = bitmap.LockBits(new Rectangle(0, 0, texture.Width, texture.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); byte[] bytes = new byte[texture.Bytes.Length]; for (int i = 0; i < bytes.Length; i += 4) { bytes[i] = texture.Bytes[i + 2]; bytes[i + 1] = texture.Bytes[i + 1]; bytes[i + 2] = texture.Bytes[i]; bytes[i + 3] = texture.Bytes[i + 3]; } Marshal.Copy(bytes, 0, data.Scan0, texture.Bytes.Length); bitmap.UnlockBits(data); bitmap.Save(file, ImageFormat.Png); bitmap.Dispose(); }
// --- apply transparent color --- /// <summary>Applies a transparent color onto a texture.</summary> /// <param name="texture">The original texture.</param> /// <param name="color">The transparent color, or a null reference.</param> /// <returns>The texture with the transparent color applied.</returns> /// <exception cref="System.NotSupportedException">Raised when the number of bits per pixel in the texture is not supported.</exception> internal static Texture ApplyTransparentColor(Texture texture, Color24? color) { if (color == null) { return texture; } else if (texture.BitsPerPixel == 32) { int width = texture.Width; int height = texture.Height; byte[] source = texture.Bytes; byte[] target = new byte[4 * width * height]; byte r = color.Value.R; byte g = color.Value.G; byte b = color.Value.B; if (source[0] == r && source[1] == g && source[2] == b) { target[0] = 128; target[1] = 128; target[2] = 128; target[3] = 0; } else { target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; } for (int i = 4; i < source.Length; i += 4) { if (source[i] == r && source[i + 1] == g && source[i + 2] == b) { target[i + 0] = target[i - 4]; target[i + 1] = target[i - 3]; target[i + 2] = target[i - 2]; target[i + 3] = 0; } else { target[i + 0] = source[i + 0]; target[i + 1] = source[i + 1]; target[i + 2] = source[i + 2]; target[i + 3] = source[i + 3]; } } return new Texture(width, height, 32, target); } else { throw new NotSupportedException(); } }
public override bool RegisterTexture(Bitmap texture, TextureParameters parameters, out OpenBveApi.Textures.Texture handle) { handle = new Texture(texture, parameters); return(true); }
/// <summary>Loads a texture and returns the texture data.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="parameters">The parameters that specify how to process the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public override bool LoadTexture(string path, OpenBveApi.Textures.TextureParameters parameters, out OpenBveApi.Textures.Texture texture) { if (System.IO.File.Exists(path) || System.IO.Directory.Exists(path)) { for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) { if (Program.CurrentHost.Plugins[i].Texture != null) { try { if (Program.CurrentHost.Plugins[i].Texture.CanLoadTexture(path)) { try { if (Program.CurrentHost.Plugins[i].Texture.LoadTexture(path, out texture)) { //texture.CompatibleTransparencyMode = Interface.CurrentOptions.OldTransparencyMode; texture = texture.ApplyParameters(parameters); return(true); } Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " returned unsuccessfully at LoadTexture"); } catch (Exception ex) { Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at LoadTexture:" + ex.Message); } } } catch (Exception ex) { Interface.AddMessage(MessageType.Error, false, "Plugin " + Program.CurrentHost.Plugins[i].Title + " raised the following exception at CanLoadTexture:" + ex.Message); } } } FileInfo f = new FileInfo(path); if (f.Length == 0) { Interface.AddMessage(MessageType.Error, false, "Zero-byte texture file encountered at " + path); } else { Interface.AddMessage(MessageType.Error, false, "No plugin found that is capable of loading texture " + path); } } else { ReportProblem(OpenBveApi.Hosts.ProblemType.PathNotFound, path); } texture = null; return(false); }
/// <summary>Loads the specified texture.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public abstract bool LoadTexture(string path, out Texture texture);
/// <summary>Resizes the specified texture to the specified width and height and returns the result.</summary> /// <param name="texture">The texture.</param> /// <param name="width">The new width.</param> /// <param name="height">The new height.</param> /// <returns>The resize texture, or the original if already of the specified size.</returns> /// <exception cref="System.NotSupportedException">The bits per pixel in the texture is not supported.</exception> internal static OpenBveApi.Textures.Texture Resize(OpenBveApi.Textures.Texture texture, int width, int height) { if (width == texture.Width && height == texture.Height) { return(texture); } if (texture.BitsPerPixel != 32) { throw new NotSupportedException("The number of bits per pixel is not supported."); } OpenBveApi.Textures.TextureTransparencyType type = texture.GetTransparencyType(); /* * Convert the texture into a bitmap. * */ Bitmap bitmap = new Bitmap(texture.Width, texture.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); BitmapData data = bitmap.LockBits(new Rectangle(0, 0, texture.Width, texture.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); Marshal.Copy(texture.Bytes, 0, data.Scan0, texture.Bytes.Length); bitmap.UnlockBits(data); /* * Scale the bitmap. * */ Bitmap scaledBitmap = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(scaledBitmap); graphics.InterpolationMode = InterpolationMode.HighQualityBilinear; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.DrawImage(bitmap, new Rectangle(0, 0, width, height), new Rectangle(0, 0, texture.Width, texture.Height), GraphicsUnit.Pixel); graphics.Dispose(); bitmap.Dispose(); /* * Convert the bitmap into a texture. * */ data = scaledBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, scaledBitmap.PixelFormat); byte[] bytes = new byte[4 * width * height]; Marshal.Copy(data.Scan0, bytes, 0, bytes.Length); scaledBitmap.UnlockBits(data); scaledBitmap.Dispose(); /* * Ensure opaque and partially transparent * textures have valid alpha components. * */ if (type == OpenBveApi.Textures.TextureTransparencyType.Opaque) { for (int i = 3; i < bytes.Length; i += 4) { bytes[i] = 255; } } else if (type == OpenBveApi.Textures.TextureTransparencyType.Partial) { for (int i = 3; i < bytes.Length; i += 4) { bytes[i] = bytes[i] < 128 ? (byte)0 : (byte)255; } } OpenBveApi.Textures.Texture result = new OpenBveApi.Textures.Texture(width, height, 32, bytes, texture.Palette); return(result); }
/// <summary>Loads a texture and returns the texture data.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="parameters">The parameters that specify how to process the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public virtual bool LoadTexture(string path, TextureParameters parameters, out Texture texture) { texture = null; return false; }
/// <summary>Loads the specified texture.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public override bool LoadTexture(string path, out Texture texture) { return Parse(path, out texture); }
/// <summary>Loads the specified texture.</summary> /// <param name="path">The path to the file or folder that contains the texture.</param> /// <param name="texture">Receives the texture.</param> /// <returns>Whether loading the texture was successful.</returns> public override bool LoadTexture(string path, out Texture texture) { texture = LoadFromFile(path); return true; }