using System;
using System.IO;
using FSO.Files.Utils;
using Microsoft.Xna.Framework;
namespace FSO.Files.Formats.IFF.Chunks
{
///
/// This chunk type collects SPR# and SPR2 resources into a "drawing group" which
/// can be used to display one tile of an object from all directions and zoom levels.
/// Objects which span across multiple tiles have a separate DGRP chunk for each tile.
/// A DGRP chunk always consists of 12 images (one for every direction/zoom level combination),
/// which in turn contain info about one or more sprites.
///
public class DGRP : IffChunk
{
public DGRPImage[] Images { get; set; }
///
/// Gets a DGRPImage instance from this DGRP instance.
///
/// The direction the DGRP is facing.
/// Zoom level DGRP is drawn at.
/// Current rotation of world.
/// A DGRPImage instance.
public DGRPImage GetImage(uint direction, uint zoom, uint worldRotation){
uint rotatedDirection = 0;
/**LeftFront = 0x10,
LeftBack = 0x40,
RightFront = 0x04,
RightBack = 0x01**/
int rotateBits = (int)direction << ((int)worldRotation * 2);
rotatedDirection = (uint)((rotateBits & 255) | (rotateBits >> 8));
foreach(DGRPImage image in Images)
{
if (image.Direction == rotatedDirection && image.Zoom == zoom)
{
return image;
}
}
return null;
}
///
/// Reads a DGRP from a stream instance.
///
/// An Iff instance.
/// A Stream instance holding a DGRP chunk.
public override void Read(IffFile iff, Stream stream)
{
using (var io = IoBuffer.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
{
var version = io.ReadUInt16();
uint imageCount = version < 20003 ? io.ReadUInt16() : io.ReadUInt32();
Images = new DGRPImage[imageCount];
for (var i = 0; i < imageCount; i++)
{
var image = new DGRPImage(this);
image.Read(version, io);
Images[i] = image;
}
}
}
public override bool Write(IffFile iff, Stream stream)
{
using (var io = IoWriter.FromStream(stream, ByteOrder.LITTLE_ENDIAN))
{
io.WriteUInt16(20004);
io.WriteUInt32((uint)Images.Length);
foreach (var img in Images)
{
img.Write(io);
}
}
return true;
}
}
///
/// A DGRP is made up of multiple DGRPImages,
/// which are made up of multiple DGRPSprites.
///
public class DGRPImage
{
private DGRP Parent;
public uint Direction;
public uint Zoom;
public DGRPSprite[] Sprites;
public DGRPImage(DGRP parent)
{
this.Parent = parent;
}
///
/// Reads a DGRPImage from a stream.
///
/// An Iff instance.
/// A Stream object holding a DGRPImage.
public void Read(uint version, IoBuffer io)
{
uint spriteCount = 0;
if (version < 20003){
spriteCount = io.ReadUInt16();
Direction = io.ReadByte();
Zoom = io.ReadByte();
}else{
Direction = io.ReadUInt32();
Zoom = io.ReadUInt32();
spriteCount = io.ReadUInt32();
}
this.Sprites = new DGRPSprite[spriteCount];
for (var i = 0; i < spriteCount; i++){
var sprite = new DGRPSprite(Parent);
sprite.Read(version, io);
this.Sprites[i] = sprite;
}
}
public void Write(IoWriter io)
{
io.WriteUInt32(Direction);
io.WriteUInt32(Zoom);
io.WriteUInt32((uint)Sprites.Length);
foreach (var spr in Sprites)
{
spr.Write(io);
}
}
}
[Flags]
public enum DGRPSpriteFlags
{
Flip = 0x1,
Unknown = 0x2, //set for end table
Luminous = 0x4,
Unknown2 = 0x8,
Unknown3 = 0x10 //set for end table
}
///
/// Makes up a DGRPImage.
///
public class DGRPSprite : ITextureProvider, IWorldTextureProvider
{
private DGRP Parent;
public uint SpriteID;
public uint SpriteFrameIndex;
public DGRPSpriteFlags Flags;
public Vector2 SpriteOffset;
public Vector3 ObjectOffset;
public bool Flip {
get { return (Flags & DGRPSpriteFlags.Flip) > 0; }
set {
Flags = Flags & (~DGRPSpriteFlags.Flip);
if (value) Flags |= DGRPSpriteFlags.Flip;
}
}
public bool Luminous
{
get { return (Flags & DGRPSpriteFlags.Luminous) > 0; }
set
{
Flags = Flags & (~DGRPSpriteFlags.Luminous);
if (value) Flags |= DGRPSpriteFlags.Luminous;
}
}
public DGRPSprite(DGRP parent)
{
this.Parent = parent;
}
///
/// Reads a DGRPSprite from a stream.
///
/// An Iff instance.
/// A Stream object holding a DGRPSprite.
public void Read(uint version, IoBuffer io)
{
if (version < 20003)
{
//Unknown ignored "Type" field
var type = io.ReadUInt16();
SpriteID = io.ReadUInt16();
SpriteFrameIndex = io.ReadUInt16();
var flagsRaw = io.ReadUInt16();
Flags = (DGRPSpriteFlags)flagsRaw;
SpriteOffset.X = io.ReadInt16();
SpriteOffset.Y = io.ReadInt16();
if (version == 20001)
{
ObjectOffset.Z = io.ReadFloat();
}
}
else
{
SpriteID = io.ReadUInt32();
SpriteFrameIndex = io.ReadUInt32();
SpriteOffset.X = io.ReadInt32();
SpriteOffset.Y = io.ReadInt32();
ObjectOffset.Z = io.ReadFloat();
Flags = (DGRPSpriteFlags)io.ReadUInt32();
if (version == 20004)
{
ObjectOffset.X = io.ReadFloat();
ObjectOffset.Y = io.ReadFloat();
}
}
}
public void Write(IoWriter io)
{
io.WriteUInt32(SpriteID);
io.WriteUInt32(SpriteFrameIndex);
io.WriteInt32((int)SpriteOffset.X);
io.WriteInt32((int)SpriteOffset.Y);
io.WriteFloat(ObjectOffset.Z);
io.WriteUInt32((uint)Flags);
io.WriteFloat(ObjectOffset.X);
io.WriteFloat(ObjectOffset.Y);
}
///
/// Gets position of this sprite.
///
/// A Vector2 instance holding position of this sprite.
public Vector2 GetPosition()
{
var iff = Parent.ChunkParent;
var spr2 = iff.Get((ushort)this.SpriteID);
if (spr2 != null)
{
return spr2.Frames[this.SpriteFrameIndex].Position;
}
return new Vector2(0, 0);
}
#region ITextureProvider Members
public Microsoft.Xna.Framework.Graphics.Texture2D GetTexture(Microsoft.Xna.Framework.Graphics.GraphicsDevice device){
var iff = Parent.ChunkParent;
var spr2 = iff.Get((ushort)this.SpriteID);
if (spr2 != null){
return spr2.Frames[this.SpriteFrameIndex].GetTexture(device);
}
var spr1 = iff.Get((ushort)this.SpriteID);
if (spr1 != null){
return spr1.Frames[(int)this.SpriteFrameIndex].GetTexture(device);
}
return null;
}
#endregion
#region IWorldTextureProvider Members
public byte[] GetDepth()
{
var iff = Parent.ChunkParent;
var spr2 = iff.Get((ushort)this.SpriteID);
if (spr2 != null)
{
spr2.Frames[this.SpriteFrameIndex].DecodeIfRequired(true);
var buf = spr2.Frames[this.SpriteFrameIndex].ZBufferData;
return buf;
}
return null;
}
public WorldTexture GetWorldTexture(Microsoft.Xna.Framework.Graphics.GraphicsDevice device)
{
var iff = Parent.ChunkParent;
var spr2 = iff.Get((ushort)this.SpriteID);
if (spr2 != null)
{
return spr2.Frames[this.SpriteFrameIndex].GetWorldTexture(device);
}
var spr1 = iff.Get((ushort)this.SpriteID);
if (spr1 != null)
{
var result = new WorldTexture();
result.Pixel = spr1.Frames[(int)this.SpriteFrameIndex].GetTexture(device);
return result;
}
return null;
}
public Point GetDimensions()
{
var iff = Parent.ChunkParent;
var spr2 = iff.Get((ushort)this.SpriteID);
if (spr2 != null)
{
var frame = spr2.Frames[this.SpriteFrameIndex];
return new Point(frame.Width, frame.Height);
}
var spr1 = iff.Get((ushort)this.SpriteID);
if (spr1 != null)
{
var result = new WorldTexture();
var frame = spr1.Frames[(int)this.SpriteFrameIndex];
return new Point(frame.Width, frame.Height);
}
return new Point(1, 1);
}
#endregion
}
}