/// <summary>Checks if a block specified by its bounding rectangle intersects any of the specified triangles.</summary> /// <param name="block">The bounding rectangle of the block.</param> /// <param name="triangles">An array of triangles that was obtained from a call to InitializeBlockClipping.</param> /// <returns>Whether the block intersects any of the triangles.</returns> private static bool BlockIntersectsTriangles(ObjectGrid.GridBounds block, Triangle[] triangles) { for (int i = 0; i < triangles.Length; i++) { if (BlockIntersectsTriangle(block, triangles[i])) { return true; } } return false; }
/// <summary>Renders the objects attached to a specified populated leaf node.</summary> /// <param name="leaf">The leaf node to render.</param> private static void RenderGridLeafNode(ObjectGrid.GridPopulatedLeafNode leaf, bool includeVisibleLeafNodes) { /* Create the display list for the leaf node if not yet available. */ if (leaf.DisplayList.IsUnavailable()) { leaf.CreateOrUpdateDisplayList(); } /* Render the leaf node if the display list is available. */ if (leaf.DisplayList.IsAvailable()) { double x = 0.5 * (leaf.Rectangle.Left + leaf.Rectangle.Right) - Camera.GridLeafNodeCenter.X; double y = -Camera.GridLeafNodeCenter.Y; double z = 0.5 * (leaf.Rectangle.Near + leaf.Rectangle.Far) - Camera.GridLeafNodeCenter.Z; Gl.glPushMatrix(); Gl.glTranslated(x, y, z); leaf.DisplayList.Call(); Gl.glPopMatrix(); } }
/// <summary>Checks if a block specified by its bounding rectangle intersects a specified triangle.</summary> /// <param name="block">The bounding rectangle of the block.</param> /// <param name="triangles">The triangle.</param> /// <returns>Whether the block intersects the triangle.</returns> private static bool BlockIntersectsTriangle(ObjectGrid.GridBounds block, Triangle triangle) { /* * First, let's check if the bounding rectangle of the * block intersects the bounding rectangle of the * triangle. If so, we need further checks to ensure * that the actual triangle intersects the block, * but if not, the triangle cannot intersect the block. * */ if ( block.Left <= triangle.BoundingRectangle.Right & block.Right >= triangle.BoundingRectangle.Left & block.Near <= triangle.BoundingRectangle.Far & block.Far >= triangle.BoundingRectangle.Near ) { /* * The bounding rectangles intersect. This means that * the triangle could intersect the block, but not * necessarily. First, let's check if any point of * the triangle lies inside the rectangle. * */ if ( triangle.PointA.X >= block.Left && triangle.PointA.X <= block.Right && triangle.PointA.Y >= block.Near && triangle.PointA.Y <= block.Far ) { return true; } else if ( triangle.PointB.X >= block.Left && triangle.PointB.X <= block.Right && triangle.PointB.Y >= block.Near && triangle.PointB.Y <= block.Far ) { return true; } else if ( triangle.PointC.X >= block.Left && triangle.PointC.X <= block.Right && triangle.PointC.Y >= block.Near && triangle.PointC.Y <= block.Far ) { return true; } else { /* * There is no point of the triangle that lies inside * the rectangle. Now, let's check if any point of the * rectangle lies inside the triangle. * */ if (IsPointInTriangle(new OpenBveApi.Math.Vector2(block.Left, block.Near), triangle)) { return true; } else if (IsPointInTriangle(new OpenBveApi.Math.Vector2(block.Left, block.Far), triangle)) { return true; } else if (IsPointInTriangle(new OpenBveApi.Math.Vector2(block.Right, block.Far), triangle)) { return true; } else if (IsPointInTriangle(new OpenBveApi.Math.Vector2(block.Right, block.Near), triangle)) { return true; } else { /* No point of the rectangle lies inside the triangle. * Now, let's check each edge of the triangle against * each edge of the rectangle for intersection. * */ for (int i = 0; i < 3; i++) { OpenBveApi.Math.Vector2 a; OpenBveApi.Math.Vector2 b; if (i == 0) { a = triangle.PointA; b = triangle.PointB; } else if (i == 1) { a = triangle.PointB; b = triangle.PointC; } else { a = triangle.PointC; b = triangle.PointA; } /* * Compare the current triangle edge against the * left and right vertical edges of the rectangle. * */ { double denominator = a.X - b.X; if (denominator == 0.0) { if (a.X >= block.Left & a.X <= block.Right) { if (a.Y <= block.Near & b.Y >= block.Far | a.Y >= block.Far & b.Y <= block.Near) { return true; } } } else { for (int j = 0; j < 2; j++) { double px = j == 0 ? block.Left : block.Right; double numerator = a.Y * (px - b.X) - b.Y * (px - a.X); double py = numerator / denominator; if (py >= block.Near & py <= block.Far) { double r = (px - a.X) / (b.X - a.X); if (r >= 0.0 & r <= 1.0) { return true; } } } } } /* * Compare the current triangle edge against the * near and far horizontal edges of the rectangle. * */ { double denominator = a.Y - b.Y; if (denominator == 0.0) { if (a.Y >= block.Near & a.Y <= block.Far) { if (a.X <= block.Left & b.X >= block.Right | a.X >= block.Right & b.X <= block.Left) { return true; } } } else { for (int j = 0; j < 2; j++) { double py = j == 0 ? block.Near : block.Far; double numerator = a.X * (py - b.Y) - b.X * (py - a.Y); double px = numerator / denominator; if (px >= block.Left & px <= block.Right) { double r = (py - a.Y) / (b.Y - a.Y); if (r >= 0.0 & r <= 1.0) { return true; } } } } } } /* * No point of the triangle lies inside the rectangle, * no point of the rectangle lies inside the triangle, * and no triangle edge intersects with a rectangle * edge. Thus, the triangle does not intersect the * rectangle. * */ return false; } } } else { /* * The bounding rectangles do not intersect. The * triangle itself thus cannot intersect the block. * */ return false; } }
/// <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); } } } }