using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using nkast.Aether.Graphics;
using nkast.Aether.Shaders;
namespace Samples.Tilemaps
{
internal class TilemapSampleComponent : DrawableGameComponent
{
GraphicsDeviceManager graphics;
ContentManager Content;
SpriteBatch spriteBatch;
SpriteFont font;
KeyboardState previousKeyboardState;
int mipLevel = 4;
bool showAtlas = false;
bool useGenerateBitmap = true;
bool useMipmapPerSprite = true;
Rectangle atlasSize = new Rectangle(0, 0, 1024, 512);
RenderTarget2D rt;
Tilemap tilemapMipmapPerSprite;
Tilemap tilemapMipmap;
Tilemap tilemapNoMipmap;
public TilemapSampleComponent(Game game, GraphicsDeviceManager graphics) : base(game)
{
this.graphics = graphics;
}
/// Initializes the component. Used to load non-graphical resources.
public override void Initialize()
{
Content = new ContentManager(Game.Services, "Content");
base.Initialize();
}
/// Load graphical resources needed by this component.
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load("font");
rt = new RenderTarget2D(GraphicsDevice, atlasSize.Width, atlasSize.Height);
// Load tilemap
tilemapMipmapPerSprite = Content.Load("tilemapMipmapPerSprite");
tilemapMipmap = Content.Load("tilemapMipmap");
tilemapNoMipmap = Content.Load("tilemapNoMipmap");
#if DEBUG
using (var fs = File.Create("tilemapNoMipmapAtlas.png"))
tilemapNoMipmap.TextureAtlas.SaveAsPng(fs, tilemapNoMipmap.TextureAtlas.Width, tilemapNoMipmap.TextureAtlas.Height);
using (var fs = File.Create("tilemapMipmapAtlas.png"))
tilemapNoMipmap.TextureAtlas.SaveAsPng(fs, tilemapMipmap.TextureAtlas.Width, tilemapNoMipmap.TextureAtlas.Height);
#endif
graphics.PreferredBackBufferWidth = atlasSize.Width;
graphics.PreferredBackBufferHeight = atlasSize.Height;
graphics.ApplyChanges();
}
/// Unload graphical resources needed by this component.
protected override void UnloadContent()
{
Content.Unload();
}
/// Update the component.
/// GameTime of the Game.
public override void Update(GameTime gameTime)
{
KeyboardState keyState = Keyboard.GetState();
GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
if (keyState.IsKeyDown(Keys.F1) && !previousKeyboardState.IsKeyDown(Keys.F1))
useMipmapPerSprite = !useMipmapPerSprite;
if (keyState.IsKeyDown(Keys.F2) && !previousKeyboardState.IsKeyDown(Keys.F2))
useGenerateBitmap = !useGenerateBitmap;
if (keyState.IsKeyDown(Keys.F3) && !previousKeyboardState.IsKeyDown(Keys.F3))
showAtlas = !showAtlas;
if (keyState.IsKeyDown(Keys.OemPlus) && !previousKeyboardState.IsKeyDown(Keys.OemPlus) && mipLevel < 10)
mipLevel++;
if (keyState.IsKeyDown(Keys.Add) && !previousKeyboardState.IsKeyDown(Keys.Add) && mipLevel < 10)
mipLevel++;
if (keyState.IsKeyDown(Keys.OemMinus) && !previousKeyboardState.IsKeyDown(Keys.OemMinus) && mipLevel > 0)
mipLevel--;
if (keyState.IsKeyDown(Keys.Subtract) && !previousKeyboardState.IsKeyDown(Keys.Subtract) && mipLevel > 0)
mipLevel--;
previousKeyboardState = keyState;
}
private void DrawTilemap(GameTime gameTime, Tilemap tilemap, Rectangle mipSize)
{
// setup tilemapEffect
var viewport = GraphicsDevice.Viewport;
Matrix projection = Matrix.CreateOrthographicOffCenter(0, viewport.Width, viewport.Height, 0, 0, 1);
Matrix halfPixelOffset = Matrix.Identity;
#if XNA
halfPixelOffset = Matrix.CreateTranslation(-0.5f, -0.5f, 0);
#endif
tilemap.Effect.Projection = halfPixelOffset * projection;
// Draw tilemap
spriteBatch.Begin(0, BlendState.AlphaBlend, SamplerState.PointWrap, null, null, tilemap.Effect);
spriteBatch.Draw(tilemap.TextureMap, mipSize, Color.White);
spriteBatch.End();
}
/// Draw this component.
/// The time elapsed since the last call to Draw.
public override void Draw(GameTime gameTime)
{
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.SetRenderTarget(rt);
GraphicsDevice.Clear(Color.Black);
var currentTilemap = (useGenerateBitmap)
? (useMipmapPerSprite ? tilemapMipmapPerSprite : tilemapMipmap)
: (tilemapNoMipmap);
int mipLevel2 = (int)Math.Pow(2, mipLevel);
var mipSize = atlasSize;
mipSize.Width /= mipLevel2;
mipSize.Height /= mipLevel2;
if (showAtlas)
{
spriteBatch.Begin();
spriteBatch.Draw(currentTilemap.TextureAtlas, mipSize, Color.White);
spriteBatch.End();
}
else
{
DrawTilemap(gameTime, currentTilemap, mipSize);
}
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.PointWrap, null, null);
spriteBatch.Draw(rt, atlasSize, mipSize, Color.White);
spriteBatch.End();
spriteBatch.Begin();
spriteBatch.DrawString(font, String.Format("[F1] MipmapPerSprite - ({0})", useMipmapPerSprite ? "ON" : "OFF"), new Vector2(20, 20), Color.White);
spriteBatch.DrawString(font, String.Format("[F2] GenerateMipmap - ({0})", useGenerateBitmap ? "ON" : "OFF"), new Vector2(20, 40), Color.White);
spriteBatch.DrawString(font, String.Format("[F3] {0}", showAtlas? "Show Tilemap" : "Show Atlas"), new Vector2(20, 60), Color.White);
spriteBatch.DrawString(font, String.Format("[+/-] MipLevel - ({0})", mipLevel), new Vector2(20, 80), Color.White);
spriteBatch.End();
}
}
}