/// <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); } else if (texture.BitsPerPixel != 32) { throw new NotSupportedException("The number of bits per pixel is not supported."); } else { OpenBveApi.Textures.TextureTransparencyType type = texture.GetTransparencyType(); /* * Convert the texture into a bitmap. * */ Bitmap bitmap = new Bitmap(texture.Width, texture.Height, 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, 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) { if (bytes[i] < 128) { bytes[i] = 0; } else { bytes[i] = 255; } } } OpenBveApi.Textures.Texture result = new OpenBveApi.Textures.Texture(width, height, 32, bytes); return(result); } }
/// <summary>Makes an object visible within the world</summary> /// <param name="ObjectIndex">The object's index</param> /// <param name="Type">Whether this is a static or dynamic object</param> internal static void ShowObject(int ObjectIndex, ObjectType Type) { if (ObjectManager.Objects[ObjectIndex] == null) { return; } if (ObjectManager.Objects[ObjectIndex].RendererIndex == 0) { if (ObjectCount >= Objects.Length) { Array.Resize <Object>(ref Objects, Objects.Length << 1); } Objects[ObjectCount].ObjectIndex = ObjectIndex; Objects[ObjectCount].Type = Type; int f = ObjectManager.Objects[ObjectIndex].Mesh.Faces.Length; Objects[ObjectCount].FaceListReferences = new ObjectListReference[f]; for (int i = 0; i < f; i++) { bool alpha = false; int k = ObjectManager.Objects[ObjectIndex].Mesh.Faces[i].Material; Textures.OpenGlTextureWrapMode wrap = Textures.OpenGlTextureWrapMode.ClampClamp; if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture != null | ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture != null) { if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode == null) { // If the object does not have a stored wrapping mode, determine it now for (int v = 0; v < ObjectManager.Objects[ObjectIndex].Mesh.Vertices.Length; v++) { if (ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.X <0.0f | ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.X> 1.0f) { wrap |= Textures.OpenGlTextureWrapMode.RepeatClamp; } if (ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y <0.0f | ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y> 1.0f) { wrap |= Textures.OpenGlTextureWrapMode.ClampRepeat; } } } else { //Yuck cast, but we need the null, as otherwise requires rewriting the texture indexer wrap = (Textures.OpenGlTextureWrapMode)ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode; } if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture != null) { if (Textures.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture, wrap)) { OpenBveApi.Textures.TextureTransparencyType type = ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture.Transparency; if (type == OpenBveApi.Textures.TextureTransparencyType.Alpha) { alpha = true; } else if (type == OpenBveApi.Textures.TextureTransparencyType.Partial && Interface.CurrentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture != null) { if (Textures.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture, wrap)) { OpenBveApi.Textures.TextureTransparencyType type = ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture.Transparency; if (type == OpenBveApi.Textures.TextureTransparencyType.Alpha) { alpha = true; } else if (type == OpenBveApi.Textures.TextureTransparencyType.Partial & Interface.CurrentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } } if (Type == ObjectType.Overlay & World.CameraRestriction != World.CameraRestrictionMode.NotAvailable) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].Color.A != 255) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].BlendMode == World.MeshMaterialBlendMode.Additive) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].GlowAttenuationData != 0) { alpha = true; } ObjectListType listType; switch (Type) { case ObjectType.Static: listType = alpha ? ObjectListType.DynamicAlpha : ObjectListType.StaticOpaque; break; case ObjectType.Dynamic: listType = alpha ? ObjectListType.DynamicAlpha : ObjectListType.DynamicOpaque; break; case ObjectType.Overlay: listType = alpha ? ObjectListType.OverlayAlpha : ObjectListType.OverlayOpaque; break; default: throw new InvalidOperationException(); } if (listType == ObjectListType.StaticOpaque) { /* * For the static opaque list, insert the face into * the first vacant position in the matching group's list. * */ int groupIndex = (int)ObjectManager.Objects[ObjectIndex].GroupIndex; if (groupIndex >= StaticOpaque.Length) { if (StaticOpaque.Length == 0) { StaticOpaque = new ObjectGroup[16]; } while (groupIndex >= StaticOpaque.Length) { Array.Resize <ObjectGroup>(ref StaticOpaque, StaticOpaque.Length << 1); } } if (StaticOpaque[groupIndex] == null) { StaticOpaque[groupIndex] = new ObjectGroup(); } ObjectList list = StaticOpaque[groupIndex].List; int newIndex = list.FaceCount; for (int j = 0; j < list.FaceCount; j++) { if (list.Faces[j] == null) { newIndex = j; break; } } if (newIndex == list.FaceCount) { if (list.FaceCount == list.Faces.Length) { Array.Resize <ObjectFace>(ref list.Faces, list.Faces.Length << 1); } list.FaceCount++; } list.Faces[newIndex] = new ObjectFace { ObjectListIndex = ObjectCount, ObjectIndex = ObjectIndex, FaceIndex = i, Wrap = wrap }; // HACK: Let's store the wrapping mode. StaticOpaque[groupIndex].Update = true; Objects[ObjectCount].FaceListReferences[i] = new ObjectListReference(listType, newIndex); Game.InfoStaticOpaqueFaceCount++; /* * Check if the given object has a bounding box, and insert it to the end of the list of bounding boxes if required */ if (ObjectManager.Objects[ObjectIndex].Mesh.BoundingBox != null) { int Index = list.BoundingBoxes.Length; for (int j = 0; j < list.BoundingBoxes.Length; j++) { if (list.Faces[j] == null) { Index = j; break; } } if (Index == list.BoundingBoxes.Length) { Array.Resize <BoundingBox>(ref list.BoundingBoxes, list.BoundingBoxes.Length << 1); } list.BoundingBoxes[Index].Upper = ObjectManager.Objects[ObjectIndex].Mesh.BoundingBox[0]; list.BoundingBoxes[Index].Lower = ObjectManager.Objects[ObjectIndex].Mesh.BoundingBox[1]; } } else { /* * For all other lists, insert the face at the end of the list. * */ ObjectList list; switch (listType) { case ObjectListType.DynamicOpaque: list = DynamicOpaque; break; case ObjectListType.DynamicAlpha: list = DynamicAlpha; break; case ObjectListType.OverlayOpaque: list = OverlayOpaque; break; case ObjectListType.OverlayAlpha: list = OverlayAlpha; break; default: throw new InvalidOperationException(); } if (list.FaceCount == list.Faces.Length) { Array.Resize <ObjectFace>(ref list.Faces, list.Faces.Length << 1); } list.Faces[list.FaceCount] = new ObjectFace { ObjectListIndex = ObjectCount, ObjectIndex = ObjectIndex, FaceIndex = i, Wrap = wrap }; // HACK: Let's store the wrapping mode. Objects[ObjectCount].FaceListReferences[i] = new ObjectListReference(listType, list.FaceCount); list.FaceCount++; } } ObjectManager.Objects[ObjectIndex].RendererIndex = ObjectCount + 1; ObjectCount++; } }