space-pew/SpacePew/LevelLoader.cs

181 lines
5.8 KiB
C#
Raw Normal View History

2015-12-04 10:23:49 +01:00
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Media;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using ICSharpCode.SharpZipLib.Zip;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Content;
using SpacePew.Models;
using Rectangle = System.Drawing.Rectangle;
namespace SpacePew
{
static class LevelLoader
{
public static Level LoadLevel(string filePath, ContentManager cm, GraphicsDevice device)
{
var levelResources = GetResourceList(filePath);
if (!levelResources.ContainsKey("leveldata.xml"))
throw new InvalidOperationException("Level: " + filePath + " doesnt contain any leveldata.xml");
var levelData = GetXmlFile(levelResources["leveldata.xml"]);
string baseTexture = levelData.SelectSingleNode("//baseTexture").InnerText.ToLower();
string indestructibleTexture = levelData.SelectSingleNode("//indestructibleTexture").InnerText.ToLower();
var spriteBatch = new SpriteBatch(device);
var level = new Level();
level.FilePath = filePath;
level.Texture = LoadTextureTiles(levelResources[baseTexture], device, spriteBatch);
level.IndestructibleTexture = LoadTextureTiles(levelResources[indestructibleTexture], device, spriteBatch);
level.DeformedTexture = new TiledTexture
{
Width = level.Texture.Width,
Height = level.Texture.Height,
TileHeight = level.Texture.TileHeight,
TileWidth = level.Texture.TileWidth,
XTiles = level.Texture.XTiles,
YTiles = level.Texture.YTiles
};
level.Texture.ForEach(t => level.DeformedTexture.Add(new Tile(
new RenderTarget2D(device, level.Texture.TileWidth, level.Texture.TileHeight, false,
SurfaceFormat.Color, DepthFormat.Depth24,
device.PresentationParameters.MultiSampleCount,
RenderTargetUsage.PreserveContents
),
t.Position)));
if (levelData.SelectSingleNode("//song") != null)
{
string songName = levelData.SelectSingleNode("//song").InnerText.ToLower();
level.OggVorbisSong = levelResources[songName];
}
level.Initialize();
return level;
}
private static XmlDocument GetXmlFile(byte[] rawData)
{
var d = new XmlDocument();
d.LoadXml(System.Text.Encoding.UTF8.GetString(rawData));
return d;
}
public static TiledTexture LoadTextureTiles(Byte[] bitmapData, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
using (var ms = new MemoryStream(bitmapData))
{
ms.Seek(0, SeekOrigin.Begin);
using (var image = Image.FromStream(ms))
{
return LoadTextureTiles(image, device, spriteBatch, tileWidth, tileHeight);
}
}
}
public static TiledTexture LoadTextureTiles(string fileName, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
using (var image = Image.FromFile(AppDomain.CurrentDomain.BaseDirectory + fileName.Replace("/", "\\")))
{
return LoadTextureTiles(image, device, spriteBatch, tileWidth, tileHeight);
}
}
public static TiledTexture LoadTextureTiles(Image image, GraphicsDevice device, SpriteBatch spriteBatch, int tileWidth = 0, int tileHeight = 0)
{
//OBS!!! S<>tt kartans bredd el h<>jd till ett primtal o det <20>r k<>rt iom att d<> kan man inte hitta en j<>mn multiple och en oj<6F>mn kommer att anv<6E>ndas
//och det kommer att pricka i framtiden.
if (tileWidth == 0)
tileWidth = FindNearbyMultiple(image.Width, 1000);
if (tileHeight == 0)
tileHeight = FindNearbyMultiple(image.Height, 1000);
int tilesX = (image.Width % tileWidth == 0)
? (int)Math.Floor(image.Width / (double)tileWidth)
: (int)Math.Ceiling(image.Width / (double)tileWidth);
int tilesY = (image.Height % tileHeight == 0)
? (int)Math.Floor(image.Height / (double)tileHeight)
: (int)Math.Ceiling(image.Height / (double)tileHeight);
var ret = new TiledTexture
{
TileWidth = tileWidth,
TileHeight = tileHeight,
XTiles = tilesX,
YTiles = tilesY,
Width = image.Width,
Height = image.Height
};
for (var j = 0; j < tilesX; j++)
{
for (var i = 0; i < tilesY; i++)
{
var part = new Bitmap(tileWidth, tileHeight, image.PixelFormat);
var graphics = Graphics.FromImage(part);
var srcRect = new Rectangle(j * tileWidth, i * tileHeight, tileWidth, tileHeight);
graphics.DrawImage(image, 0, 0, srcRect, GraphicsUnit.Pixel);
using (var ms = new MemoryStream())
{
//TODO: n<>got vettigare <20>n s<> h<>r f<>r att f<> fram bytesen... tar ju <20>r och dagar att ladda nu.
part.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.Seek(0, SeekOrigin.Begin);
ret.Add(new Tile(Texture2D.FromStream(device, ms), new Microsoft.Xna.Framework.Point(j * tileWidth, i * tileHeight)));
}
}
}
return ret;
}
private static int FindNearbyMultiple(int totLen, int chunkLen)
{
chunkLen = totLen / (int)Math.Ceiling(totLen / (double)chunkLen);
var step = 0;
while (step < 100)
{
var t = chunkLen - step;
if ((totLen % t) == 0)
return t;
t = chunkLen + step;
if ((totLen % t) == 0)
return t;
step++;
}
return FindNearbyMultiple(totLen - 1, chunkLen);
}
private static Dictionary<string, byte[]> GetResourceList(string file)
{
var resources = new Dictionary<string, byte[]>();
using (var stream = new ZipInputStream(File.OpenRead(file)))
{
ZipEntry entry = null;
while ((entry = stream.GetNextEntry()) != null)
{
if (entry.Name.Length > 0)
{
var buf = new byte[(int)entry.Size];
stream.Read(buf, 0, buf.Length);
resources.Add(entry.Name.ToLower().Trim(), buf);
}
}
}
return resources;
}
}
}