/// <summary>Renders the opaque part of a set of specified static objects.</summary> /// <param name="objects">The list of static objects.</param> /// <param name="count">The number of static objects.</param> /// <param name="count">The current OpenGL state.</param> /// <remarks>This function may change the texture or emissive color in the current OpenGL state.</remarks> internal static void RenderStaticOpaqueObjects(ObjectGrid.StaticOpaqueObject[] objects, int count, ref OpenGlState state) { /* * Count the number of faces. * */ int faceCount = 0; for (int i = 0; i < count; i++) { OpenBveApi.Geometry.FaceVertexMesh mesh = ObjectLibrary.Library.Objects[objects[i].LibraryIndex] as OpenBveApi.Geometry.FaceVertexMesh; if (mesh != null) { faceCount += mesh.Faces.Length; } } /* * Sort the faces by shared material properties. This will later increase * rendering speed as fewer state changes will be involved in OpenGL. * */ Face[] faces = new Face[faceCount]; long[] keys = new long[faceCount]; faceCount = 0; for (int i = 0; i < count; i++) { OpenBveApi.Geometry.FaceVertexMesh mesh = ObjectLibrary.Library.Objects[objects[i].LibraryIndex] as OpenBveApi.Geometry.FaceVertexMesh; if (mesh != null) { for (int j = 0; j < mesh.Faces.Length; j++) { int material = mesh.Faces[j].Material; long texture = mesh.Materials[material].DaytimeTexture is Textures.ApiHandle ? (long)(((Textures.ApiHandle)mesh.Materials[material].DaytimeTexture).TextureIndex) + 1 : (long)0; long emissive = (long)(255.0f * mesh.Materials[material].EmissiveColor.R) | (long)(255.0f * mesh.Materials[material].EmissiveColor.G) << 8 | (long)(255.0f * mesh.Materials[material].EmissiveColor.B) << 16; faces[faceCount] = new Face(i, j); keys[faceCount] = texture | emissive << 32; faceCount++; } } } Array.Sort<long, Face>(keys, faces); /* * Render the faces. * */ state.SetAlphaFunction(Gl.GL_EQUAL, 1.0f); for (int i = 0; i < faceCount; i++) { int objectIndex = faces[i].ObjectIndex; OpenBveApi.Geometry.FaceVertexMesh mesh = ObjectLibrary.Library.Objects[objects[objectIndex].LibraryIndex] as OpenBveApi.Geometry.FaceVertexMesh; if (mesh != null) { int material = mesh.Faces[faces[i].FaceIndex].Material; if (mesh.Materials[material].BlendMode == OpenBveApi.Geometry.BlendMode.Normal) { RenderFace(mesh, faces[i].FaceIndex, objects[objectIndex].GridPosition, objects[objectIndex].GridOrientation, ref state); } } } }
// --- render a single face --- /// <summary>Renders a face of a face-vertex mesh.</summary> /// <param name="mesh">The face-vertex mesh.</param> /// <param name="faceIndex">The face of the mesh to render.</param> /// <param name="position">The position of the face.</param> /// <param name="orientation">The orientation of the face.</param> /// <param name="state">The current OpenGL state.</param> /// <remarks>This function may change the texture or emissive color in the current OpenGL state.</remarks> private static void RenderFace(OpenBveApi.Geometry.FaceVertexMesh mesh, int faceIndex, OpenBveApi.Math.Vector3 position, OpenBveApi.Math.Orientation3 orientation, ref OpenGlState state) { int material = mesh.Faces[faceIndex].Material; /* * Set the texture. * */ Textures.ApiHandle apiHandle = mesh.Materials[material].DaytimeTexture as Textures.ApiHandle; int textureIndex = apiHandle != null ? apiHandle.TextureIndex : -1; if (textureIndex >= 0 && Textures.RegisteredTextures[textureIndex].Status == Textures.TextureStatus.Loaded) { int openGlTextureIndex = Textures.RegisteredTextures[textureIndex].OpenGlTextureIndex; state.BindTexture(openGlTextureIndex); } else { state.UnbindTexture(); } /* * Begin rendering the face. * */ switch (mesh.Faces[faceIndex].Type) { case OpenBveApi.Geometry.FaceType.Triangles: Gl.glBegin(Gl.GL_TRIANGLES); break; case OpenBveApi.Geometry.FaceType.TriangleStrip: Gl.glBegin(Gl.GL_TRIANGLE_STRIP); break; case OpenBveApi.Geometry.FaceType.TriangleFan: Gl.glBegin(Gl.GL_TRIANGLE_FAN); break; case OpenBveApi.Geometry.FaceType.Quads: Gl.glBegin(Gl.GL_QUADS); break; case OpenBveApi.Geometry.FaceType.QuadStrip: Gl.glBegin(Gl.GL_QUAD_STRIP); break; case OpenBveApi.Geometry.FaceType.Polygon: Gl.glBegin(Gl.GL_POLYGON); break; default: throw new InvalidOperationException(); } /* * Set the emissive color. * */ OpenBveApi.Color.ColorRGB emissiveColor = mesh.Materials[material].EmissiveColor; state.SetEmissiveColor(emissiveColor); /* * Render the vertices of the face. * */ for (int j = 0; j < mesh.Faces[faceIndex].Vertices.Length; j++) { int vertex = mesh.Faces[faceIndex].Vertices[j]; OpenBveApi.Math.Vector3 spatialCoordinates = mesh.Vertices[vertex].SpatialCoordinates; spatialCoordinates.Rotate(orientation); spatialCoordinates.Translate(position); OpenBveApi.Math.Vector3 normal = mesh.Vertices[vertex].Normal; normal.Rotate(orientation); Gl.glColor4f(mesh.Vertices[vertex].ReflectiveColor.R, mesh.Vertices[vertex].ReflectiveColor.G, mesh.Vertices[vertex].ReflectiveColor.B, mesh.Vertices[vertex].ReflectiveColor.A); Gl.glNormal3d(normal.X, normal.Y, normal.Z); Gl.glTexCoord2d(mesh.Vertices[vertex].TextureCoordinates.X, mesh.Vertices[vertex].TextureCoordinates.Y); Gl.glVertex3d(spatialCoordinates.X, spatialCoordinates.Y, spatialCoordinates.Z); } /* * End rendering the face. * */ Gl.glEnd(); }
// --- render specific kinds of objects --- /// <summary>Renders a solid-color polygon from an array of vertices.</summary> /// <param name="vertices">The vertices that describe the polygon.</param> /// <param name="reflectiveColor">The reflective color.</param> /// <param name="emissiveColor">The emissive color.</param> /// <remarks>This function may unbind the texture or change the emissive color in the current OpenGL state.</remarks> internal static void RenderPolygonFromVertices(OpenBveApi.Math.Vector3[] vertices, OpenBveApi.Color.ColorRGB reflectiveColor, OpenBveApi.Color.ColorRGB emissiveColor, ref OpenGlState state) { /* * Begin rendering the polygon. * */ state.UnbindTexture(); Gl.glBegin(Gl.GL_POLYGON); state.SetEmissiveColor(emissiveColor); /* * Render the vertices. * */ OpenBveApi.Math.Vector3 normal; OpenBveApi.Math.Vector3.CreateNormal(vertices[0], vertices[1], vertices[2], out normal); for (int i = 0; i < vertices.Length; i++) { Gl.glColor3f(reflectiveColor.R, reflectiveColor.G, reflectiveColor.B); Gl.glNormal3d(normal.X, normal.Y, normal.Z); Gl.glVertex3d(vertices[i].X, vertices[i].Y, vertices[i].Z); } /* * End rendering the polygon. * */ Gl.glEnd(); }