/// <summary>Renders an object based background</summary> /// <param name="data">The background object</param> private void RenderBackgroundObject(BackgroundObject data) { if (renderer.AvailableNewRenderer) { renderer.DefaultShader.Activate(); renderer.DefaultShader.SetCurrentProjectionMatrix(renderer.CurrentProjectionMatrix); if (data.Object.Mesh.VAO == null) { VAOExtensions.CreateVAO(ref data.Object.Mesh, false, renderer.DefaultShader.VertexLayout); } } foreach (MeshFace face in data.Object.Mesh.Faces) { OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; if (data.Object.Mesh.Materials[face.Material].DaytimeTexture != null) { if (data.Object.Mesh.Materials[face.Material].WrapMode == null) { foreach (VertexTemplate vertex in data.Object.Mesh.Vertices) { if (vertex.TextureCoordinates.X < 0.0f || vertex.TextureCoordinates.X > 1.0f) { wrap |= OpenGlTextureWrapMode.RepeatClamp; } if (vertex.TextureCoordinates.Y < 0.0f || vertex.TextureCoordinates.Y > 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } data.Object.Mesh.Materials[face.Material].WrapMode = wrap; } } if (renderer.AvailableNewRenderer) { renderer.RenderFace(renderer.DefaultShader, new ObjectState { Prototype = data.Object }, face, Matrix4D.NoTransformation, Matrix4D.Scale(1.0) * renderer.CurrentViewMatrix); } else { renderer.RenderFaceImmediateMode(new ObjectState { Prototype = data.Object }, face, Matrix4D.NoTransformation, Matrix4D.Scale(1.0) * renderer.CurrentViewMatrix); } } if (renderer.AvailableNewRenderer) { renderer.DefaultShader.Deactivate(); } }
/// <summary>Makes an object visible within the world for selection</summary> /// <param name="ObjectIndex">The object's index</param> private static void ShowObjectSelection(int ObjectIndex) { if (ObjectManager.Objects[ObjectIndex] == null) { return; } if (ObjectManager.Objects[ObjectIndex].RendererIndex == 0) { if (ObjectCount >= Objects.Length) { Array.Resize(ref Objects, Objects.Length << 1); } Objects[ObjectCount].ObjectIndex = ObjectIndex; Objects[ObjectCount].Type = ObjectType.Overlay; int f = ObjectManager.Objects[ObjectIndex].Mesh.Faces.Length; Objects[ObjectCount].FaceListReferences = new ObjectListReference[f]; for (int i = 0; i < f; i++) { int k = ObjectManager.Objects[ObjectIndex].Mesh.Faces[i].Material; OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; if (Touch.FaceCount == Touch.Faces.Length) { Array.Resize(ref Touch.Faces, Touch.Faces.Length << 1); } Touch.Faces[Touch.FaceCount] = new ObjectFace { ObjectListIndex = ObjectCount, ObjectIndex = ObjectIndex, FaceIndex = i, Wrap = wrap }; // HACK: Let's store the wrapping mode. Objects[ObjectCount].FaceListReferences[i] = new ObjectListReference(ObjectListType.Touch, Touch.FaceCount); Touch.FaceCount++; } ObjectManager.Objects[ObjectIndex].RendererIndex = ObjectCount + 1; ObjectCount++; } }
/// <summary>Renders an object based background</summary> /// <param name="data">The background object</param> private void RenderBackgroundObject(BackgroundObject data) { if (data.Object.Mesh.VAO == null) { VAOExtensions.CreateVAO(ref data.Object.Mesh, false); } foreach (MeshFace face in data.Object.Mesh.Faces) { OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; if (data.Object.Mesh.Materials[face.Material].DaytimeTexture != null) { if (data.Object.Mesh.Materials[face.Material].WrapMode == null) { foreach (VertexTemplate vertex in data.Object.Mesh.Vertices) { if (vertex.TextureCoordinates.X < 0.0f || vertex.TextureCoordinates.X > 1.0f) { wrap |= OpenGlTextureWrapMode.RepeatClamp; } if (vertex.TextureCoordinates.Y < 0.0f || vertex.TextureCoordinates.Y > 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } data.Object.Mesh.Materials[face.Material].WrapMode = wrap; } } renderer.DefaultShader.Activate(); renderer.ResetShader(renderer.DefaultShader); renderer.RenderFace(renderer.DefaultShader, new ObjectState { Prototype = data.Object }, face); renderer.DefaultShader.Deactivate(); } }
internal static void RenderBackground(BackgroundManager.BackgroundObject Object) { if (!TexturingEnabled) { GL.Enable(EnableCap.Texture2D); TexturingEnabled = true; } int Mat = -1; for (int i = 0; i < Object.ObjectBackground.Mesh.Faces.Length; i++) { int m = Object.ObjectBackground.Mesh.Faces[i].Material; if (m != Mat) { OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; for (int v = 0; v < Object.ObjectBackground.Mesh.Vertices.Length; v++) { if (Object.ObjectBackground.Mesh.Vertices[v].TextureCoordinates.X <0.0f | Object.ObjectBackground.Mesh.Vertices[v].TextureCoordinates.X> 1.0f) { wrap |= OpenGlTextureWrapMode.RepeatClamp; } if (Object.ObjectBackground.Mesh.Vertices[v].TextureCoordinates.Y <0.0f | Object.ObjectBackground.Mesh.Vertices[v].TextureCoordinates.Y> 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } if (Object.ObjectBackground.Mesh.Materials[m].DaytimeTexture != null) { Textures.LoadTexture(Object.ObjectBackground.Mesh.Materials[m].DaytimeTexture, wrap); GL.BindTexture(TextureTarget.Texture2D, Object.ObjectBackground.Mesh.Materials[m].DaytimeTexture.OpenGlTextures[(int)wrap].Name); } } int FaceType = Object.ObjectBackground.Mesh.Faces[i].Flags & MeshFace.FaceTypeMask; switch (FaceType) { case MeshFace.FaceTypeTriangles: GL.Begin(PrimitiveType.Triangles); break; case MeshFace.FaceTypeTriangleStrip: GL.Begin(PrimitiveType.TriangleStrip); break; case MeshFace.FaceTypeQuads: GL.Begin(PrimitiveType.Quads); break; case MeshFace.FaceTypeQuadStrip: GL.Begin(PrimitiveType.QuadStrip); break; default: GL.Begin(PrimitiveType.Polygon); break; } for (int j = 0; j < Object.ObjectBackground.Mesh.Faces[i].Vertices.Length; j++) { GL.Color4(inv255 * (float)Object.ObjectBackground.Mesh.Materials[m].Color.R * 1.0f, inv255 * Object.ObjectBackground.Mesh.Materials[m].Color.G * 1.0f, inv255 * (float)Object.ObjectBackground.Mesh.Materials[m].Color.B * 1.0f, inv255 * (float)Object.ObjectBackground.Mesh.Materials[m].Color.A); VertexTemplate v = Object.ObjectBackground.Mesh.Vertices[Object.ObjectBackground.Mesh.Faces[i].Vertices[j].Index]; if (v is ColoredVertex) { ColoredVertex vv = v as ColoredVertex; GL.Color3(vv.Color.R, vv.Color.G, vv.Color.B); } GL.TexCoord2(v.TextureCoordinates.X, v.TextureCoordinates.Y); GL.Vertex3(v.Coordinates.X, v.Coordinates.Y, v.Coordinates.Z); } GL.End(); } }
// --- load texture --- /// <summary>Loads the specified texture into OpenGL if not already loaded.</summary> /// <param name="handle">The handle to the registered texture.</param> /// <param name="wrap">The texture type indicating the clamp mode.</param> /// <returns>Whether loading the texture was successful.</returns> internal static bool LoadTexture(Texture handle, OpenGlTextureWrapMode wrap) { if (handle.OpenGlTextures[(int)wrap].Valid) { return(true); } else if (handle.Ignore) { return(false); } else { OpenBveApi.Textures.Texture texture; if (handle.Origin.GetTexture(out texture)) { if (texture.BitsPerPixel == 32) { int[] names = new int[1]; Gl.glGenTextures(1, names); int error = Gl.glGetError(); Gl.glBindTexture(Gl.GL_TEXTURE_2D, names[0]); error = Gl.glGetError(); handle.OpenGlTextures[(int)wrap].Name = names[0]; handle.Width = texture.Width; handle.Height = texture.Height; handle.Transparency = texture.GetTransparencyType(); texture = UpsizeToPowerOfTwo(texture); // int newWidth = Math.Min(texture.Width, 256); // int newHeight = Math.Min(texture.Height, 256); // texture = Resize(texture, newWidth, newHeight); switch (Interface.CurrentOptions.Interpolation) { case Interface.InterpolationMode.NearestNeighbor: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); break; case Interface.InterpolationMode.Bilinear: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; case Interface.InterpolationMode.NearestNeighborMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_NEAREST); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); break; case Interface.InterpolationMode.BilinearMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; case Interface.InterpolationMode.TrilinearMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; default: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; } if ((wrap & OpenGlTextureWrapMode.RepeatClamp) != 0) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT); } else { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE); } if ((wrap & OpenGlTextureWrapMode.ClampRepeat) != 0) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT); } else { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); } if (Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.NearestNeighbor & Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.Bilinear) { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_FALSE); } else { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE); } if (Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.AnisotropicFiltering) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_ANISOTROPY_EXT, Interface.CurrentOptions.AnisotropicFilteringLevel); } if (handle.Transparency == OpenBveApi.Textures.TextureTransparencyType.Opaque) { /* * If the texture is fully opaque, the alpha channel is not used. * If the graphics driver and card support 24-bits per channel, * it is best to convert the bitmap data to that format in order * to save memory on the card. If the card does not support the * format, it will likely be upconverted to 32-bits per channel * again, and this is wasted effort. * */ int width = texture.Width; int height = texture.Height; int stride = (3 * (width + 1) >> 2) << 2; byte[] oldBytes = texture.Bytes; byte[] newBytes = new byte[stride * texture.Height]; int i = 0, j = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { newBytes[j + 0] = oldBytes[i + 0]; newBytes[j + 1] = oldBytes[i + 1]; newBytes[j + 2] = oldBytes[i + 2]; i += 4; j += 3; } j += stride - 3 * width; } Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB8, texture.Width, texture.Height, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, newBytes); } else { /* * The texture uses its alpha channel, so send the bitmap data * in 32-bits per channel as-is. * */ Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, texture.Width, texture.Height, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, texture.Bytes); } handle.OpenGlTextures[(int)wrap].Valid = true; return(true); } } } handle.Ignore = true; return(false); }
public override bool LoadTexture(Texture Texture, OpenGlTextureWrapMode wrapMode) { return(Program.Renderer.TextureManager.LoadTexture(Texture, wrapMode, CPreciseTimer.GetClockTicks(), Interface.CurrentOptions.Interpolation, Interface.CurrentOptions.AnisotropicFilteringLevel)); }
/// <summary>Loads a texture and returns the texture data.</summary> /// <param name="texture">Receives the texture.</param> /// <param name="wrapMode">The openGL wrap mode</param> /// <returns>Whether loading the texture was successful.</returns> public virtual bool LoadTexture(Textures.Texture texture, OpenGlTextureWrapMode wrapMode) { return(false); }
public void ShowObject(ObjectState State, ObjectType Type) { bool result = AddObject(State); if (State.Prototype.Mesh.VAO == null) { VAOExtensions.CreateVAO(ref State.Prototype.Mesh, State.Prototype.Dynamic); } if (!result) { return; } foreach (MeshFace face in State.Prototype.Mesh.Faces) { OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture != null || State.Prototype.Mesh.Materials[face.Material].NighttimeTexture != null) { if (State.Prototype.Mesh.Materials[face.Material].WrapMode == null) { // If the object does not have a stored wrapping mode, determine it now foreach (VertexTemplate vertex in State.Prototype.Mesh.Vertices) { if (vertex.TextureCoordinates.X < 0.0f || vertex.TextureCoordinates.X > 1.0f) { wrap |= OpenGlTextureWrapMode.RepeatClamp; } if (vertex.TextureCoordinates.Y < 0.0f || vertex.TextureCoordinates.Y > 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } State.Prototype.Mesh.Materials[face.Material].WrapMode = wrap; } } bool alpha = false; if (Type == ObjectType.Overlay && camera.CurrentRestriction != CameraRestrictionMode.NotAvailable) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].Color.A != 255) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].BlendMode == MeshMaterialBlendMode.Additive) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].GlowAttenuationData != 0) { alpha = true; } else { if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture != null) { currentHost.LoadTexture(State.Prototype.Mesh.Materials[face.Material].DaytimeTexture, (OpenGlTextureWrapMode)State.Prototype.Mesh.Materials[face.Material].WrapMode); if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture.Transparency == TextureTransparencyType.Partial && currentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture != null) { currentHost.LoadTexture(State.Prototype.Mesh.Materials[face.Material].NighttimeTexture, (OpenGlTextureWrapMode)State.Prototype.Mesh.Materials[face.Material].WrapMode); if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture.Transparency == TextureTransparencyType.Partial && currentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } /* * For all lists, insert the face at the end of the list. * */ List <FaceState> list; switch (Type) { case ObjectType.Static: case ObjectType.Dynamic: list = alpha ? myAlphaFaces : myOpaqueFaces; break; case ObjectType.Overlay: list = alpha ? myOverlayAlphaFaces : myOverlayOpaqueFaces; break; default: throw new ArgumentOutOfRangeException(nameof(Type), Type, null); } list.Add(new FaceState(State, face)); } }
// --- texture --- public override bool LoadTexture(Texture Texture, OpenGlTextureWrapMode wrapMode) { return(Program.Renderer.TextureManager.LoadTexture(Texture, wrapMode, Environment.TickCount, InterpolationMode.BilinearMipmapped, 16)); }
// --- load texture --- /// <summary>Loads the specified texture into OpenGL if not already loaded.</summary> /// <param name="handle">The handle to the registered texture.</param> /// <param name="wrap">The texture type indicating the clamp mode.</param> /// <param name="currentTicks">The current system clock-ticks</param> /// <param name="Interpolation">The interpolation mode to use when loading the texture</param> /// <param name="AnisotropicFilteringLevel">The anisotropic filtering level to use when loading the texture</param> /// <returns>Whether loading the texture was successful.</returns> public bool LoadTexture(Texture handle, OpenGlTextureWrapMode wrap, int currentTicks, InterpolationMode Interpolation, int AnisotropicFilteringLevel) { //Don't try to load a texture to a null handle, this is a seriously bad idea.... if (handle == null || handle.OpenGlTextures == null) { return(false); } //Set last access time handle.LastAccess = currentTicks; if (handle.OpenGlTextures[(int)wrap].Valid) { return(true); } if (handle.Ignore) { return(false); } Texture texture; if (handle.Origin.GetTexture(out texture)) { if (texture.BitsPerPixel == 32) { int[] names = new int[1]; GL.GenTextures(1, names); GL.BindTexture(TextureTarget.Texture2D, names[0]); handle.OpenGlTextures[(int)wrap].Name = names[0]; handle.Width = texture.Width; handle.Height = texture.Height; handle.Transparency = texture.GetTransparencyType(); //texture = ResizeToPowerOfTwo(texture); switch (Interpolation) { case InterpolationMode.NearestNeighbor: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest); break; case InterpolationMode.Bilinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; case InterpolationMode.NearestNeighborMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.NearestMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest); break; case InterpolationMode.BilinearMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.NearestMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; case InterpolationMode.TrilinearMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; default: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; } if ((wrap & OpenGlTextureWrapMode.RepeatClamp) != 0) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Repeat); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.ClampToEdge); } if ((wrap & OpenGlTextureWrapMode.ClampRepeat) != 0) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Repeat); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.ClampToEdge); } if (Interpolation == InterpolationMode.NearestNeighbor || Interpolation == InterpolationMode.Bilinear) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 0); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1); } if (Interpolation == InterpolationMode.AnisotropicFiltering && AnisotropicFilteringLevel > 0) { GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)ExtTextureFilterAnisotropic.TextureMaxAnisotropyExt, AnisotropicFilteringLevel); } if (handle.Transparency == TextureTransparencyType.Opaque) { /* * If the texture is fully opaque, the alpha channel is not used. * If the graphics driver and card support 24-bits per channel, * it is best to convert the bitmap data to that format in order * to save memory on the card. If the card does not support the * format, it will likely be upconverted to 32-bits per channel * again, and this is wasted effort. * */ int width = texture.Width; int height = texture.Height; int stride = (3 * (width + 1) >> 2) << 2; byte[] oldBytes = texture.Bytes; byte[] newBytes = new byte[stride * texture.Height]; int i = 0, j = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { newBytes[j + 0] = oldBytes[i + 0]; newBytes[j + 1] = oldBytes[i + 1]; newBytes[j + 2] = oldBytes[i + 2]; i += 4; j += 3; } j += stride - 3 * width; } GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb8, texture.Width, texture.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.UnsignedByte, newBytes); } else { /* * The texture uses its alpha channel, so send the bitmap data * in 32-bits per channel as-is. * */ GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, texture.Width, texture.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, texture.Bytes); } handle.OpenGlTextures[(int)wrap].Valid = true; return(true); } } handle.Ignore = true; return(false); }
/// <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; OpenGlTextureWrapMode wrap = 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 |= OpenGlTextureWrapMode.RepeatClamp; } if (ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y <0.0f | ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y> 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } } else { //Yuck cast, but we need the null, as otherwise requires rewriting the texture indexer wrap = (OpenGlTextureWrapMode)ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode; } if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture != null) { if (Program.CurrentHost.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture, wrap)) { TextureTransparencyType type = ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture.Transparency; if (type == TextureTransparencyType.Alpha) { alpha = true; } else if (type == TextureTransparencyType.Partial && Interface.CurrentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture != null) { if (Program.CurrentHost.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture, wrap)) { TextureTransparencyType type = ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture.Transparency; if (type == TextureTransparencyType.Alpha) { alpha = true; } else if (type == TextureTransparencyType.Partial & Interface.CurrentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } } if (Type == ObjectType.Overlay & Camera.CurrentRestriction != 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 == 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++; } }
// --- load texture --- /// <summary>Loads the specified texture into OpenGL if not already loaded.</summary> /// <param name="handle">The handle to the registered texture.</param> /// <param name="wrap">The texture type indicating the clamp mode.</param> /// <returns>Whether loading the texture was successful.</returns> internal static bool LoadTexture(Texture handle, OpenGlTextureWrapMode wrap) { if (handle.OpenGlTextures[(int)wrap].Valid) { return true; } else if (handle.Ignore) { return false; } else { OpenBveApi.Textures.Texture texture; if (handle.Origin.GetTexture(out texture)) { if (texture.BitsPerPixel == 32) { int[] names = new int[1]; Gl.glGenTextures(1, names); int error = Gl.glGetError(); Gl.glBindTexture(Gl.GL_TEXTURE_2D, names[0]); error = Gl.glGetError(); handle.OpenGlTextures[(int)wrap].Name = names[0]; handle.Width = texture.Width; handle.Height = texture.Height; handle.Transparency = texture.GetTransparencyType(); texture = UpsizeToPowerOfTwo(texture); // int newWidth = Math.Min(texture.Width, 256); // int newHeight = Math.Min(texture.Height, 256); // texture = Resize(texture, newWidth, newHeight); switch (Interface.CurrentOptions.Interpolation) { case Interface.InterpolationMode.NearestNeighbor: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); break; case Interface.InterpolationMode.Bilinear: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; case Interface.InterpolationMode.NearestNeighborMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_NEAREST); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); break; case Interface.InterpolationMode.BilinearMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; case Interface.InterpolationMode.TrilinearMipmapped: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; default: Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_LINEAR_MIPMAP_LINEAR); Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_LINEAR); break; } if ((wrap & OpenGlTextureWrapMode.RepeatClamp) != 0) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT); } else { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE); } if ((wrap & OpenGlTextureWrapMode.ClampRepeat) != 0) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT); } else { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); } if (Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.NearestNeighbor & Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.Bilinear) { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_FALSE); } else { Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_GENERATE_MIPMAP, Gl.GL_TRUE); } if (Interface.CurrentOptions.Interpolation == Interface.InterpolationMode.AnisotropicFiltering) { Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAX_ANISOTROPY_EXT, Interface.CurrentOptions.AnisotropicFilteringLevel); } if (handle.Transparency == OpenBveApi.Textures.TextureTransparencyType.Opaque) { /* * If the texture is fully opaque, the alpha channel is not used. * If the graphics driver and card support 24-bits per channel, * it is best to convert the bitmap data to that format in order * to save memory on the card. If the card does not support the * format, it will likely be upconverted to 32-bits per channel * again, and this is wasted effort. * */ int width = texture.Width; int height = texture.Height; int stride = (3 * (width + 1) >> 2) << 2; byte[] oldBytes = texture.Bytes; byte[] newBytes = new byte[stride * texture.Height]; int i = 0, j = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { newBytes[j + 0] = oldBytes[i + 0]; newBytes[j + 1] = oldBytes[i + 1]; newBytes[j + 2] = oldBytes[i + 2]; i += 4; j += 3; } j += stride - 3 * width; } Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGB8, texture.Width, texture.Height, 0, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, newBytes); } else { /* * The texture uses its alpha channel, so send the bitmap data * in 32-bits per channel as-is. * */ Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA8, texture.Width, texture.Height, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, texture.Bytes); } handle.OpenGlTextures[(int)wrap].Valid = true; return true; } } } handle.Ignore = true; return false; }
public void ShowObject(ObjectState State, ObjectType Type) { bool result = AddObject(State); if (!renderer.ForceLegacyOpenGL && State.Prototype.Mesh.VAO == null) { VAOExtensions.CreateVAO(ref State.Prototype.Mesh, State.Prototype.Dynamic, renderer.DefaultShader.VertexLayout); } if (!result) { return; } foreach (MeshFace face in State.Prototype.Mesh.Faces) { OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture != null || State.Prototype.Mesh.Materials[face.Material].NighttimeTexture != null) { if (State.Prototype.Mesh.Materials[face.Material].WrapMode == null) { // If the object does not have a stored wrapping mode, determine it now foreach (VertexTemplate vertex in State.Prototype.Mesh.Vertices) { if (vertex.TextureCoordinates.X < 0.0f || vertex.TextureCoordinates.X > 1.0f) { wrap |= OpenGlTextureWrapMode.RepeatClamp; } if (vertex.TextureCoordinates.Y < 0.0f || vertex.TextureCoordinates.Y > 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } State.Prototype.Mesh.Materials[face.Material].WrapMode = wrap; } } bool alpha = false; if (Type == ObjectType.Overlay && camera.CurrentRestriction != CameraRestrictionMode.NotAvailable) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].Color.A != 255) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].BlendMode == MeshMaterialBlendMode.Additive) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].GlowAttenuationData != 0) { alpha = true; } else { if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture != null) { currentHost.LoadTexture(State.Prototype.Mesh.Materials[face.Material].DaytimeTexture, (OpenGlTextureWrapMode)State.Prototype.Mesh.Materials[face.Material].WrapMode); if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].DaytimeTexture.Transparency == TextureTransparencyType.Partial && currentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture != null) { currentHost.LoadTexture(State.Prototype.Mesh.Materials[face.Material].NighttimeTexture, (OpenGlTextureWrapMode)State.Prototype.Mesh.Materials[face.Material].WrapMode); if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (State.Prototype.Mesh.Materials[face.Material].NighttimeTexture.Transparency == TextureTransparencyType.Partial && currentOptions.TransparencyMode == TransparencyMode.Quality) { alpha = true; } } } List <FaceState> list; switch (Type) { case ObjectType.Static: case ObjectType.Dynamic: list = alpha ? myAlphaFaces : myOpaqueFaces; break; case ObjectType.Overlay: list = alpha ? myOverlayAlphaFaces : myOverlayOpaqueFaces; break; default: throw new ArgumentOutOfRangeException(nameof(Type), Type, null); } if (!alpha) { /* * If an opaque face, itinerate through the list to see if the prototype is present in the list * When the new renderer is in use, this prevents re-binding the VBO as it is simply re-drawn with * a different translation matrix * NOTE: The shader isn't currently smart enough to do depth discards, so if this changes may need to * be revisited */ if (list.Count == 0) { list.Add(new FaceState(State, face)); } else { for (int i = 0; i < list.Count; i++) { if (list[i].Object.Prototype == State.Prototype) { list.Insert(i, new FaceState(State, face)); break; } if (i == list.Count - 1) { list.Add(new FaceState(State, face)); break; } } } } else { /* * Alpha faces should be inserted at the end of the list- We're going to sort it anyway so it makes no odds */ list.Add(new FaceState(State, face)); } } }
// --- load texture --- /// <summary>Loads the specified texture into OpenGL if not already loaded.</summary> /// <param name="handle">The handle to the registered texture.</param> /// <param name="wrap">The texture type indicating the clamp mode.</param> /// <returns>Whether loading the texture was successful.</returns> internal static bool LoadTexture(Texture handle, OpenGlTextureWrapMode wrap){ if (handle.OpenGlTextures[(int)wrap].Valid) return true; if (handle.Ignore) return false; else { OpenBveApi.Textures.Texture texture; if (handle.Origin.GetTexture(out texture)) { if (texture.BitsPerPixel == 32) { int[] names = new int[1]; GL.GenTextures(1, names); ErrorCode error = GL.GetError(); GL.BindTexture(TextureTarget.Texture2D, names[0]); error = GL.GetError(); handle.OpenGlTextures[(int)wrap].Name = names[0]; handle.Width = texture.Width; handle.Height = texture.Height; handle.Transparency = texture.GetTransparencyType(); texture = UpsizeToPowerOfTwo(texture); // int newWidth = Math.Min(texture.Width, 256); // int newHeight = Math.Min(texture.Height, 256); // texture = Resize(texture, newWidth, newHeight); switch (Options.Current.Interpolation) { case Options.InterpolationMode.NearestNeighbor: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest); break; case Options.InterpolationMode.Bilinear: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; case Options.InterpolationMode.NearestNeighborMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.NearestMipmapNearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Nearest); break; case Options.InterpolationMode.BilinearMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.NearestMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; case Options.InterpolationMode.TrilinearMipmapped: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; default: GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (float)TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (float)TextureMagFilter.Linear); break; } if ((wrap & OpenGlTextureWrapMode.RepeatClamp) != 0) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.Repeat); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (float)TextureWrapMode.ClampToEdge); } if ((wrap & OpenGlTextureWrapMode.ClampRepeat) != 0) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.Repeat); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (float)TextureWrapMode.ClampToEdge); } if (Options.Current.Interpolation == Options.InterpolationMode.NearestNeighbor && Options.Current.Interpolation == Options.InterpolationMode.Bilinear) { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 0); } else { GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.GenerateMipmap, 1); } if (Options.Current.Interpolation == Options.InterpolationMode.AnisotropicFiltering) { GL.TexParameter(TextureTarget.Texture2D, (TextureParameterName)ExtTextureFilterAnisotropic.TextureMaxAnisotropyExt, Options.Current.AnisotropicFilteringLevel); } if (handle.Transparency == OpenBveApi.Textures.TextureTransparencyType.Opaque) { /* * If the texture is fully opaque, the alpha channel is not used. * If the graphics driver and card support 24-bits per channel, * it is best to convert the bitmap data to that format in order * to save memory on the card. If the card does not support the * format, it will likely be upconverted to 32-bits per channel * again, and this is wasted effort. * */ int width = texture.Width; int height = texture.Height; int stride = (3 * (width + 1) >> 2) << 2; byte[] oldBytes = texture.Bytes; byte[] newBytes = new byte[stride * texture.Height]; int i = 0, j = 0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { newBytes[j + 0] = oldBytes[i + 0]; newBytes[j + 1] = oldBytes[i + 1]; newBytes[j + 2] = oldBytes[i + 2]; i += 4; j += 3; } j += stride - 3 * width; } GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb8, texture.Width, texture.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgb, PixelType.UnsignedByte, newBytes); } else { /* * The texture uses its alpha channel, so send the bitmap data * in 32-bits per channel as-is. * */ GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, texture.Width, texture.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Rgba, PixelType.UnsignedByte, texture.Bytes); } handle.OpenGlTextures[(int)wrap].Valid = true; return true; } } } handle.Ignore = true; return false; }
private static void RenderFace(ref MeshMaterial Material, VertexTemplate[] Vertices, OpenGlTextureWrapMode wrap, ref MeshFace Face, double CameraX, double CameraY, double CameraZ) { // texture if (Material.DaytimeTexture != null) { if (Textures.LoadTexture(Material.DaytimeTexture, wrap)) { if (!TexturingEnabled) { GL.Enable(EnableCap.Texture2D); TexturingEnabled = true; } if (Material.DaytimeTexture.OpenGlTextures[(int)wrap] != LastBoundTexture) { GL.BindTexture(TextureTarget.Texture2D, Material.DaytimeTexture.OpenGlTextures[(int)wrap].Name); LastBoundTexture = Material.DaytimeTexture.OpenGlTextures[(int)wrap]; } } else { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; LastBoundTexture = null; } } } else { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; LastBoundTexture = null; } } // blend mode float factor; if (Material.BlendMode == MeshMaterialBlendMode.Additive) { factor = 1.0f; if (!BlendEnabled) { GL.Enable(EnableCap.Blend); } GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One); if (FogEnabled) { GL.Disable(EnableCap.Fog); } } else if (Material.NighttimeTexture == null) { float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } factor = 1.0f - 0.7f * blend; } else { factor = 1.0f; } if (Material.NighttimeTexture != null) { if (LightingEnabled) { GL.Disable(EnableCap.Lighting); LightingEnabled = false; } } else { if (OptionLighting & !LightingEnabled) { GL.Enable(EnableCap.Lighting); LightingEnabled = true; } } // render daytime polygon int FaceType = Face.Flags & MeshFace.FaceTypeMask; switch (FaceType) { case MeshFace.FaceTypeTriangles: GL.Begin(PrimitiveType.Triangles); break; case MeshFace.FaceTypeTriangleStrip: GL.Begin(PrimitiveType.TriangleStrip); break; case MeshFace.FaceTypeQuads: GL.Begin(PrimitiveType.Quads); break; case MeshFace.FaceTypeQuadStrip: GL.Begin(PrimitiveType.QuadStrip); break; default: GL.Begin(PrimitiveType.Polygon); break; } if (Material.GlowAttenuationData != 0) { float alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); if (OptionWireframe) { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, 1.0f); } else { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); } } else { if (OptionWireframe) { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, 1.0f); } else { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A); } } if ((Material.Flags & MeshMaterial.EmissiveColorMask) != 0) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { inv255 *(float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); } else { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); } if (Material.DaytimeTexture != null) { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { GL.Normal3(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); if (Vertices[Face.Vertices[j].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)Vertices[Face.Vertices[j].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); if (Vertices[Face.Vertices[j].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)Vertices[Face.Vertices[j].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } else { if (LightingEnabled) { for (int j = 0; j < Face.Vertices.Length; j++) { GL.Normal3(Face.Vertices[j].Normal.X, Face.Vertices[j].Normal.Y, Face.Vertices[j].Normal.Z); if (Vertices[Face.Vertices[j].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)Vertices[Face.Vertices[j].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } else { for (int j = 0; j < Face.Vertices.Length; j++) { if (Vertices[Face.Vertices[j].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)Vertices[Face.Vertices[j].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } } } GL.End(); // render nighttime polygon if (Material.NighttimeTexture != null && Textures.LoadTexture(Material.NighttimeTexture, wrap)) { if (!TexturingEnabled) { GL.Enable(EnableCap.Texture2D); TexturingEnabled = true; } if (!BlendEnabled) { GL.Enable(EnableCap.Blend); } GL.BindTexture(TextureTarget.Texture2D, Material.NighttimeTexture.OpenGlTextures[(int)wrap].Name); LastBoundTexture = null; GL.AlphaFunc(AlphaFunction.Greater, 0.0f); GL.Enable(EnableCap.AlphaTest); switch (FaceType) { case MeshFace.FaceTypeTriangles: GL.Begin(PrimitiveType.Triangles); break; case MeshFace.FaceTypeTriangleStrip: GL.Begin(PrimitiveType.TriangleStrip); break; case MeshFace.FaceTypeQuads: GL.Begin(PrimitiveType.Quads); break; case MeshFace.FaceTypeQuadStrip: GL.Begin(PrimitiveType.QuadStrip); break; default: GL.Begin(PrimitiveType.Polygon); break; } float alphafactor; if (Material.GlowAttenuationData != 0) { alphafactor = (float)GetDistanceFactor(Vertices, ref Face, Material.GlowAttenuationData, CameraX, CameraY, CameraZ); float blend = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } alphafactor *= blend; } else { alphafactor = inv255 * (float)Material.DaytimeNighttimeBlend + 1.0f - OptionLightingResultingAmount; if (alphafactor > 1.0f) { alphafactor = 1.0f; } } if (OptionWireframe) { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, 1.0f); } else { GL.Color4(inv255 * (float)Material.Color.R * factor, inv255 * Material.Color.G * factor, inv255 * (float)Material.Color.B * factor, inv255 * (float)Material.Color.A * alphafactor); } if ((Material.Flags & MeshMaterial.EmissiveColorMask) != 0) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { inv255 *(float)Material.EmissiveColor.R, inv255 * (float)Material.EmissiveColor.G, inv255 * (float)Material.EmissiveColor.B, 1.0f }); } else { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new float[] { 0.0f, 0.0f, 0.0f, 1.0f }); } for (int j = 0; j < Face.Vertices.Length; j++) { GL.TexCoord2(Vertices[Face.Vertices[j].Index].TextureCoordinates.X, Vertices[Face.Vertices[j].Index].TextureCoordinates.Y); if (Vertices[Face.Vertices[j].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)Vertices[Face.Vertices[j].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); } GL.End(); RestoreAlphaFunc(); if (!BlendEnabled) { GL.Disable(EnableCap.Blend); } } // normals if (OptionNormals) { if (TexturingEnabled) { GL.Disable(EnableCap.Texture2D); TexturingEnabled = false; } for (int j = 0; j < Face.Vertices.Length; j++) { GL.Begin(PrimitiveType.Lines); GL.Color4(inv255 * (float)Material.Color.R, inv255 * (float)Material.Color.G, inv255 * (float)Material.Color.B, 1.0f); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z - CameraZ)); GL.Vertex3((float)(Vertices[Face.Vertices[j].Index].Coordinates.X + Face.Vertices[j].Normal.X - CameraX), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Y + Face.Vertices[j].Normal.Y - CameraY), (float)(Vertices[Face.Vertices[j].Index].Coordinates.Z + Face.Vertices[j].Normal.Z - CameraZ)); GL.End(); } } // finalize if (Material.BlendMode == MeshMaterialBlendMode.Additive) { GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); if (!BlendEnabled) { GL.Disable(EnableCap.Blend); } if (FogEnabled) { GL.Enable(EnableCap.Fog); } } }
// show object internal static void ShowObject(int ObjectIndex, ObjectType Type) { bool Overlay = Type == ObjectType.Overlay; if (ObjectManager.Objects[ObjectIndex] == null) { return; } if (ObjectManager.Objects[ObjectIndex].RendererIndex == 0) { if (ObjectListCount >= ObjectList.Length) { Array.Resize <Object>(ref ObjectList, ObjectList.Length << 1); } ObjectList[ObjectListCount].ObjectIndex = ObjectIndex; ObjectList[ObjectListCount].Type = Type; int f = ObjectManager.Objects[ObjectIndex].Mesh.Faces.Length; ObjectList[ObjectListCount].FaceListIndices = new int[f]; for (int i = 0; i < f; i++) { if (Overlay) { // overlay if (OverlayListCount >= OverlayList.Length) { Array.Resize(ref OverlayList, OverlayList.Length << 1); Array.Resize(ref OverlayListDistance, OverlayList.Length); } OverlayList[OverlayListCount].ObjectIndex = ObjectIndex; OverlayList[OverlayListCount].FaceIndex = i; OverlayList[OverlayListCount].ObjectListIndex = ObjectListCount; ObjectList[ObjectListCount].FaceListIndices[i] = (OverlayListCount << 2) + 3; OverlayListCount++; } else { int k = ObjectManager.Objects[ObjectIndex].Mesh.Faces[i].Material; OpenGlTextureWrapMode wrap = OpenGlTextureWrapMode.ClampClamp; bool transparentcolor = false, alpha = false; if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].Color.A != 255) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].BlendMode == MeshMaterialBlendMode.Additive) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].GlowAttenuationData != 0) { alpha = true; } else { if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture != 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 |= OpenGlTextureWrapMode.RepeatClamp; } if (ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y <0.0f | ObjectManager.Objects[ObjectIndex].Mesh.Vertices[v].TextureCoordinates.Y> 1.0f) { wrap |= OpenGlTextureWrapMode.ClampRepeat; } } ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode = wrap; } else { //Yuck cast, but we need the null, as otherwise requires rewriting the texture indexer wrap = (OpenGlTextureWrapMode)ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode; } Program.CurrentHost.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture, (OpenGlTextureWrapMode)ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode); if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].DaytimeTexture.Transparency == TextureTransparencyType.Partial) { transparentcolor = true; } } if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture != null) { Program.CurrentHost.LoadTexture(ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture, (OpenGlTextureWrapMode)ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].WrapMode); if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture.Transparency == TextureTransparencyType.Alpha) { alpha = true; } else if (ObjectManager.Objects[ObjectIndex].Mesh.Materials[k].NighttimeTexture.Transparency == TextureTransparencyType.Partial) { transparentcolor = true; } } } if (alpha) { // alpha if (AlphaListCount >= AlphaList.Length) { Array.Resize(ref AlphaList, AlphaList.Length << 1); Array.Resize(ref AlphaListDistance, AlphaList.Length); } AlphaList[AlphaListCount] = new ObjectFace(); AlphaList[AlphaListCount].ObjectIndex = ObjectIndex; AlphaList[AlphaListCount].FaceIndex = i; AlphaList[AlphaListCount].ObjectListIndex = ObjectListCount; AlphaList[AlphaListCount].Wrap = wrap; ObjectList[ObjectListCount].FaceListIndices[i] = (AlphaListCount << 2) + 2; AlphaListCount++; } else if (transparentcolor) { // transparent color if (TransparentColorListCount >= TransparentColorList.Length) { Array.Resize(ref TransparentColorList, TransparentColorList.Length << 1); Array.Resize(ref TransparentColorListDistance, TransparentColorList.Length); } TransparentColorList[TransparentColorListCount] = new ObjectFace(); TransparentColorList[TransparentColorListCount].ObjectIndex = ObjectIndex; TransparentColorList[TransparentColorListCount].FaceIndex = i; TransparentColorList[TransparentColorListCount].ObjectListIndex = ObjectListCount; TransparentColorList[TransparentColorListCount].Wrap = wrap; ObjectList[ObjectListCount].FaceListIndices[i] = (TransparentColorListCount << 2) + 1; TransparentColorListCount++; } else { // opaque if (OpaqueListCount >= OpaqueList.Length) { Array.Resize(ref OpaqueList, OpaqueList.Length << 1); } OpaqueList[OpaqueListCount] = new ObjectFace(); OpaqueList[OpaqueListCount].ObjectIndex = ObjectIndex; OpaqueList[OpaqueListCount].FaceIndex = i; OpaqueList[OpaqueListCount].ObjectListIndex = ObjectListCount; OpaqueList[OpaqueListCount].Wrap = wrap; ObjectList[ObjectListCount].FaceListIndices[i] = OpaqueListCount << 2; OpaqueListCount++; } } } ObjectManager.Objects[ObjectIndex].RendererIndex = ObjectListCount + 1; ObjectListCount++; } }