/
Anim.cs
289 lines (273 loc) · 12 KB
/
Anim.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*
* Idmr.LfdReader.dll, Library file to read and write LFD resource files
* Copyright (C) 2009-2021 Michael Gaisser (mjgaisser@gmail.com)
* Licensed under the MPL v2.0 or later
*
* Full notice in help/Idmr.LfdReader.chm
* Version: 1.2
*/
/* CHANGE LOG
* v1.2, 160712
* [ADD] _isModified edits
* [DEL] removed old code duplicating DELT data
* v1.1, 141215
* [UPD] changed license to MPL
* v1.0
*/
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Idmr.Common;
namespace Idmr.LfdReader
{
/// <summary>Object for "ANIM" animation resources.</summary>
/// <remarks>The Anim resource is simply a collection of <see cref="Delt"/> resources and the box that encompasses all of them.
/// Like the <see cref="Delt"/>, the palette is controlled by the <see cref="Film"/> that is defining the current view.
/// The <see cref="Film"/> also controls the Anim's animation speed, direction and looping.</remarks>
/// <example><h4>Raw Data definition</h4>
/// <code>
/// RawData
/// {
/// /* 0x00 */ short NumberOfFrames;
/// /* 0x02 */ Frame[NumberOfFrames] Frames;
/// }
///
/// Frame
/// {
/// /* 0x00 */ int Length;
/// /* 0x02 */ Delt.RawData Image;
/// }</code>
/// <para>The only real unique value in the Anim is the number of frames that are stored within the resource.
/// The Frame object is nothing more than a wrapper for the <see cref="Delt"/> resource with only the <i>Frame.Length</i> value which is just the encoded size of <i>Frame.Image</i>.
/// The <see cref="Location"/> and <see cref="Size"/> properties are derived from the dimensions of the individual Frames.</para>
/// All Frames share the same palette.</example>
public partial class Anim : Resource
{
ColorPalette _palette = null;
short _left = -1;
short _top = -1;
short _width = -1;
short _height = -1;
FrameCollection _frames;
#region constructors
/// <summary>Creates a blank resource.</summary>
public Anim()
{
_type = ResourceType.Anim;
_frames = new FrameCollection(this);
}
/// <summary>Creates a new instance from an existing opened file with default 8bpp Palette.</summary>
/// <param name="stream">The opened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Anim(FileStream stream, long filePosition)
{
read(stream, filePosition);
}
/// <summary>Creates a new instance from an existing opened file with the supplied Palette.</summary>
/// <param name="stream">This opened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <param name="palette">The colors used for the resource.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Anim(FileStream stream, long filePosition, ColorPalette palette)
{
_palette = palette;
read(stream, filePosition);
}
/// <summary>Creates a new instance from an existing opened file with the supplied Palette array.</summary>
/// <param name="stream">The opened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <param name="palettes">The colors used for the resource.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Anim(FileStream stream, long filePosition, Pltt[] palettes)
{
_palette = new Bitmap(1, 1, PixelFormat.Format8bppIndexed).Palette;
read(stream, filePosition);
SetPalette(palettes);
}
/// <summary>Creates a new instance from an existing file with default 8bpp Palette.</summary>
/// <param name="path">The full path to the unopened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Anim(string path, long filePosition)
{
FileStream stream = File.OpenRead(path);
read(stream, filePosition);
stream.Close();
}
/// <summary>Creates a new instance from an existing file with the supplied Palette.</summary>
/// <param name="path">The full path to the unopened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <param name="palette">The colors used for the resource.</param>
/// <exception cref="LoadFileException">Typically due to file corruption.</exception>
public Anim(string path, long filePosition, ColorPalette palette)
{
_palette = palette;
FileStream stream = File.OpenRead(path);
read(stream, filePosition);
stream.Close();
}
/// <summary>Creates a new instance from an exsiting file with the supplied Palette array.</summary>
/// <param name="path">The full path to the unopened LFD file.</param>
/// <param name="filePosition">The offset of the beginning of the resource.</param>
/// <param name="palettes">The colors used for the resource.</param>
/// <exception cref="Idmr.Common.LoadFileException">Typically due to file corruption.</exception>
public Anim(string path, long filePosition, Pltt[] palettes)
{
FileStream stream = File.OpenRead(path);
read(stream, filePosition);
stream.Close();
SetPalette(palettes);
}
#endregion constructors
void read(FileStream stream, long filePosition)
{
try { _process(stream, filePosition); }
catch (Exception x) { throw new LoadFileException(x); }
}
#region public methods
/// <summary>Processes raw data to populate the resource.</summary>
/// <param name="raw">Raw byte data.</param>
/// <param name="containsHeader">Whether or not <paramref name="raw"/> contains the resource Header information.</param>
/// <exception cref="ArgumentException">Header-defined <see cref="Type"/> is not <see cref="Resource.ResourceType.Anim"/>.</exception>
public override void DecodeResource(byte[] raw, bool containsHeader)
{
_decodeResource(raw, containsHeader);
if (_type != ResourceType.Anim) throw new ArgumentException("Raw header is not for an Anim resource");
short numberOfFrames = BitConverter.ToInt16(_rawData, 0);
_frames = new FrameCollection(this);
for (int i = 0; i < numberOfFrames; i++) _frames.Add(new Frame(this));
int frameLength;
int offset = 2;
for (int i = 0; i < NumberOfFrames; i++)
{
frameLength = BitConverter.ToInt32(_rawData, offset);
byte[] delt = new byte[frameLength];
ArrayFunctions.TrimArray(_rawData, offset + 4, delt);
_frames[i]._delt.DecodeResource(delt, false);
if (HasDefinedPalette) _frames[i]._delt.Palette = _palette;
offset += frameLength + 4;
}
recalculateDimensions();
}
/// <summary>Prepares the resource for writing and updates <see cref="Resource.RawData"/>.</summary>
public override void EncodeResource()
{
int len = 2;
for (int i = 0; i < NumberOfFrames; i++)
{
_frames[i]._delt.EncodeResource();
len += _frames[i]._delt.Length + 4;
}
byte[] raw = new byte[len];
int offset = 0;
ArrayFunctions.WriteToArray(NumberOfFrames, raw, ref offset);
for (int i = 0; i < NumberOfFrames; i++)
{
ArrayFunctions.WriteToArray(_frames[i]._delt.Length + 4, raw, ref offset);
ArrayFunctions.WriteToArray(_frames[i]._delt.RawData, raw, ref offset);
}
_rawData = raw;
}
/// <summary>Sets the colors used for the Anim.</summary>
/// <param name="palette">The colors to be used.</param>
/// <remarks>All <see cref="Frame.Image">Images</see> are updated.</remarks>
public void SetPalette(ColorPalette palette)
{
_palette = palette;
for (int i = 0; i < _frames.Count; i++) _frames[i]._delt.Palette = _palette;
}
/// <summary>Sets the colors used for the Anim.</summary>
/// <param name="palettes">The colors to be used.</param>
/// <remarks>All <see cref="Frame.Image">Images</see> are updated.</remarks>
public void SetPalette(Pltt[] palettes) { SetPalette(Pltt.ConvertToPalette(palettes)); }
#endregion public methods
#region public properties
/// <summary>Determines if <see cref="Frame.Image">Images</see> should be returned sized relative to <see cref="Location"/>.</summary>
public bool RelativePosition { get; set; }
/// <summary>Gets total number of frames within the resource.</summary>
public short NumberOfFrames { get { return (short)_frames.Count; } }
/// <summary>Gets or sets the Left screen location of the resource.</summary>
/// <remarks>Each <see cref="Frame"/> will update its <see cref="Frame.Position"/> to maintain it's relative distance to <see cref="Location"/>.</remarks>
/// <exception cref="BoundaryException"><i>value</i> causes portion of image to be off-screen.</exception>
public short Left
{
get { return _left; }
set
{
if (value >= Delt.MaximumWidth - _width || value < 0)
throw new BoundaryException("value", "0-" + (Delt.MaximumWidth - _width));
short diff = (short)(value - _left);
for (int f = 0; f < NumberOfFrames; f++) _frames[f].Left += diff;
_left = value;
_isModifed = true;
}
}
/// <summary>Gets or sets the Top screen location of the resource.</summary>
/// <remarks>Each <see cref="Frame"/> will update its <see cref="Frame.Position"/> to maintain it's relative distance to <see cref="Location"/>.</remarks>
/// <exception cref="BoundaryException"><i>value</i> causes portion of image to be off-screen.</exception>
public short Top
{
get { return _top; }
set
{
if (value >= Delt.MaximumHeight - _height || value < 0)
throw new BoundaryException("value", "0-" + (Delt.MaximumHeight - _height));
short diff = (short)(value - _top);
for (int f = 0; f < NumberOfFrames; f++) _frames[f].Top += diff;
_top = value;
_isModifed = true;
}
}
/// <summary>Gets the maximum width occupied by the resource.</summary>
public short Width { get { return _width; } }
/// <summary>Gets the maximum height occupied by the resource.</summary>
public short Height { get { return _height; } }
/// <summary>Gets or sets the resource screen location.</summary>
/// <remarks>Each <see cref="Frame"/> will update its <see cref="Frame.Position"/> to maintain it's relative distance to <see cref="Location"/>.</remarks>
/// <exception cref="BoundaryException"><i>value</i> causes portion of image to be off-screen.</exception>
public Point Location
{
get { return new Point(_left, _top); }
set
{
try
{
Left = (short)value.X;
Top = (short)value.Y;
}
catch (BoundaryException x)
{ throw new BoundaryException("value", "0,0 - " + (Delt.MaximumWidth - _width) + "," + (Delt.MaximumHeight - _height), x); }
}
}
/// <summary>Gets the maximum size occupied by the image.</summary>
public Size Size { get { return new Size(_width, _height); } }
/// <summary>Gets if the Anim palette has been defined.</summary>
public bool HasDefinedPalette { get { return _palette != null; } }
/// <summary>When <b>true</b>, locks the overall Anim boundaries.</summary>
/// <remarks>When fixed, <see cref="Frame.Image"/> and <see cref="Frame.Position"/> cannot be edited in a manner that would result in portions of the <see cref="Frame"/> residing outside the original boundaries of the Anim.<br/>
/// Defaults to <b>false</b>.</remarks>
public bool HasFixedDimensions { get; set; }
/// <summary>Gets the collection of images.</summary>
public FrameCollection Frames { get { return _frames; } }
#endregion public properties
internal void recalculateDimensions()
{
short left = Delt.MaximumWidth, right = -1, top = Delt.MaximumHeight, bottom = -1;
for (int f = 0; f < NumberOfFrames; f++)
{
left = (_frames[f].Left < left ? _frames[f].Left : left);
top = (_frames[f].Top < top ? _frames[f].Top : top);
short frameRight = (short)(_frames[f].Left + _frames[f].Width - 1);
right = (frameRight > right ? frameRight : right);
short frameBottom = (short)(_frames[f].Top + _frames[f].Height - 1);
bottom = (frameBottom > bottom ? frameBottom : bottom);
}
_left = left;
_top = top;
_width = (short)(right - left + 1);
_height = (short)(bottom - top + 1);
}
}
}