PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/OpenRA.Editor/Surface.cs

https://github.com/jeff-1amstudios/OpenRA
C# | 390 lines | 298 code | 84 blank | 8 comment | 70 complexity | acbbf0551b9b805de40cda4a8346e37c MD5 | raw file
  1. #region Copyright & License Information
  2. /*
  3. * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
  4. * This file is part of OpenRA, which is free software. It is made
  5. * available to you under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation. For more information,
  7. * see COPYING.
  8. */
  9. #endregion
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Drawing;
  13. using System.Drawing.Imaging;
  14. using System.Linq;
  15. using System.Windows.Forms;
  16. using OpenRA.FileFormats;
  17. using OpenRA.Traits;
  18. using SGraphics = System.Drawing.Graphics;
  19. namespace OpenRA.Editor
  20. {
  21. class Surface : Control
  22. {
  23. public Map Map { get; private set; }
  24. public TileSet TileSet { get; private set; }
  25. public Palette Palette { get; private set; }
  26. public int2 Offset;
  27. public int2 GetOffset() { return Offset; }
  28. public float Zoom = 1.0f;
  29. ITool Tool;
  30. public bool IsPanning;
  31. public bool ShowActorNames;
  32. public event Action AfterChange = () => { };
  33. public event Action<string> MousePositionChanged = _ => { };
  34. Dictionary<string, ActorTemplate> ActorTemplates = new Dictionary<string, ActorTemplate>();
  35. Dictionary<int, ResourceTemplate> ResourceTemplates = new Dictionary<int, ResourceTemplate>();
  36. public Keys GetModifiers() { return ModifierKeys; }
  37. public void Bind(Map m, TileSet ts, Palette p)
  38. {
  39. Map = m;
  40. TileSet = ts;
  41. Palette = p;
  42. PlayerPalettes = null;
  43. Chunks.Clear();
  44. Tool = null;
  45. }
  46. public void SetTool(ITool tool) { Tool = tool; }
  47. public void BindActorTemplates(IEnumerable<ActorTemplate> templates)
  48. {
  49. ActorTemplates = templates.ToDictionary(a => a.Info.Name.ToLowerInvariant());
  50. }
  51. public void BindResourceTemplates(IEnumerable<ResourceTemplate> templates)
  52. {
  53. ResourceTemplates = templates.ToDictionary(a => a.Info.ResourceType);
  54. }
  55. public Dictionary<int2, Bitmap> Chunks = new Dictionary<int2, Bitmap>();
  56. public Surface()
  57. : base()
  58. {
  59. BackColor = Color.Black;
  60. SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
  61. SetStyle(ControlStyles.ResizeRedraw, true);
  62. UpdateStyles();
  63. }
  64. static readonly Pen CordonPen = new Pen(Color.Red);
  65. int2 MousePos;
  66. public void Scroll(int2 dx)
  67. {
  68. Offset -= dx;
  69. Invalidate();
  70. }
  71. protected override void OnMouseWheel(MouseEventArgs e)
  72. {
  73. base.OnMouseWheel(e);
  74. if (Map == null) return;
  75. Zoom *= e.Delta > 0 ? 4.0f / 3.0f : .75f;
  76. Invalidate();
  77. }
  78. protected override void OnMouseLeave(EventArgs e)
  79. {
  80. base.OnMouseLeave(e);
  81. this.Parent.Focus();
  82. Invalidate();
  83. }
  84. protected override void OnMouseEnter(EventArgs e)
  85. {
  86. base.OnMouseLeave(e);
  87. this.Focus();
  88. Invalidate();
  89. }
  90. protected override void OnMouseMove(MouseEventArgs e)
  91. {
  92. base.OnMouseMove(e);
  93. if (Map == null) return;
  94. var oldMousePos = MousePos;
  95. MousePos = new int2(e.Location);
  96. MousePositionChanged(GetBrushLocation().ToString());
  97. if (e.Button == MouseButtons.Middle || (e.Button != MouseButtons.None && IsPanning))
  98. Scroll(oldMousePos - MousePos);
  99. else
  100. {
  101. if (e.Button == MouseButtons.Right)
  102. Erase();
  103. if (e.Button == MouseButtons.Left)
  104. Draw();
  105. Invalidate();
  106. }
  107. }
  108. void Erase()
  109. {
  110. // Crash preventing
  111. var BrushLocation = GetBrushLocation();
  112. if (Map == null || BrushLocation.X >= Map.MapSize.X ||
  113. BrushLocation.Y >= Map.MapSize.Y ||
  114. BrushLocation.X < 0 ||
  115. BrushLocation.Y < 0)
  116. return;
  117. Tool = null;
  118. var key = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == BrushLocation);
  119. if (key.Key != null) Map.Actors.Value.Remove(key.Key);
  120. if (Map.MapResources.Value[BrushLocation.X, BrushLocation.Y].type != 0)
  121. {
  122. Map.MapResources.Value[BrushLocation.X, BrushLocation.Y] = new TileReference<byte, byte>();
  123. var ch = new int2((BrushLocation.X) / ChunkSize, (BrushLocation.Y) / ChunkSize);
  124. if (Chunks.ContainsKey(ch))
  125. {
  126. Chunks[ch].Dispose();
  127. Chunks.Remove(ch);
  128. }
  129. }
  130. AfterChange();
  131. }
  132. void Draw()
  133. {
  134. if (Tool != null) Tool.Apply(this);
  135. AfterChange();
  136. }
  137. protected override void OnMouseDown(MouseEventArgs e)
  138. {
  139. base.OnMouseDown(e);
  140. if (Map == null) return;
  141. if (!IsPanning)
  142. {
  143. if (e.Button == MouseButtons.Right) Erase();
  144. if (e.Button == MouseButtons.Left) Draw();
  145. }
  146. Invalidate();
  147. }
  148. public const int ChunkSize = 8; // 8x8 chunks ==> 192x192 bitmaps.
  149. Bitmap RenderChunk(int u, int v)
  150. {
  151. var bitmap = new Bitmap(ChunkSize * TileSet.TileSize, ChunkSize * TileSet.TileSize);
  152. bitmap.SetPixel(0, 0, Color.Green);
  153. var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
  154. ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
  155. unsafe
  156. {
  157. int* p = (int*)data.Scan0.ToPointer();
  158. var stride = data.Stride >> 2;
  159. for (var i = 0; i < ChunkSize; i++)
  160. for (var j = 0; j < ChunkSize; j++)
  161. {
  162. var tr = Map.MapTiles.Value[u * ChunkSize + i, v * ChunkSize + j];
  163. var tile = TileSet.Tiles[tr.type];
  164. var index = (tr.index < tile.TileBitmapBytes.Count) ? tr.index : (byte)0;
  165. var rawImage = tile.TileBitmapBytes[index];
  166. for (var x = 0; x < TileSet.TileSize; x++)
  167. for (var y = 0; y < TileSet.TileSize; y++)
  168. p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = Palette.GetColor(rawImage[x + TileSet.TileSize * y]).ToArgb();
  169. if (Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type != 0)
  170. {
  171. var resourceImage = ResourceTemplates[Map.MapResources.Value[u * ChunkSize + i, v * ChunkSize + j].type].Bitmap;
  172. var srcdata = resourceImage.LockBits(new Rectangle(0, 0, resourceImage.Width, resourceImage.Height),
  173. ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  174. int* q = (int*)srcdata.Scan0.ToPointer();
  175. var srcstride = srcdata.Stride >> 2;
  176. for (var x = 0; x < TileSet.TileSize; x++)
  177. for (var y = 0; y < TileSet.TileSize; y++)
  178. {
  179. var c = q[y * srcstride + x];
  180. if ((c & 0xff000000) != 0) /* quick & dirty, i cbf doing real alpha */
  181. p[(j * TileSet.TileSize + y) * stride + i * TileSet.TileSize + x] = c;
  182. }
  183. resourceImage.UnlockBits(srcdata);
  184. }
  185. }
  186. }
  187. bitmap.UnlockBits(data);
  188. return bitmap;
  189. }
  190. public int2 GetBrushLocation()
  191. {
  192. var vX = (int)Math.Floor((MousePos.X - Offset.X) / Zoom);
  193. var vY = (int)Math.Floor((MousePos.Y - Offset.Y) / Zoom);
  194. return new int2(vX / TileSet.TileSize, vY / TileSet.TileSize);
  195. }
  196. public void DrawActor(SGraphics g, int2 p, ActorTemplate t, ColorPalette cp)
  197. {
  198. var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
  199. DrawImage(g, t.Bitmap, p, centered, cp);
  200. }
  201. float2 GetDrawPosition(int2 location, Bitmap bmp, bool centered)
  202. {
  203. float OffsetX = centered ? bmp.Width / 2 - TileSet.TileSize / 2 : 0;
  204. float DrawX = TileSet.TileSize * location.X * Zoom + Offset.X - OffsetX;
  205. float OffsetY = centered ? bmp.Height / 2 - TileSet.TileSize / 2 : 0;
  206. float DrawY = TileSet.TileSize * location.Y * Zoom + Offset.Y - OffsetY;
  207. return new float2(DrawX, DrawY);
  208. }
  209. public void DrawImage(SGraphics g, Bitmap bmp, int2 location, bool centered, ColorPalette cp)
  210. {
  211. var drawPos = GetDrawPosition(location, bmp, centered);
  212. var sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
  213. var destRect = new RectangleF(drawPos.X, drawPos.Y, bmp.Width * Zoom, bmp.Height * Zoom);
  214. var restorePalette = bmp.Palette;
  215. if (cp != null) bmp.Palette = cp;
  216. g.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
  217. if (cp != null) bmp.Palette = restorePalette;
  218. }
  219. void DrawActorBorder(System.Drawing.Graphics g, int2 p, ActorTemplate t)
  220. {
  221. var centered = t.Appearance == null || !t.Appearance.RelativeToTopLeft;
  222. var drawPos = GetDrawPosition(p, t.Bitmap, centered);
  223. g.DrawRectangle(CordonPen,
  224. drawPos.X, drawPos.Y,
  225. t.Bitmap.Width * Zoom, t.Bitmap.Height * Zoom);
  226. }
  227. ColorPalette GetPaletteForPlayer(string name)
  228. {
  229. var pr = Map.Players[name];
  230. var pcpi = Rules.Info["player"].Traits.Get<PlayerColorPaletteInfo>();
  231. var remap = new PlayerColorRemap(pr.ColorRamp, pcpi.PaletteFormat);
  232. return new Palette(Palette, remap).AsSystemPalette();
  233. }
  234. Cache<string, ColorPalette> PlayerPalettes;
  235. ColorPalette GetPaletteForActor(ActorReference ar)
  236. {
  237. if (PlayerPalettes == null)
  238. PlayerPalettes = new Cache<string, ColorPalette>(GetPaletteForPlayer);
  239. var ownerInit = ar.InitDict.GetOrDefault<OwnerInit>();
  240. if (ownerInit == null)
  241. return null;
  242. return PlayerPalettes[ownerInit.PlayerName];
  243. }
  244. protected override void OnPaint(PaintEventArgs e)
  245. {
  246. if (Map == null) return;
  247. if (TileSet == null) return;
  248. for (var u = 0; u < Map.MapSize.X; u += ChunkSize)
  249. for (var v = 0; v < Map.MapSize.Y; v += ChunkSize)
  250. {
  251. var x = new int2(u / ChunkSize, v / ChunkSize);
  252. if (!Chunks.ContainsKey(x)) Chunks[x] = RenderChunk(u / ChunkSize, v / ChunkSize);
  253. Bitmap bmp = Chunks[x];
  254. float DrawX = TileSet.TileSize * (float)ChunkSize * (float)x.X * Zoom + Offset.X;
  255. float DrawY = TileSet.TileSize * (float)ChunkSize * (float)x.Y * Zoom + Offset.Y;
  256. RectangleF sourceRect = new RectangleF(0, 0, bmp.Width, bmp.Height);
  257. RectangleF destRect = new RectangleF(DrawX, DrawY, bmp.Width * Zoom, bmp.Height * Zoom);
  258. e.Graphics.DrawImage(bmp, destRect, sourceRect, GraphicsUnit.Pixel);
  259. }
  260. e.Graphics.DrawRectangle(CordonPen,
  261. Map.Bounds.Left * TileSet.TileSize * Zoom + Offset.X,
  262. Map.Bounds.Top * TileSet.TileSize * Zoom + Offset.Y,
  263. Map.Bounds.Width * TileSet.TileSize * Zoom,
  264. Map.Bounds.Height * TileSet.TileSize * Zoom);
  265. foreach (var ar in Map.Actors.Value)
  266. {
  267. if (ActorTemplates.ContainsKey(ar.Value.Type))
  268. DrawActor(e.Graphics, ar.Value.Location(), ActorTemplates[ar.Value.Type],
  269. GetPaletteForActor(ar.Value));
  270. else
  271. Console.WriteLine("Warning: Unknown or excluded actor: {0}", ar.Value.Type);
  272. }
  273. if (ShowActorNames)
  274. foreach (var ar in Map.Actors.Value)
  275. if (!ar.Key.StartsWith("Actor")) // if it has a custom name
  276. e.Graphics.DrawStringContrast(Font, ar.Key,
  277. (int)(ar.Value.Location().X * TileSet.TileSize * Zoom + Offset.X),
  278. (int)(ar.Value.Location().Y * TileSet.TileSize * Zoom + Offset.Y),
  279. Brushes.White,
  280. Brushes.Black);
  281. if (Tool != null)
  282. Tool.Preview(this, e.Graphics);
  283. if (Tool == null)
  284. {
  285. var x = Map.Actors.Value.FirstOrDefault(a => a.Value.Location() == GetBrushLocation());
  286. if (x.Key != null)
  287. DrawActorBorder(e.Graphics, x.Value.Location(), ActorTemplates[x.Value.Type]);
  288. }
  289. }
  290. }
  291. static class ActorReferenceExts
  292. {
  293. public static int2 Location(this ActorReference ar)
  294. {
  295. return ar.InitDict.Get<LocationInit>().value;
  296. }
  297. public static void DrawStringContrast(this SGraphics g, Font f, string s, int x, int y, Brush fg, Brush bg)
  298. {
  299. g.DrawString(s, f, bg, x - 1, y - 1);
  300. g.DrawString(s, f, bg, x + 1, y - 1);
  301. g.DrawString(s, f, bg, x - 1, y + 1);
  302. g.DrawString(s, f, bg, x + 1, y + 1);
  303. g.DrawString(s, f, fg, x, y);
  304. }
  305. }
  306. }