mirror of
https://github.com/simtactics/mysimulation.git
synced 2025-03-19 08:21:22 +00:00
325 lines
10 KiB
C#
325 lines
10 KiB
C#
|
using System;
|
|||
|
using System.IO;
|
|||
|
using FSO.Files.Utils;
|
|||
|
using Microsoft.Xna.Framework;
|
|||
|
|
|||
|
namespace FSO.Files.Formats.IFF.Chunks
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 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.
|
|||
|
/// </summary>
|
|||
|
public class DGRP : IffChunk
|
|||
|
{
|
|||
|
public DGRPImage[] Images { get; set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets a DGRPImage instance from this DGRP instance.
|
|||
|
/// </summary>
|
|||
|
/// <param name="direction">The direction the DGRP is facing.</param>
|
|||
|
/// <param name="zoom">Zoom level DGRP is drawn at.</param>
|
|||
|
/// <param name="worldRotation">Current rotation of world.</param>
|
|||
|
/// <returns>A DGRPImage instance.</returns>
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Reads a DGRP from a stream instance.
|
|||
|
/// </summary>
|
|||
|
/// <param name="iff">An Iff instance.</param>
|
|||
|
/// <param name="stream">A Stream instance holding a DGRP chunk.</param>
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// A DGRP is made up of multiple DGRPImages,
|
|||
|
/// which are made up of multiple DGRPSprites.
|
|||
|
/// </summary>
|
|||
|
public class DGRPImage
|
|||
|
{
|
|||
|
private DGRP Parent;
|
|||
|
public uint Direction;
|
|||
|
public uint Zoom;
|
|||
|
public DGRPSprite[] Sprites;
|
|||
|
|
|||
|
public DGRPImage(DGRP parent)
|
|||
|
{
|
|||
|
this.Parent = parent;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Reads a DGRPImage from a stream.
|
|||
|
/// </summary>
|
|||
|
/// <param name="iff">An Iff instance.</param>
|
|||
|
/// <param name="stream">A Stream object holding a DGRPImage.</param>
|
|||
|
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
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Makes up a DGRPImage.
|
|||
|
/// </summary>
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Reads a DGRPSprite from a stream.
|
|||
|
/// </summary>
|
|||
|
/// <param name="iff">An Iff instance.</param>
|
|||
|
/// <param name="stream">A Stream object holding a DGRPSprite.</param>
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets position of this sprite.
|
|||
|
/// </summary>
|
|||
|
/// <returns>A Vector2 instance holding position of this sprite.</returns>
|
|||
|
public Vector2 GetPosition()
|
|||
|
{
|
|||
|
var iff = Parent.ChunkParent;
|
|||
|
var spr2 = iff.Get<SPR2>((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<SPR2>((ushort)this.SpriteID);
|
|||
|
if (spr2 != null){
|
|||
|
return spr2.Frames[this.SpriteFrameIndex].GetTexture(device);
|
|||
|
}
|
|||
|
var spr1 = iff.Get<SPR>((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<SPR2>((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<SPR2>((ushort)this.SpriteID);
|
|||
|
if (spr2 != null)
|
|||
|
{
|
|||
|
return spr2.Frames[this.SpriteFrameIndex].GetWorldTexture(device);
|
|||
|
}
|
|||
|
var spr1 = iff.Get<SPR>((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<SPR2>((ushort)this.SpriteID);
|
|||
|
if (spr2 != null)
|
|||
|
{
|
|||
|
var frame = spr2.Frames[this.SpriteFrameIndex];
|
|||
|
return new Point(frame.Width, frame.Height);
|
|||
|
}
|
|||
|
var spr1 = iff.Get<SPR>((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
|
|||
|
}
|
|||
|
}
|