diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index fa2b109971..18be2fd1fb 100755 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -143,7 +143,7 @@ namespace OpenRA { ++RenderFrame; viewport.DrawRegions(worldRenderer, new DefaultInputHandler( orderManager.world )); - Sound.SetListenerPosition(viewport.Location + .5f * new float2(viewport.Width, viewport.Height)); + Sound.SetListenerPosition(viewport.CenterLocation); } PerfHistory.items["render"].Tick(); diff --git a/OpenRA.Game/Graphics/Renderer.cs b/OpenRA.Game/Graphics/Renderer.cs index 1ccc61d433..c415638bf8 100644 --- a/OpenRA.Game/Graphics/Renderer.cs +++ b/OpenRA.Game/Graphics/Renderer.cs @@ -73,15 +73,15 @@ namespace OpenRA.Graphics internal IGraphicsDevice Device { get { return device; } } - public void BeginFrame(float2 scroll) + public void BeginFrame(float2 scroll, float zoom) { device.Clear(Color.Black); float2 r1 = new float2(2f/Resolution.Width, -2f/Resolution.Height); float2 r2 = new float2(-1, 1); - - SetShaderParams( WorldSpriteShader, r1, r2, scroll ); - SetShaderParams( WorldLineShader, r1, r2, scroll ); + var zr1 = zoom*r1; + SetShaderParams( WorldSpriteShader, zr1, r2, scroll ); + SetShaderParams( WorldLineShader, zr1, r2, scroll ); SetShaderParams( LineShader, r1, r2, scroll ); SetShaderParams( RgbaSpriteShader, r1, r2, scroll ); SetShaderParams( SpriteShader, r1, r2, scroll ); diff --git a/OpenRA.Game/Graphics/TerrainRenderer.cs b/OpenRA.Game/Graphics/TerrainRenderer.cs index a9d075a0ca..da570f0224 100644 --- a/OpenRA.Game/Graphics/TerrainRenderer.cs +++ b/OpenRA.Game/Graphics/TerrainRenderer.cs @@ -61,7 +61,7 @@ namespace OpenRA.Graphics { int verticesPerRow = map.Bounds.Width * 4; - int visibleRows = (int)(viewport.Height * 1f / Game.CellSize + 2); + int visibleRows = (int)(viewport.Height * 1f / Game.CellSize / viewport.Zoom + 2); int firstRow = (int)(viewport.Location.Y * 1f / Game.CellSize - map.Bounds.Top); int lastRow = firstRow + visibleRows; diff --git a/OpenRA.Game/Graphics/Viewport.cs b/OpenRA.Game/Graphics/Viewport.cs index 3939471a8b..c7261a1fac 100755 --- a/OpenRA.Game/Graphics/Viewport.cs +++ b/OpenRA.Game/Graphics/Viewport.cs @@ -34,10 +34,13 @@ namespace OpenRA.Graphics readonly Renderer renderer; readonly Rectangle adjustedMapBounds; + // Top-left of the viewport, in world-px units public float2 Location { get { return scrollPosition; } } + public float2 CenterLocation { get { return scrollPosition + 0.5f/Zoom*screenSize.ToFloat2(); } } public int Width { get { return screenSize.X; } } public int Height { get { return screenSize.Y; } } + public float Zoom = 1f; float cursorFrame = 0f; @@ -51,7 +54,8 @@ namespace OpenRA.Graphics public void Scroll(float2 delta, bool ignoreBorders) { - var d = delta.ToInt2(); + // Convert from world-px to viewport-px + var d = (1f/Zoom*delta).ToInt2(); var newScrollPosition = scrollPosition + d; if(!ignoreBorders) @@ -88,7 +92,7 @@ namespace OpenRA.Graphics public void DrawRegions( WorldRenderer wr, IInputHandler inputHandler ) { - renderer.BeginFrame(scrollPosition); + renderer.BeginFrame(scrollPosition, Zoom); if (wr != null) wr.Draw(); @@ -115,23 +119,20 @@ namespace OpenRA.Graphics { cursorFrame += 0.5f; } - + + // Convert from viewport coords to cell coords (not px) + public float2 ViewToWorld(MouseInput mi) { return ViewToWorld(mi.Location); } public float2 ViewToWorld(int2 loc) { - return (1f / Game.CellSize) * (loc.ToFloat2() + Location); + return (1f / Game.CellSize) * (1f/Zoom*loc.ToFloat2() + Location); } - public float2 ViewToWorld(MouseInput mi) - { - return ViewToWorld(mi.Location); - } - - public int2 ViewToWorldPx(int2 loc) { return loc + Location.ToInt2(); } + public int2 ViewToWorldPx(int2 loc) { return (1f/Zoom*loc.ToFloat2() + Location).ToInt2(); } public int2 ViewToWorldPx(MouseInput mi) { return ViewToWorldPx(mi.Location); } public void Center(float2 loc) { - scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - screenSize / 2).ToInt2()); + scrollPosition = this.NormalizeScrollPosition((Game.CellSize*loc - 1f/(2*Zoom)*screenSize.ToFloat2()).ToInt2()); } public void Center(IEnumerable actors) @@ -141,27 +142,26 @@ namespace OpenRA.Graphics var avgPos = actors .Select(a => a.CenterLocation) .Aggregate((a, b) => a + b) / actors.Count(); - scrollPosition = this.NormalizeScrollPosition((avgPos - screenSize / 2)); + scrollPosition = this.NormalizeScrollPosition((avgPos - 1f/(2*Zoom)*screenSize.ToFloat2()).ToInt2()); } + // Rectangle (in viewport coords) that contains things to be drawn public Rectangle ViewBounds(World world) { var r = WorldBounds(world); - var left = (int)(Game.CellSize * r.Left - Game.viewport.Location.X); - var top = (int)(Game.CellSize * r.Top - Game.viewport.Location.Y); - var right = left + (int)(Game.CellSize * r.Width); - var bottom = top + (int)(Game.CellSize * r.Height); - - if (left < 0) left = 0; - if (top < 0) top = 0; - if (right > Game.viewport.Width) right = Game.viewport.Width; - if (bottom > Game.viewport.Height) bottom = Game.viewport.Height; - return new Rectangle(left, top, right - left, bottom - top); + var origin = Location.ToInt2(); + var left = Math.Max(0, Game.CellSize * r.Left - origin.X)*Zoom; + var top = Math.Max(0, Game.CellSize * r.Top - origin.Y)*Zoom; + var right = Math.Min((Game.CellSize * r.Right - origin.X) * Zoom, Width); + var bottom = Math.Min((Game.CellSize * r.Bottom - origin.Y) * Zoom, Height); + + return Rectangle.FromLTRB((int)left, (int)top, (int)right, (int)bottom); } int2 cachedScroll = new int2(int.MaxValue, int.MaxValue); Rectangle cachedRect; + // Rectangle (in cell coords) of cells that are currently visible on the screen public Rectangle WorldBounds(World world) { if (cachedScroll != scrollPosition) @@ -169,6 +169,7 @@ namespace OpenRA.Graphics int2 boundary = new int2(1,1); // Add a curtain of cells around the viewport to account for rounding errors var tl = ViewToWorld(int2.Zero).ToInt2() - boundary; var br = ViewToWorld(new int2(Width, Height)).ToInt2() + boundary; + cachedRect = Rectangle.Intersect(Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y), world.Map.Bounds); cachedScroll = scrollPosition; } diff --git a/OpenRA.Game/Graphics/WorldRenderer.cs b/OpenRA.Game/Graphics/WorldRenderer.cs index 6ea8fd2727..97f1fce031 100644 --- a/OpenRA.Game/Graphics/WorldRenderer.cs +++ b/OpenRA.Game/Graphics/WorldRenderer.cs @@ -52,14 +52,12 @@ namespace OpenRA.Graphics IEnumerable SpritesToRender() { - var bounds = Game.viewport.ViewBounds(world); + var bounds = Game.viewport.WorldBounds(world); var comparer = new SpriteComparer(); - bounds.Offset((int)Game.viewport.Location.X, (int)Game.viewport.Location.Y); - var actors = world.FindUnits( - new int2(bounds.Left, bounds.Top), - new int2(bounds.Right, bounds.Bottom)); + new int2(Game.CellSize*bounds.Left, Game.CellSize*bounds.Top), + new int2(Game.CellSize*bounds.Right, Game.CellSize*bounds.Bottom)); var renderables = actors.SelectMany(a => a.Render()) .OrderBy(r => r, comparer); diff --git a/OpenRA.Game/Traits/World/ScreenShaker.cs b/OpenRA.Game/Traits/World/ScreenShaker.cs index c6b9d0ddfa..23ba50ffc4 100644 --- a/OpenRA.Game/Traits/World/ScreenShaker.cs +++ b/OpenRA.Game/Traits/World/ScreenShaker.cs @@ -48,9 +48,7 @@ namespace OpenRA.Traits float GetIntensity() { - var cp = Game.viewport.Location - + .5f * new float2(Game.viewport.Width, Game.viewport.Height); - + var cp = Game.viewport.CenterLocation; var intensity = Game.CellSize * Game.CellSize * 100 * shakeEffects.Sum( e => e.Intensity / (e.Position - cp).LengthSquared); diff --git a/OpenRA.Mods.Cnc/CncLoadScreen.cs b/OpenRA.Mods.Cnc/CncLoadScreen.cs index 205f6f505e..617ba966d6 100644 --- a/OpenRA.Mods.Cnc/CncLoadScreen.cs +++ b/OpenRA.Mods.Cnc/CncLoadScreen.cs @@ -71,7 +71,7 @@ namespace OpenRA.Mods.Cnc loadTimer.Reset(); loadTick = ++loadTick % 8; - r.BeginFrame(float2.Zero); + r.BeginFrame(float2.Zero, 1f); r.RgbaSpriteRenderer.DrawSprite(gdiLogo, gdiPos); r.RgbaSpriteRenderer.DrawSprite(nodLogo, nodPos); r.RgbaSpriteRenderer.DrawSprite(evaLogo, evaPos); diff --git a/OpenRA.Mods.RA/Effects/CashTick.cs b/OpenRA.Mods.RA/Effects/CashTick.cs index 33212e4968..57947dbc4a 100644 --- a/OpenRA.Mods.RA/Effects/CashTick.cs +++ b/OpenRA.Mods.RA/Effects/CashTick.cs @@ -20,7 +20,7 @@ namespace OpenRA.Mods.RA.Effects string s; int remaining; int velocity; - float2 pos; + float2 pos, offset; Color color; public CashTick(int value, int lifetime, int velocity, float2 pos, Color color) @@ -28,7 +28,8 @@ namespace OpenRA.Mods.RA.Effects this.color = color; this.velocity = velocity; s = "{0}${1}".F(value < 0 ? "-" : "+", value); - this.pos = pos - 0.5f*Game.Renderer.Fonts["TinyBold"].Measure(s).ToFloat2(); + this.pos = pos; + offset = 0.5f*Game.Renderer.Fonts["TinyBold"].Measure(s).ToFloat2(); remaining = lifetime; } @@ -41,7 +42,7 @@ namespace OpenRA.Mods.RA.Effects public IEnumerable Render() { - Game.Renderer.Fonts["TinyBold"].DrawTextWithContrast(s, pos - Game.viewport.Location, color, Color.Black,1); + Game.Renderer.Fonts["TinyBold"].DrawTextWithContrast(s, Game.viewport.Zoom*(pos - Game.viewport.Location) - offset, color, Color.Black,1); yield break; } } diff --git a/OpenRA.Mods.RA/NullLoadScreen.cs b/OpenRA.Mods.RA/NullLoadScreen.cs index 1952476e8a..c58134f50b 100644 --- a/OpenRA.Mods.RA/NullLoadScreen.cs +++ b/OpenRA.Mods.RA/NullLoadScreen.cs @@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA return; // Draw a black screen - Game.Renderer.BeginFrame(float2.Zero); + Game.Renderer.BeginFrame(float2.Zero, 1f); Game.Renderer.EndFrame( new NullInputHandler() ); } diff --git a/OpenRA.Mods.RA/RALoadScreen.cs b/OpenRA.Mods.RA/RALoadScreen.cs index 4186a6ccf0..d66f1a32ed 100644 --- a/OpenRA.Mods.RA/RALoadScreen.cs +++ b/OpenRA.Mods.RA/RALoadScreen.cs @@ -58,7 +58,7 @@ namespace OpenRA.Mods.RA var text = Comments.Random(Game.CosmeticRandom); var textSize = r.Fonts["Bold"].Measure(text); - r.BeginFrame(float2.Zero); + r.BeginFrame(float2.Zero, 1f); WidgetUtils.FillRectWithSprite(StripeRect, Stripe); r.RgbaSpriteRenderer.DrawSprite(Logo, LogoPos); r.Fonts["Bold"].DrawText(text, new float2(Renderer.Resolution.Width - textSize.X - 20, Renderer.Resolution.Height - textSize.Y - 20), Color.White); diff --git a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs index d363564e8e..29c927148b 100755 --- a/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/RadarBinWidget.cs @@ -129,27 +129,28 @@ namespace OpenRA.Mods.RA.Widgets if( world == null || world.LocalPlayer == null ) return; radarCollection = "radar-" + world.LocalPlayer.Country.Race; - - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "left"), radarOrigin); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "right"), radarOrigin + new float2(201, 0)); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bottom"), radarOrigin + new float2(0, 192)); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(ChromeProvider.GetImage(radarCollection, "bg"), radarOrigin + new float2(9, 0)); + var rsr = Game.Renderer.RgbaSpriteRenderer; + rsr.DrawSprite(ChromeProvider.GetImage(radarCollection, "left"), radarOrigin); + rsr.DrawSprite(ChromeProvider.GetImage(radarCollection, "right"), radarOrigin + new float2(201, 0)); + rsr.DrawSprite(ChromeProvider.GetImage(radarCollection, "bottom"), radarOrigin + new float2(0, 192)); + rsr.DrawSprite(ChromeProvider.GetImage(radarCollection, "bg"), radarOrigin + new float2(9, 0)); // Don't draw the radar if the tray is moving if (radarAnimationFrame >= radarSlideAnimationLength) { var o = new float2(mapRect.Location.X, mapRect.Location.Y + world.Map.Bounds.Height * previewScale * (1 - radarMinimapHeight)/2); var s = new float2(mapRect.Size.Width, mapRect.Size.Height*radarMinimapHeight); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(terrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(customTerrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(actorSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(shroudSprite, o, s); + rsr.DrawSprite(terrainSprite, o, s); + rsr.DrawSprite(customTerrainSprite, o, s); + rsr.DrawSprite(actorSprite, o, s); + rsr.DrawSprite(shroudSprite, o, s); // Draw viewport rect if (radarAnimationFrame == radarSlideAnimationLength + radarActivateAnimationLength) { var tl = CellToMinimapPixel(new int2((int)(Game.viewport.Location.X/Game.CellSize), (int)(Game.viewport.Location.Y/Game.CellSize))); var br = CellToMinimapPixel(new int2((int)((Game.viewport.Location.X + Game.viewport.Width)/Game.CellSize), (int)((Game.viewport.Location.Y + Game.viewport.Height)/Game.CellSize))); + Game.Renderer.EnableScissor((int)mapRect.Left, (int)mapRect.Top, (int)mapRect.Width, (int)mapRect.Height); Game.Renderer.LineRenderer.DrawRect(tl, br, Color.White); Game.Renderer.DisableScissor(); diff --git a/OpenRA.Mods.RA/Widgets/RadarWidget.cs b/OpenRA.Mods.RA/Widgets/RadarWidget.cs index aa9c2369a5..1a785a6bd4 100755 --- a/OpenRA.Mods.RA/Widgets/RadarWidget.cs +++ b/OpenRA.Mods.RA/Widgets/RadarWidget.cs @@ -129,10 +129,11 @@ namespace OpenRA.Mods.RA.Widgets var o = new float2(mapRect.Location.X, mapRect.Location.Y + world.Map.Bounds.Height * previewScale * (1 - radarMinimapHeight)/2); var s = new float2(mapRect.Size.Width, mapRect.Size.Height*radarMinimapHeight); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(terrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(customTerrainSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(actorSprite, o, s); - Game.Renderer.RgbaSpriteRenderer.DrawSprite(shroudSprite, o, s); + var rsr = Game.Renderer.RgbaSpriteRenderer; + rsr.DrawSprite(terrainSprite, o, s); + rsr.DrawSprite(customTerrainSprite, o, s); + rsr.DrawSprite(actorSprite, o, s); + rsr.DrawSprite(shroudSprite, o, s); // Draw viewport rect if (hasRadar && !Animating)