1 using System.Drawing;
2 using System.Drawing.Imaging;
3 using OpenBveApi.Colors;
4 
5 namespace OpenBveApi.Textures
6 {
7 	/// <summary>Represents a System.Drawing.Bitmap where the texture can be loaded from.</summary>
8 	public class BitmapOrigin : TextureOrigin
9 	{
10 		/// <summary>The bitmap.</summary>
11 		public readonly Bitmap Bitmap;
12 		/// <summary>The texture parameters to be applied when loading the texture to OpenGL</summary>
13 		public readonly TextureParameters Parameters;
14 
15 		// --- constructors ---
16 		/// <summary>Creates a new bitmap origin.</summary>
17 		/// <param name="bitmap">The bitmap.</param>
BitmapOrigin(Bitmap bitmap)18 		public BitmapOrigin(Bitmap bitmap)
19 		{
20 			this.Bitmap = bitmap;
21 		}
22 
23 		/// <summary>Creates a new bitmap origin.</summary>
24 		/// <param name="bitmap">The bitmap.</param>
25 		/// <param name="parameters">The texture parameters</param>
BitmapOrigin(Bitmap bitmap, TextureParameters parameters)26 		public BitmapOrigin(Bitmap bitmap, TextureParameters parameters)
27 		{
28 			this.Bitmap = bitmap;
29 			this.Parameters = parameters;
30 		}
31 
32 		// --- functions ---
33 		/// <summary>Gets the texture from this origin.</summary>
34 		/// <param name="texture">Receives the texture.</param>
35 		/// <returns>Whether the texture could be obtained successfully.</returns>
GetTexture(out Texture texture)36 		public override bool GetTexture(out Texture texture)
37 		{
38 			Bitmap bitmap = this.Bitmap;
39 			Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
40 			/*
41 			 * If the bitmap format is not already 32-bit BGRA,
42 			 * then convert it to 32-bit BGRA.
43 			 * */
44 			Color24[] p = null;
45 			if (bitmap.PixelFormat != PixelFormat.Format32bppArgb && bitmap.PixelFormat != PixelFormat.Format24bppRgb)
46 			{
47 				/* Only store the color palette data for
48 				 * textures using a restricted palette
49 				 * With a large number of textures loaded at
50 				 * once, this can save a decent chunk of memory
51 				 * */
52 				p = new Color24[bitmap.Palette.Entries.Length];
53 				for (int i = 0; i < bitmap.Palette.Entries.Length; i++)
54 				{
55 					p[i] = bitmap.Palette.Entries[i];
56 				}
57 			}
58 
59 			if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
60 			{
61 				Bitmap compatibleBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format32bppArgb);
62 				System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(compatibleBitmap);
63 				graphics.DrawImage(bitmap, rect, rect, GraphicsUnit.Pixel);
64 				graphics.Dispose();
65 				bitmap = compatibleBitmap;
66 			}
67 
68 			/*
69 			 * Extract the raw bitmap data.
70 			 * */
71 			BitmapData data = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat);
72 			if (data.Stride == 4 * data.Width)
73 			{
74 				/*
75 				 * Copy the data from the bitmap
76 				 * to the array in BGRA format.
77 				 * */
78 				byte[] raw = new byte[data.Stride * data.Height];
79 				System.Runtime.InteropServices.Marshal.Copy(data.Scan0, raw, 0, data.Stride * data.Height);
80 				bitmap.UnlockBits(data);
81 				int width = bitmap.Width;
82 				int height = bitmap.Height;
83 				/*
84 				 * Change the byte order from BGRA to RGBA.
85 				 * */
86 				for (int i = 0; i < raw.Length; i += 4)
87 				{
88 					byte temp = raw[i];
89 					raw[i] = raw[i + 2];
90 					raw[i + 2] = temp;
91 				}
92 
93 				texture = new Texture(width, height, 32, raw, p);
94 				texture = texture.ApplyParameters(this.Parameters);
95 				return true;
96 			}
97 
98 			/*
99 				   * The stride is invalid. This indicates that the
100 				   * CLI either does not implement the conversion to
101 				   * 32-bit BGRA correctly, or that the CLI has
102 				   * applied additional padding that we do not
103 				   * support.
104 				   * */
105 			bitmap.UnlockBits(data);
106 			texture = null;
107 			return false;
108 		}
109 	}
110 }
111