PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/TEditXna/View/WorldRenderXna.xaml.cs

https://github.com/Surfpup/Terraria-Map-Editor
C# | 1517 lines | 1314 code | 161 blank | 42 comment | 646 complexity | 9e051bc2029d418d7fc746d4eebf8b85 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Input;
  7. using BCCL.Geometry.Primitives;
  8. using BCCL.UI.Xaml.XnaContentHost;
  9. using BCCL.Utility;
  10. using Microsoft.Xna.Framework;
  11. using Microsoft.Xna.Framework.Graphics;
  12. using TEditXNA.Terraria;
  13. using TEditXNA.Terraria.Objects;
  14. using TEditXna.Editor;
  15. using TEditXna.Editor.Tools;
  16. using TEditXna.ViewModel;
  17. using System.Windows.Media.Imaging;
  18. using Point = System.Windows.Point;
  19. using Vector2 = Microsoft.Xna.Framework.Vector2;
  20. namespace TEditXna.View
  21. {
  22. /// <summary>
  23. /// Interaction logic for WorldRenderXna.xaml
  24. /// </summary>
  25. public partial class WorldRenderXna : UserControl
  26. {
  27. private Color _backgroundColor = Color.FromNonPremultiplied(32, 32, 32, 255);
  28. private readonly GameTimer _gameTimer;
  29. private readonly WorldViewModel _wvm;
  30. private bool _isMiddleMouseDown;
  31. private Vector2 _middleClickPoint;
  32. private Vector2 _mousePosition;
  33. private Vector2 _dpiScale;
  34. private Vector2 _scrollPosition = new Vector2(0, 0);
  35. private SimpleProvider _serviceProvider;
  36. private SpriteBatch _spriteBatch;
  37. public Textures _textureDictionary;
  38. private Texture2D[] _tileMap;
  39. private Texture2D _preview;
  40. private Dictionary<string, Texture2D> _textures = new Dictionary<string, Texture2D>();
  41. private Texture2D _selectionTexture;
  42. private float _zoom = 1;
  43. private float _minNpcScale = 0.75f;
  44. public WorldRenderXna()
  45. {
  46. TEditXna.Terraria.Config.world = this;
  47. // to stop visual studio design time crash :(
  48. if (!Debugging.IsInDesignMode)
  49. {
  50. InitializeComponent();
  51. _gameTimer = new GameTimer();
  52. }
  53. _wvm = ViewModelLocator.WorldViewModel;
  54. _wvm.PreviewChanged += PreviewChanged;
  55. _wvm.PropertyChanged += _wvm_PropertyChanged;
  56. _wvm.RequestZoom += _wvm_RequestZoom;
  57. _wvm.RequestScroll += _wvm_RequestScroll;
  58. }
  59. void _wvm_RequestScroll(object sender, BCCL.Framework.Events.EventArgs<ScrollDirection> e)
  60. {
  61. float x = _scrollPosition.X;
  62. float y = _scrollPosition.Y;
  63. float inc = 1 / _zoom * 10;
  64. switch (e.Value1)
  65. {
  66. case ScrollDirection.Up:
  67. y += inc;
  68. break;
  69. case ScrollDirection.Down:
  70. y -= inc;
  71. break;
  72. case ScrollDirection.Left:
  73. x += inc;
  74. break;
  75. case ScrollDirection.Right:
  76. x -= inc;
  77. break;
  78. }
  79. _scrollPosition = new Vector2(x, y);
  80. ClampScroll();
  81. }
  82. void _wvm_RequestZoom(object sender, BCCL.Framework.Events.EventArgs<bool> e)
  83. {
  84. if (e.Value1)
  85. {
  86. Zoom(1);
  87. }
  88. else
  89. {
  90. Zoom(-1);
  91. }
  92. }
  93. private void _wvm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
  94. {
  95. if (e.PropertyName == "CurrentWorld")
  96. {
  97. Zoom(0);
  98. }
  99. }
  100. private void PreviewChanged(object sender, EventArgs e)
  101. {
  102. UpdatePreview();
  103. }
  104. private void UpdatePreview()
  105. {
  106. if (xnaViewport.GraphicsService.GraphicsDevice != null)
  107. {
  108. if (_wvm.ActiveTool != null)
  109. {
  110. var preview = _wvm.ActiveTool.PreviewTool();
  111. if (preview != null)
  112. _preview = preview.ToTexture2D(xnaViewport.GraphicsService.GraphicsDevice);
  113. }
  114. }
  115. }
  116. private static Vector2 PointToVector2(Point point)
  117. {
  118. return new Vector2((float)point.X, (float)point.Y);
  119. }
  120. private void InitializeGraphicsComponents(GraphicsDeviceEventArgs e)
  121. {
  122. // Load services, textures and initialize spritebatch
  123. _serviceProvider = new SimpleProvider(xnaViewport.GraphicsService);
  124. _spriteBatch = new SpriteBatch(e.GraphicsDevice);
  125. _textureDictionary = new Textures(_serviceProvider);
  126. System.Windows.Media.Matrix m = PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice;
  127. _dpiScale = new Vector2((float)m.M11, (float)m.M22);
  128. }
  129. public void CenterOnTile(int x, int y)
  130. {
  131. _scrollPosition = new Vector2(
  132. -x + (float)(xnaViewport.ActualWidth / _zoom / 2),
  133. -y + (float)(xnaViewport.ActualHeight / _zoom / 2));
  134. ClampScroll();
  135. ScrollBarH.Value = -_scrollPosition.X;
  136. ScrollBarV.Value = -_scrollPosition.Y;
  137. }
  138. #region Load Content
  139. private void xnaViewport_LoadContent(object sender, GraphicsDeviceEventArgs e)
  140. {
  141. // Abort rendering if in design mode or if gameTimer is already running
  142. if (Debugging.IsInDesignMode || _gameTimer.IsRunning)
  143. return;
  144. InitializeGraphicsComponents(e);
  145. if (_textureDictionary.Valid)
  146. LoadTerrariaTextures(e);
  147. _selectionTexture = new Texture2D(e.GraphicsDevice, 1, 1);
  148. LoadResourceTextures(e);
  149. _selectionTexture.SetData(new[] { Color.FromNonPremultiplied(0, 128, 255, 128) });
  150. // Start the Game Timer
  151. _gameTimer.Start();
  152. }
  153. private void LoadResourceTextures(GraphicsDeviceEventArgs e)
  154. {
  155. _textures.Add("Spawn", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.spawn_marker.png", e.GraphicsDevice));
  156. _textures.Add("Dungeon", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.dungeon_marker.png", e.GraphicsDevice));
  157. _textures.Add("Old Man", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_old_man.png", e.GraphicsDevice));
  158. _textures.Add("Arms Dealer", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_arms_dealer.png", e.GraphicsDevice));
  159. _textures.Add("Clothier", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_clothier.png", e.GraphicsDevice));
  160. _textures.Add("Demolitionist", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_demolitionist.png", e.GraphicsDevice));
  161. _textures.Add("Dryad", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_dryad.png", e.GraphicsDevice));
  162. _textures.Add("Guide", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_guide.png", e.GraphicsDevice));
  163. _textures.Add("Merchant", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_merchant.png", e.GraphicsDevice));
  164. _textures.Add("Nurse", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_nurse.png", e.GraphicsDevice));
  165. _textures.Add("Goblin Tinkerer", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_goblin.png", e.GraphicsDevice));
  166. _textures.Add("Wizard", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_wizard.png", e.GraphicsDevice));
  167. _textures.Add("Mechanic", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_mechanic.png", e.GraphicsDevice));
  168. _textures.Add("Santa Claus", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.npc_santa_claus.png", e.GraphicsDevice));
  169. _textures.Add("Grid", WriteableBitmapEx.ResourceToTexture2D("TEditXna.Images.Overlays.grid.png", e.GraphicsDevice));
  170. }
  171. private void LoadTerrariaTextures(GraphicsDeviceEventArgs e)
  172. {
  173. // If the texture dictionary is valid (Found terraria and loaded content) load texture data
  174. foreach (var id in World.NpcIds)
  175. {
  176. _textureDictionary.GetNPC(id.Value);
  177. }
  178. //foreach (var tile in World.TileProperties.Where(t => t.IsFramed))
  179. //{
  180. // var tileTexture = _textureDictionary.GetTile(tile.Id);
  181. //}
  182. foreach (var sprite in World.Sprites)
  183. {
  184. if (sprite.Size.X == 0 || sprite.Size.Y == 0)
  185. continue;
  186. try
  187. {
  188. var tile = World.TileProperties[sprite.Tile];
  189. if (tile.TextureGrid.X == 0 || tile.TextureGrid.Y == 0)
  190. continue;
  191. var texture = new Texture2D(e.GraphicsDevice, sprite.Size.X * tile.TextureGrid.X, sprite.Size.Y * tile.TextureGrid.Y);
  192. var tileTex = _textureDictionary.GetTile(sprite.Tile);
  193. for (int x = 0; x < sprite.Size.X; x++)
  194. {
  195. for (int y = 0; y < sprite.Size.Y; y++)
  196. {
  197. var source = new Rectangle(x * (tile.TextureGrid.X + 2) + sprite.Origin.X, y * (tile.TextureGrid.Y + 2) + sprite.Origin.Y, tile.TextureGrid.X, tile.TextureGrid.Y);
  198. if (source.Bottom > tileTex.Height)
  199. source.Height -= (source.Bottom - tileTex.Height);
  200. if (source.Right > tileTex.Width)
  201. source.Width -= (source.Right - tileTex.Width);
  202. var color = new Color[source.Height * source.Width];
  203. var dest = new Rectangle(x * tile.TextureGrid.X, y * tile.TextureGrid.Y, source.Width, source.Height);
  204. tileTex.GetData(0, source, color, 0, color.Length);
  205. texture.SetData(0, dest, color, 0, color.Length);
  206. }
  207. }
  208. sprite.IsPreviewTexture = true;
  209. sprite.Preview = texture.Texture2DToWriteableBitmap();
  210. }
  211. catch (Exception ex)
  212. {
  213. ErrorLogging.LogException(ex);
  214. }
  215. }
  216. }
  217. #endregion
  218. #region Update
  219. private void xnaViewport_RenderXna(object sender, GraphicsDeviceEventArgs e)
  220. {
  221. // Clear the graphics device and texture buffer
  222. e.GraphicsDevice.Clear(_backgroundColor);
  223. // Abort rendering if in design mode or if gameTimer is not running
  224. if (Debugging.IsInDesignMode || !_gameTimer.IsRunning || _wvm.CurrentWorld == null)
  225. return;
  226. Update(e);
  227. Render(e);
  228. }
  229. private void Update(GraphicsDeviceEventArgs e)
  230. {
  231. // Update
  232. _gameTimer.Update();
  233. ScrollWorld();
  234. }
  235. private void ScrollBar_Scroll(object sender, System.Windows.Controls.Primitives.ScrollEventArgs e)
  236. {
  237. _scrollPosition = new Vector2(-(float)ScrollBarH.Value, -(float)ScrollBarV.Value);
  238. ClampScroll();
  239. }
  240. private void ScrollWorld()
  241. {
  242. if (_isMiddleMouseDown)
  243. {
  244. Vector2 stretchDistance = (_mousePosition - _middleClickPoint);
  245. Vector2 clampedScroll = _scrollPosition + stretchDistance / _zoom;
  246. _scrollPosition = clampedScroll;
  247. _middleClickPoint = _mousePosition;
  248. ClampScroll();
  249. }
  250. }
  251. private void ClampScroll()
  252. {
  253. if (_wvm.CurrentWorld == null || xnaViewport == null)
  254. {
  255. _scrollPosition = new Vector2(0, 0);
  256. ScrollBarH.Value = -_scrollPosition.X;
  257. ScrollBarV.Value = -_scrollPosition.Y;
  258. return;
  259. }
  260. int xNormalRange = -_wvm.CurrentWorld.TilesWide + (int)(xnaViewport.ActualWidth / _zoom);
  261. int yNormalRange = -_wvm.CurrentWorld.TilesHigh + (int)(xnaViewport.ActualHeight / _zoom);
  262. if (_wvm.CurrentWorld.TilesWide > (int)(xnaViewport.ActualWidth / _zoom))
  263. _scrollPosition.X = MathHelper.Clamp(_scrollPosition.X, xNormalRange, 0);
  264. else
  265. _scrollPosition.X = MathHelper.Clamp(_scrollPosition.X, (_wvm.CurrentWorld.TilesWide / 2 - (int)(xnaViewport.ActualWidth / _zoom) / 2), 0);
  266. if (_wvm.CurrentWorld.TilesHigh > (int)(xnaViewport.ActualHeight / _zoom))
  267. _scrollPosition.Y = MathHelper.Clamp(_scrollPosition.Y, yNormalRange, 0);
  268. else
  269. _scrollPosition.Y = MathHelper.Clamp(_scrollPosition.Y, (_wvm.CurrentWorld.TilesHigh / 2 - (int)(xnaViewport.ActualHeight / _zoom) / 2), 0);
  270. ScrollBarH.Value = -_scrollPosition.X;
  271. ScrollBarV.Value = -_scrollPosition.Y;
  272. }
  273. #endregion
  274. #region Render
  275. private void Render(GraphicsDeviceEventArgs e)
  276. {
  277. // Clear the graphics device and texture buffer
  278. //e.GraphicsDevice.Clear(Color.Black);
  279. e.GraphicsDevice.Textures[0] = null;
  280. GenPixelTiles(e);
  281. // Start SpriteBatch
  282. _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone);
  283. DrawPixelTiles();
  284. // Draw sprite overlays
  285. if (_wvm.ShowTextures && _textureDictionary.Valid)
  286. DrawSprites();
  287. if (_wvm.ShowGrid)
  288. DrawGrid();
  289. if (_wvm.ShowPoints)
  290. {
  291. _spriteBatch.End();
  292. _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone);
  293. DrawPoints();
  294. _spriteBatch.End();
  295. _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone);
  296. }
  297. if (_wvm.Selection.IsActive)
  298. DrawSelection();
  299. DrawToolPreview();
  300. // End SpriteBatch
  301. _spriteBatch.End();
  302. }
  303. private void GenPixelTiles(GraphicsDeviceEventArgs e)
  304. {
  305. if (_wvm != null)
  306. {
  307. if (_wvm.PixelMap != null)
  308. {
  309. if (_tileMap == null || _tileMap.Length != _wvm.PixelMap.ColorBuffers.Length)
  310. {
  311. _tileMap = new Texture2D[_wvm.PixelMap.ColorBuffers.Length];
  312. }
  313. for (int i = 0; i < _tileMap.Length; i++)
  314. {
  315. if (!Check2DFrustrum(i))
  316. continue;
  317. // Make a new texture for nulls
  318. bool init = _tileMap[i] == null;
  319. if (init || _tileMap[i].Width != _wvm.PixelMap.TileWidth || _tileMap[i].Height != _wvm.PixelMap.TileHeight)
  320. _tileMap[i] = new Texture2D(e.GraphicsDevice, _wvm.PixelMap.TileWidth, _wvm.PixelMap.TileHeight);
  321. if (_wvm.PixelMap.BufferUpdated[i] || init)
  322. {
  323. _tileMap[i].SetData(_wvm.PixelMap.ColorBuffers[i]);
  324. _wvm.PixelMap.BufferUpdated[i] = false;
  325. }
  326. }
  327. }
  328. }
  329. }
  330. private void DrawGrid()
  331. {
  332. Rectangle visibleBounds = GetViewingArea();
  333. var gridTex = _textures["Grid"];
  334. if (visibleBounds.Height * visibleBounds.Width < 25000)
  335. {
  336. for (int x = 0; x < visibleBounds.Right; x += 16)
  337. {
  338. for (int y = 0; y < visibleBounds.Bottom; y += 16)
  339. {
  340. if ((x + 16 >= visibleBounds.Left || x <= visibleBounds.Right) &&
  341. (y + 16 >= visibleBounds.Top || y <= visibleBounds.Bottom))
  342. {
  343. var dest = new Rectangle(1 + (int)((_scrollPosition.X + x) * _zoom), 1 + (int)((_scrollPosition.Y + y) * _zoom), (int)(_zoom * 256 / 16), (int)(_zoom * 256 / 16));
  344. _spriteBatch.Draw(gridTex, dest, Color.White);
  345. }
  346. }
  347. }
  348. }
  349. }
  350. /* Heathtech */
  351. //Pretty much overwrote this whole function. The original part is still intact, but much more hidden
  352. private void DrawSprites()
  353. {
  354. Rectangle visibleBounds = GetViewingArea();
  355. TEditXna.Terraria.Objects.BlendRules blendRules = TEditXna.Terraria.Objects.BlendRules.Instance;
  356. if (visibleBounds.Height * visibleBounds.Width < 25000)
  357. {
  358. //Extended the viewing space to give tiles time to cache their UV's
  359. for (int y = visibleBounds.Top - 1; y < visibleBounds.Bottom + 2; y++)
  360. {
  361. for (int x = visibleBounds.Left - 1; x < visibleBounds.Right + 2; x++)
  362. {
  363. if (x < 0 || y < 0 || x >= _wvm.CurrentWorld.TilesWide || y >= _wvm.CurrentWorld.TilesHigh)
  364. {
  365. continue;
  366. }
  367. var curtile = _wvm.CurrentWorld.Tiles[x, y];
  368. var tileprop = World.TileProperties[curtile.Type];
  369. //Neighbor tiles are often used when dynamically determining which UV position to render
  370. int e = 0, n = 1, w = 2, s = 3, ne = 4, nw = 5, sw = 6, se = 7;
  371. Tile[] neighborTile = new Tile[8];
  372. neighborTile[e] = (x + 1) < _wvm.CurrentWorld.TilesWide ? _wvm.CurrentWorld.Tiles[x + 1, y] : null;
  373. neighborTile[n] = (y - 1) > 0 ? _wvm.CurrentWorld.Tiles[x, y - 1] : null;
  374. neighborTile[w] = (x - 1) > 0 ? _wvm.CurrentWorld.Tiles[x - 1, y] : null;
  375. neighborTile[s] = (y + 1) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x, y + 1] : null;
  376. neighborTile[ne] = (x + 1) < _wvm.CurrentWorld.TilesWide && (y - 1) > 0 ? _wvm.CurrentWorld.Tiles[x + 1, y - 1] : null;
  377. neighborTile[nw] = (x - 1) > 0 && (y - 1) > 0 ? _wvm.CurrentWorld.Tiles[x - 1, y - 1] : null;
  378. neighborTile[sw] = (x - 1) > 0 && (y + 1) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x - 1, y + 1] : null;
  379. neighborTile[se] = (x + 1) < _wvm.CurrentWorld.TilesWide && (y + 1) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x + 1, y + 1] : null;
  380. if (_wvm.ShowWalls)
  381. {
  382. if (curtile.Wall > 0)
  383. {
  384. var wallTex = _textureDictionary.GetWall(curtile.Wall);
  385. if (wallTex != null)
  386. {
  387. if (curtile.uvWallCache == 0xFFFF)
  388. {
  389. int sameStyle = 0x00000000;
  390. sameStyle |= (neighborTile[e] != null && neighborTile[e].Wall == curtile.Wall) ? 0x0001 : 0x0000;
  391. sameStyle |= (neighborTile[n] != null && neighborTile[n].Wall == curtile.Wall) ? 0x0010 : 0x0000;
  392. sameStyle |= (neighborTile[w] != null && neighborTile[w].Wall == curtile.Wall) ? 0x0100 : 0x0000;
  393. sameStyle |= (neighborTile[s] != null && neighborTile[s].Wall == curtile.Wall) ? 0x1000 : 0x0000;
  394. Vector2Int32 uvBlend = blendRules.GetUVForMasks((uint)sameStyle, 0x00000000, 0);
  395. curtile.uvWallCache = (ushort)((uvBlend.Y << 8) + uvBlend.X);
  396. }
  397. var texsize = new Vector2Int32(32, 32);
  398. var source = new Rectangle((curtile.uvWallCache & 0x00FF) * (texsize.X + 4), (curtile.uvWallCache >> 8) * (texsize.Y + 4), texsize.X, texsize.Y);
  399. var dest = new Rectangle(1 + (int)((_scrollPosition.X + x - 0.5) * _zoom), 1 + (int)((_scrollPosition.Y + y - 0.5) * _zoom), (int)_zoom * 2, (int)_zoom * 2);
  400. _spriteBatch.Draw(wallTex, dest, source, Color.White, 0f, default(Vector2), SpriteEffects.None, 1);
  401. }
  402. }
  403. }
  404. if (_wvm.ShowTiles)
  405. {
  406. if (curtile.IsActive)
  407. {
  408. if (tileprop.IsFramed)
  409. {
  410. Rectangle source = new Rectangle(), dest = new Rectangle();
  411. var tileTex = _textureDictionary.GetTile(curtile.Type);
  412. bool isTree = false, isMushroom = false;
  413. bool isLeft = false, isBase = false, isRight = false;
  414. if (curtile.Type == 5 && curtile.U >= 22 && curtile.V >= 198)
  415. {
  416. isTree = true;
  417. switch (curtile.U)
  418. {
  419. case 22: isBase = true; break;
  420. case 44: isLeft = true; break;
  421. case 66: isRight = true; break;
  422. }
  423. //Abuse uvTileCache to remember what type of tree it is, since potentially scanning a hundred of blocks PER tree tile sounds slow
  424. int treeType = (curtile.uvTileCache & 0x000F);
  425. if (treeType > 4) //Tree type not yet set
  426. {
  427. //Check tree type
  428. treeType = 0; //Default to normal in case no grass grows beneath the tree
  429. int baseX = (isLeft) ? 1 : (isRight) ? -1 : 0;
  430. for (int i = 0; i < 100; i++)
  431. {
  432. Tile checkTile = (y + i) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x + baseX, y + i] : null;
  433. bool found = true;
  434. if (checkTile != null && checkTile.IsActive)
  435. {
  436. switch (checkTile.Type)
  437. {
  438. case 2: treeType = 0; break; //Normal
  439. case 23: treeType = 1; break; //Corruption
  440. case 60: treeType = 2; break; //Jungle
  441. case 109: treeType = 3; break; //Hallow
  442. case 147: treeType = 4; break; //Snow
  443. default: found = false; break;
  444. }
  445. if (found == true)
  446. {
  447. curtile.uvTileCache = (ushort)((0x00 << 8) + 0x01 * treeType);
  448. break;
  449. }
  450. }
  451. }
  452. }
  453. if (isBase)
  454. {
  455. tileTex = (Texture2D)_textureDictionary.GetTreeTops(treeType);
  456. }
  457. else
  458. {
  459. tileTex = (Texture2D)_textureDictionary.GetTreeBranches(treeType);
  460. }
  461. }
  462. if (curtile.Type == 72 && curtile.U >= 36)
  463. {
  464. isMushroom = true;
  465. tileTex = (Texture2D)_textureDictionary.GetShroomTop(0);
  466. }
  467. if (tileTex != null)
  468. {
  469. if (!isTree && !isMushroom)
  470. {
  471. source = new Rectangle(curtile.U, curtile.V, tileprop.TextureGrid.X, tileprop.TextureGrid.Y);
  472. if (source.Width <= 0)
  473. source.Width = 16;
  474. if (source.Height <= 0)
  475. source.Height = 16;
  476. if (source.Bottom > tileTex.Height)
  477. source.Height -= (source.Bottom - tileTex.Height);
  478. if (source.Right > tileTex.Width)
  479. source.Width -= (source.Right - tileTex.Width);
  480. if (source.Width <= 0 || source.Height <= 0)
  481. continue;
  482. dest = new Rectangle(1 + (int)((_scrollPosition.X + x) * _zoom), 1 + (int)((_scrollPosition.Y + y) * _zoom), (int)_zoom, (int)_zoom);
  483. var texsize = tileprop.TextureGrid;
  484. if (texsize.X != 16 || texsize.Y != 16)
  485. {
  486. dest.Width = (int)(texsize.X * (_zoom / 16));
  487. dest.Height = (int)(texsize.Y * (_zoom / 16));
  488. var frame = (tileprop.Frames.FirstOrDefault(f => f.UV == new Vector2Short(curtile.U, curtile.V)));
  489. var frameAnchor = FrameAnchor.None;
  490. if (frame != null)
  491. frameAnchor = frame.Anchor;
  492. switch (frameAnchor)
  493. {
  494. case FrameAnchor.None:
  495. dest.X += (int)(((16 - texsize.X) / 2F) * _zoom / 16);
  496. dest.Y += (int)(((16 - texsize.Y) / 2F) * _zoom / 16);
  497. break;
  498. case FrameAnchor.Left:
  499. //position.X += (16 - texsize.X) / 2;
  500. dest.Y += (int)(((16 - texsize.Y) / 2F) * _zoom / 16);
  501. break;
  502. case FrameAnchor.Right:
  503. dest.X += (int)((16 - texsize.X) * _zoom / 16);
  504. dest.Y += (int)(((16 - texsize.Y) / 2F) * _zoom / 16);
  505. break;
  506. case FrameAnchor.Top:
  507. dest.X += (int)(((16 - texsize.X) / 2F) * _zoom / 16);
  508. //position.Y += (16 - texsize.Y);
  509. break;
  510. case FrameAnchor.Bottom:
  511. dest.X += (int)(((16 - texsize.X) / 2F) * _zoom / 16);
  512. dest.Y += (int)((16 - texsize.Y) * _zoom / 16);
  513. break;
  514. }
  515. }
  516. }
  517. else if (isTree)
  518. {
  519. source = new Rectangle(0, 0, 40, 40);
  520. dest = new Rectangle(1 + (int)((_scrollPosition.X + x) * _zoom), 1 + (int)((_scrollPosition.Y + y) * _zoom), (int)_zoom, (int)_zoom);
  521. FrameAnchor frameAnchor = FrameAnchor.None;
  522. int treeType = (curtile.uvTileCache & 0x000F);
  523. if (isBase)
  524. {
  525. switch (treeType)
  526. {
  527. case 0:
  528. case 1:
  529. case 4:
  530. source.Width = 80;
  531. source.Height = 80;
  532. break;
  533. case 2:
  534. source.Width = 114;
  535. source.Height = 96;
  536. break;
  537. case 3:
  538. source.X = (x % 3) * (82 * 3);
  539. source.Width = 80;
  540. source.Height = 140;
  541. break;
  542. }
  543. source.X += ((curtile.V - 198) / 22) * (source.Width + 2);
  544. frameAnchor = FrameAnchor.Bottom;
  545. }
  546. else if (isLeft)
  547. {
  548. source.X = 0;
  549. switch (treeType)
  550. {
  551. case 3:
  552. source.Y = (x % 3) * (42 * 3);
  553. break;
  554. }
  555. frameAnchor = FrameAnchor.Right;
  556. source.Y += ((curtile.V - 198) / 22) * (source.Height + 2);
  557. }
  558. else if (isRight)
  559. {
  560. source.X = 42;
  561. switch (treeType)
  562. {
  563. case 3:
  564. source.Y = (x % 3) * (42 * 3);
  565. break;
  566. }
  567. frameAnchor = FrameAnchor.Left;
  568. source.Y += ((curtile.V - 198) / 22) * (source.Height + 2);
  569. }
  570. dest.Width = (int)(_zoom * source.Width / 16f);
  571. dest.Height = (int)(_zoom * source.Height / 16f);
  572. switch (frameAnchor)
  573. {
  574. case FrameAnchor.None:
  575. dest.X += (int)(((16 - source.Width) / 2F) * _zoom / 16);
  576. dest.Y += (int)(((16 - source.Height) / 2F) * _zoom / 16);
  577. break;
  578. case FrameAnchor.Left:
  579. dest.Y += (int)(((16 - source.Height) / 2F) * _zoom / 16);
  580. break;
  581. case FrameAnchor.Right:
  582. dest.X += (int)((16 - source.Width) * _zoom / 16);
  583. dest.Y += (int)(((16 - source.Height) / 2F) * _zoom / 16);
  584. break;
  585. case FrameAnchor.Top:
  586. dest.X += (int)(((16 - source.Width) / 2F) * _zoom / 16);
  587. break;
  588. case FrameAnchor.Bottom:
  589. dest.X += (int)(((16 - source.Width) / 2F) * _zoom / 16);
  590. dest.Y += (int)((16 - source.Height) * _zoom / 16);
  591. break;
  592. }
  593. }
  594. else if (isMushroom)
  595. {
  596. source = new Rectangle(0, 0, 60, 42);
  597. dest = new Rectangle(1 + (int)((_scrollPosition.X + x) * _zoom), 1 + (int)((_scrollPosition.Y + y) * _zoom), (int)_zoom, (int)_zoom);
  598. source.X = (curtile.V / 18) * 62;
  599. dest.Width = (int)(_zoom * source.Width / 16f);
  600. dest.Height = (int)(_zoom * source.Height / 16f);
  601. dest.X += (int)(((16 - source.Width) / 2F) * _zoom / 16);
  602. dest.Y += (int)((16 - source.Height) * _zoom / 16);
  603. }
  604. _spriteBatch.Draw(tileTex, dest, source, Color.White, 0f, default(Vector2), SpriteEffects.None, 0);
  605. }
  606. }
  607. else if (tileprop.IsPlatform)
  608. {
  609. var tileTex = _textureDictionary.GetTile(curtile.Type);
  610. if (tileTex != null)
  611. {
  612. Vector2Int32 uv;
  613. if (curtile.uvTileCache == 0xFFFF)
  614. {
  615. uv = new Vector2Int32(0, 0);
  616. byte state = 0x00;
  617. state |= (byte)((neighborTile[w] != null && neighborTile[w].IsActive && neighborTile[w].Type == curtile.Type) ? 0x01 : 0x00);
  618. state |= (byte)((neighborTile[w] != null && neighborTile[w].IsActive && World.TileProperties[neighborTile[w].Type].IsSolid && neighborTile[w].Type != curtile.Type) ? 0x02 : 0x00);
  619. state |= (byte)((neighborTile[e] != null && neighborTile[e].IsActive && neighborTile[e].Type == curtile.Type) ? 0x04 : 0x00);
  620. state |= (byte)((neighborTile[e] != null && neighborTile[e].IsActive && World.TileProperties[neighborTile[e].Type].IsSolid && neighborTile[e].Type != curtile.Type) ? 0x08 : 0x00);
  621. switch (state)
  622. {
  623. case 0x00:
  624. case 0x0A:
  625. uv.X = 5;
  626. break;
  627. case 0x01:
  628. uv.X = 1;
  629. break;
  630. case 0x02:
  631. uv.X = 6;
  632. break;
  633. case 0x04:
  634. uv.X = 2;
  635. break;
  636. case 0x05:
  637. uv.X = 0;
  638. break;
  639. case 0x06:
  640. uv.X = 3;
  641. break;
  642. case 0x08:
  643. uv.X = 7;
  644. break;
  645. case 0x09:
  646. uv.X = 4;
  647. break;
  648. }
  649. uv.Y = blendRules.randomVariation.Next(3);
  650. curtile.uvTileCache = (ushort)((uv.Y << 8) + uv.X);
  651. }
  652. var texsize = new Vector2Int32(tileprop.TextureGrid.X, tileprop.TextureGrid.Y);
  653. if (texsize.X == 0 || texsize.Y == 0)
  654. {
  655. texsize = new Vector2Int32(16, 16);
  656. }
  657. var source = new Rectangle((curtile.uvTileCache & 0x00FF) * (texsize.X + 2), (curtile.uvTileCache >> 8) * (texsize.Y + 2), texsize.X, texsize.Y);
  658. var dest = new Rectangle(1 + (int)((_scrollPosition.X + x) * _zoom), 1 + (int)((_scrollPosition.Y + y) * _zoom), (int)_zoom, (int)_zoom);
  659. _spriteBatch.Draw(tileTex, dest, source, Color.White, 0f, default(Vector2), SpriteEffects.None, 0);
  660. }
  661. }
  662. else if (tileprop.IsCactus)
  663. {
  664. var tileTex = _textureDictionary.GetTile(curtile.Type);
  665. if ((curtile.uvTileCache & 0x00FF) >= 16)
  666. {
  667. tileTex = (Texture2D)_textureDictionary.GetMisc("Evil_Cactus");
  668. }
  669. else if ((curtile.uvTileCache & 0x00FF) >= 8)
  670. {
  671. tileTex = (Texture2D)_textureDictionary.GetMisc("Good_Cactus");
  672. }
  673. if (tileTex != null)
  674. {
  675. Vector2Int32 uv;
  676. if (curtile.uvTileCache == 0xFFFF || curtile.hasLazyChecked == false)
  677. {
  678. bool isLeft = false, isRight = false, isBase = false;
  679. //Has this cactus been base-evaluated yet?
  680. int neighborX = (neighborTile[w].uvTileCache & 0x00FF) % 8; //Why % 8? If X >= 8, use hallow, If X >= 16, use corruption
  681. if (neighborX == 0 || neighborX == 1 || neighborX == 4 || neighborX == 5)
  682. {
  683. isRight = true;
  684. }
  685. neighborX = neighborTile[e].uvTileCache & 0x00FF;
  686. if (neighborX == 0 || neighborX == 1 || neighborX == 4 || neighborX == 5)
  687. {
  688. isLeft = true;
  689. }
  690. neighborX = curtile.uvTileCache & 0x00FF;
  691. if (neighborX == 0 || neighborX == 1 || neighborX == 4 || neighborX == 5)
  692. {
  693. isBase = true;
  694. }
  695. //Evaluate Base
  696. if (isLeft == false && isRight == false && isBase == false)
  697. {
  698. int length1 = 0;
  699. int length2 = 0;
  700. while (true)
  701. {
  702. Tile checkTile = (y + length1) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x, y + length1] : null;
  703. if (checkTile == null || checkTile.IsActive == false || checkTile.Type != curtile.Type)
  704. {
  705. break;
  706. }
  707. length1++;
  708. }
  709. if (x + 1 < _wvm.CurrentWorld.TilesWide)
  710. {
  711. while (true)
  712. {
  713. Tile checkTile = (y + length2) < _wvm.CurrentWorld.TilesHigh ? _wvm.CurrentWorld.Tiles[x + 1, y + length2] : null;
  714. if (checkTile == null || checkTile.IsActive == false || checkTile.Type != curtile.Type)
  715. {
  716. break;
  717. }
  718. length2++;
  719. }
  720. }
  721. int baseX = 0;
  722. int baseY = length1;
  723. isBase = true;
  724. if (length2 >= length1)
  725. {
  726. baseX = 1;
  727. baseY = length2;
  728. isBase = false;
  729. isLeft = true;
  730. }
  731. for (int cy = y; cy < y + baseY; cy++)
  732. {
  733. if (_wvm.CurrentWorld.Tiles[x + baseX, cy].uvTileCache == 0xFFFF)
  734. {
  735. if (cy == y)
  736. {
  737. _wvm.CurrentWorld.Tiles[x + baseX, cy].uvTileCache = 0x00 << 8 + 0x00;
  738. }
  739. else
  740. {
  741. _wvm.CurrentWorld.Tiles[x + baseX, cy].uvTileCache = 0x01 << 8 + 0x00;
  742. }
  743. }
  744. }
  745. }
  746. uv = new Vector2Int32(0, 0);
  747. byte state = 0x00;
  748. state |= (byte)((neighborTile[e] != null && neighborTile[e].IsActive && neighborTile[e].Type == curtile.Type) ? 0x01 : 0x00);
  749. state |= (byte)((neighborTile[n] != null && neighborTile[n].IsActive && neighborTile[n].Type == curtile.Type) ? 0x02 : 0x00);
  750. state |= (byte)((neighborTile[w] != null && neighborTile[w].IsActive && neighborTile[w].Type == curtile.Type) ? 0x04 : 0x00);
  751. state |= (byte)((neighborTile[s] != null && neighborTile[s].IsActive && neighborTile[s].Type == curtile.Type) ? 0x08 : 0x00);
  752. //state |= (byte)((neighborTile[ne] != null && neighborTile[ne].IsActive && neighborTile[ne].Type == curtile.Type) ? 0x10 : 0x00);
  753. //state |= (byte)((neighborTile[nw] != null && neighborTile[nw].IsActive && neighborTile[nw].Type == curtile.Type) ? 0x20 : 0x00);
  754. state |= (byte)((neighborTile[sw] != null && neighborTile[sw].IsActive && neighborTile[sw].Type == curtile.Type) ? 0x40 : 0x00);
  755. state |= (byte)((neighborTile[se] != null && neighborTile[se].IsActive && neighborTile[se].Type == curtile.Type) ? 0x80 : 0x00);
  756. if (isLeft)
  757. {
  758. uv.X = 3;
  759. if ((state & 0x08) != 0x00) //s
  760. {
  761. if ((state & 0x02) != 0x00) //n
  762. {
  763. uv.Y = 1;
  764. }
  765. else //!n
  766. {
  767. uv.Y = 0;
  768. }
  769. }
  770. else //!s
  771. {
  772. if ((state & 0x02) != 0x00) //n
  773. {
  774. uv.Y = 2;
  775. }

Large files files are truncated, but you can click here to view the full file