public static void UpdateVertices(Camera cam, WaterRenderer renderer) { foreach (EntityGrid entityGrid in EntityGrids) { if (entityGrid.WorldRect.X > cam.WorldView.Right || entityGrid.WorldRect.Right < cam.WorldView.X) { continue; } if (entityGrid.WorldRect.Y - entityGrid.WorldRect.Height > cam.WorldView.Y || entityGrid.WorldRect.Y < cam.WorldView.Y - cam.WorldView.Height) { continue; } var allEntities = entityGrid.GetAllEntities(); foreach (Hull hull in allEntities) { hull.UpdateVertices(cam, entityGrid, renderer); } } }
private void UpdateVertices(Camera cam, EntityGrid entityGrid, WaterRenderer renderer) { Vector2 submarinePos = Submarine == null ? Vector2.Zero : Submarine.DrawPosition; //if there's no more space in the buffer, don't render the water in the hull //not an ideal solution, but this seems to only happen in cases where the missing //water is not very noticeable (e.g. zoomed very far out so that multiple subs and ruins are visible) if (renderer.PositionInBuffer > renderer.vertices.Length - 6) { return; } if (!renderer.IndoorsVertices.ContainsKey(entityGrid)) { renderer.IndoorsVertices[entityGrid] = new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize]; renderer.PositionInIndoorsBuffer[entityGrid] = 0; } //calculate where the surface should be based on the water volume float top = rect.Y + submarinePos.Y; float bottom = top - rect.Height; float renderSurface = drawSurface + submarinePos.Y; if (bottom > cam.WorldView.Y || top < cam.WorldView.Y - cam.WorldView.Height) { return; } Matrix transform = cam.Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f; if (!update) { // create the four corners of our triangle. Vector3[] corners = new Vector3[4]; corners[0] = new Vector3(rect.X, rect.Y, 0.0f); corners[1] = new Vector3(rect.X + rect.Width, rect.Y, 0.0f); corners[2] = new Vector3(corners[1].X, rect.Y - rect.Height, 0.0f); corners[3] = new Vector3(corners[0].X, corners[2].Y, 0.0f); Vector2[] uvCoords = new Vector2[4]; for (int i = 0; i < 4; i++) { corners[i] += new Vector3(submarinePos, 0.0f); uvCoords[i] = Vector2.Transform(new Vector2(corners[i].X, -corners[i].Y), transform); } renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(corners[0], uvCoords[0]); renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]); renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(corners[0], uvCoords[0]); renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(corners[3], uvCoords[3]); renderer.PositionInBuffer += 6; return; } float x = rect.X; if (Submarine != null) { x += Submarine.DrawPosition.X; } int start = (int)Math.Floor((cam.WorldView.X - x) / WaveWidth); start = Math.Max(start, 0); int end = (waveY.Length - 1) - (int)Math.Floor(((x + rect.Width) - (cam.WorldView.Right)) / WaveWidth); end = Math.Min(end, waveY.Length - 1); x += start * WaveWidth; Vector3[] prevCorners = new Vector3[2]; Vector2[] prevUVs = new Vector2[2]; int width = WaveWidth; for (int i = start; i < end; i++) { Vector3[] corners = new Vector3[6]; //top left corners[0] = new Vector3(x, top, 0.0f); //watersurface left corners[3] = new Vector3(corners[0].X, renderSurface + waveY[i], 0.0f); //top right corners[1] = new Vector3(x + width, top, 0.0f); //watersurface right corners[2] = new Vector3(corners[1].X, renderSurface + waveY[i + 1], 0.0f); //bottom left corners[4] = new Vector3(x, bottom, 0.0f); //bottom right corners[5] = new Vector3(x + width, bottom, 0.0f); Vector2[] uvCoords = new Vector2[4]; for (int n = 0; n < 4; n++) { uvCoords[n] = Vector2.Transform(new Vector2(corners[n].X, -corners[n].Y), transform); } if (renderer.PositionInBuffer <= renderer.vertices.Length - 6) { if (i == start) { prevCorners[0] = corners[0]; prevCorners[1] = corners[3]; prevUVs[0] = uvCoords[0]; prevUVs[1] = uvCoords[3]; } //we only create a new quad if this is the first or the last one, of if there's a wave large enough that we need more geometry if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[2].Y) > 0.01f) { renderer.vertices[renderer.PositionInBuffer] = new VertexPositionTexture(prevCorners[0], prevUVs[0]); renderer.vertices[renderer.PositionInBuffer + 1] = new VertexPositionTexture(corners[1], uvCoords[1]); renderer.vertices[renderer.PositionInBuffer + 2] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 3] = new VertexPositionTexture(prevCorners[0], prevUVs[0]); renderer.vertices[renderer.PositionInBuffer + 4] = new VertexPositionTexture(corners[2], uvCoords[2]); renderer.vertices[renderer.PositionInBuffer + 5] = new VertexPositionTexture(prevCorners[1], prevUVs[1]); prevCorners[0] = corners[1]; prevCorners[1] = corners[2]; prevUVs[0] = uvCoords[1]; prevUVs[1] = uvCoords[2]; renderer.PositionInBuffer += 6; } } if (renderer.PositionInIndoorsBuffer[entityGrid] <= renderer.IndoorsVertices[entityGrid].Length - 12 && cam.Zoom > 0.6f) { const float SurfaceSize = 10.0f; const float SineFrequency1 = 0.01f; const float SineFrequency2 = 0.05f; //surface shrinks and finally disappears when the water level starts to reach the top of the hull float surfaceScale = 1.0f - MathHelper.Clamp(corners[3].Y - (top - SurfaceSize), 0.0f, 1.0f); Vector3 surfaceOffset = new Vector3(0.0f, -SurfaceSize, 0.0f); surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2; surfaceOffset.Y += (float)Math.Sin((rect.X + i * WaveWidth) * SineFrequency2 - renderer.WavePos.X) * 2; surfaceOffset *= surfaceScale; Vector3 surfaceOffset2 = new Vector3(0.0f, -SurfaceSize, 0.0f); surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency1 + renderer.WavePos.X * 0.25f) * 2; surfaceOffset2.Y += (float)Math.Sin((rect.X + i * WaveWidth + width) * SineFrequency2 - renderer.WavePos.X) * 2; surfaceOffset2 *= surfaceScale; int posInBuffer = renderer.PositionInIndoorsBuffer[entityGrid]; renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[5], renderer.IndoorsWaterColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[4], renderer.IndoorsWaterColor, Vector2.Zero); posInBuffer += 6; renderer.PositionInIndoorsBuffer[entityGrid] = posInBuffer; if (surfaceScale > 0) { renderer.IndoorsVertices[entityGrid][posInBuffer + 0] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 1] = new VertexPositionColorTexture(corners[2], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 2] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 3] = new VertexPositionColorTexture(corners[3], renderer.IndoorsSurfaceTopColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 4] = new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.IndoorsVertices[entityGrid][posInBuffer + 5] = new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.IndoorsSurfaceBottomColor, Vector2.Zero); renderer.PositionInIndoorsBuffer[entityGrid] += 6; } } x += WaveWidth; //clamp the last segment to the right edge of the hull if (i == end - 2) { width -= (int)Math.Max((x + WaveWidth) - (Submarine == null ? rect.Right : (rect.Right + Submarine.DrawPosition.X)), 0); } } }