git-svn-id: svn://svn.ijw.co.nz/svn/OpenRa@1066 993157c7-ee19-0410-b2c4-bb4e9862e678

This commit is contained in:
chrisf
2007-06-23 18:42:56 +00:00
parent df767490a3
commit cb26bbc491
5 changed files with 381 additions and 10 deletions

View File

@@ -28,12 +28,32 @@ namespace ShpViewer
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.SuspendLayout();
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(292, 273);
this.flowLayoutPanel1.TabIndex = 0;
//
// ShpViewForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 273);
this.Controls.Add(this.flowLayoutPanel1);
this.Name = "ShpViewForm";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
}
}

View File

@@ -34,18 +34,16 @@ namespace ShpViewer
}
InitializeComponent();
}
protected override void OnPaint( PaintEventArgs e )
{
base.OnPaint( e );
int y = 10;
foreach( Bitmap b in bitmaps )
foreach (Bitmap b in bitmaps)
{
e.Graphics.DrawImage( b, 10, y );
y += 10 + b.Height;
PictureBox p = new PictureBox();
p.Image = b;
p.Size = b.Size;
flowLayoutPanel1.Controls.Add(p);
}
Focus();
}
}
}

120
ShpViewer/ShpViewForm.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -51,6 +51,10 @@
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="ShpViewForm.resx">
<SubType>Designer</SubType>
<DependentUpon>ShpViewForm.cs</DependentUpon>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>

229
aud format.txt Normal file
View File

@@ -0,0 +1,229 @@
THE AUD FILE FORMAT
Revision 3
by Vladan Bato (bat22@geocities.com)
In this document I'll try to describe the AUD file format used in
Command & Conquer and Redalert.
Command & Conquer is a trademark of Westwood Studios, Inc.
Command & Conquer is Copyright (C)1995 Westwood Studios, Inc.
Command & Conquer: Red Alert is a trademark of Westwood Studios, Inc.
Command & Conquer: Red Alert is Copyright (C)1995,1996 Westwood Studios, Inc.
The information provided here is for anyone who would like to make an
AUD player program or AUD to WAV or WAV to AUD converters.
Most information about AUD files and IMA-ADPCM compression has been
provided by Douglas McFadyen.
I won't explain here the format of the WAV files. You'll have to find this
info yourself. I'll just tell you how to obtain 16-bit PCM data and how
to encode it.
I will use Pascal-like notation throughout this document.
===============================
0. IMPRTANT NOTE - WHAT'S NEW
===============================
This revision contains an important difference in the IMA-ADPCM compression
routine. Instead of computing the diffrence between the current and
previous sample, it computes the difference between the current sample
and the value that the decoding routine will predict for the previous
sample.
This is the way the algorithm is implemented in C&C.
If you implement it the way it was in previous revisions of this document,
the sound will be the same but there will be a "pop" sound at the end.
==============
1. AUD FILES
==============
The AUD files have the following header :
Header : record
SamplesPerSec : word; {Frequency}
Size : longint; {Size of file (without header)}
OutSize : longint; {Size of ouput data}
Flags : byte; {bit 0=stereo, bit 1=16bit}
Typ : byte; {1=WW compressed, 99=IMA ADPCM}
end;
There are two types of compression. The first is the IMA-ADPCM compression
used for 16-bit sound. It's used in most AUD files.
The other one is a Westwood's proprietary compression for 8-bit sound and
is used only for death screams. I won't describe it in this document
because I don't know how it works.
The rest of the AUD files is divided in chunks. These are usually 512
bytes long, except for the last one.
Each chunk has the following header :
ChunkHd : record
Size : word; {Size of compressed data}
OutSize : word; {Size of ouput data}
ID : longint; {Always $0000DEAF}
end;
The IMA-ADPCM compression compresses 16-bit samples to 4 bits. This means
that OutSize will be apporximately 4*Size.
The IMA-ADPCM compression and decompression are described in the following
sections.
Note that the current sample value and index into the Step Table should
be initialized to 0 at the start and are mantained across the chunks
(see below).
==========================
2. IMA-ADPCM COMPRESSION
==========================
I won't describe the theory behind the IMA-ADPCM compression. I will just
give some pseudo code to compress and decompress data.
The compression algorithm takes a stream of signed 16-bit samples in input
and produces a stream of 4-bit codes in output.
The 4-bit codes are stored in pairs (two codes in one byte). The first one
is stored in the lower four bits.
Two varaibles must be mantained while compressing : the previous sample
value and the current index into the step table.
You can find the Step Table in Appendix B.
The Index adjustment table is in Appendix A.
Here's the pseudo-code that will do the compression :
Index:=0;
Prev_Sample:=0;
while there_is_more_data do
begin
Cur_Sample:=Get_Next_Sample;
Delta:=Cur_Sample-Prev_Sample;
if Delta<0 then
begin
Delta:=-Delta;
Sb:=1;
end else Sb:=0;
{Sb is bit 4 of the output Code (sign bit)}
Code := 4*Delta div Step_Table[Index];
if Code>7 then Code:=7;
{These are the 3 low-order bits of output code}
Index:=Index+Index_Adjust[Code];
if Index<0 then Index:=0;
if Index>88 the Index:=88;
Predicted_Delta:=(Step_Table[Index]*Code) div 4 +
Step_Table[Index] div 8;
{This is the Delta that decoding routine will compute}
Prev_Sample:=Prev_Sample+Predicted_Delta;
if Prev_Sample>32767 then Prev_Sample:=32767
else if Prev_Sample<-32768 then Prev_Sample:=-32768;
{Prev_Sample is the sample value that the decoding routine
will compute}
Output_Code(Code+Sb*8);
end;
Note that this code is usually implemented in more efficient manner
(No need to divide).
The Get_Next_Sample function should return the next sample from the input
buffer.
The Output_Code function should store the 4-bit code to the output buffer.
One byte contains two 4-bit codes, and this function should take care of
this.
============================
3. IMA-ADPCM DECOMPRESSION
============================
It is the exact opposite of the above. It receives 4-bit codes in input
and produce 16-bit samples in output.
Again you have to mantain an Index into the Step Table an the current
sample value.
The tables used are the same as for compression.
Here's the code :
Index:=0;
Cur_Sample:=0;
while there_is_more_data do
begin
Code:=Get_Next_Code;
if (Code and $8) <> 0 then Sb:=1 else Sb:=0;
Code:=Code and $7;
{Separate the sign bit from the rest}
Delta:=(Step_Table[Index]*Code) div 4 + Step_Table[Index] div 8;
{The last one is to minimize errors}
if Sb=1 then Delta:=-Delta;
Cur_Sample:=Cur_Sample+Delta;
if Cur_Sample>32767 then Cur_Sample:=32767
else if Cur_Sample<-32768 then Cur_Sample:=-32768;
Output_Sample(Cur_Sample);
Index:=Index+Index_Adjust[Code];
if Index<0 then Index:=0;
if Index>88 the Index:=88;
end;
Again, this can be done more efficiently (no need for multiplication).
The Get_Next_Code function should return the next 4-bit code. It must
extract it from the input buffer (note that two 4-bit codes are stored
in the same byte, the first one in the lower bits).
The Output_Sample function should write the signed 16-bit sample to the
output buffer.
=========================================
Appendix A : THE INDEX ADJUSTMENT TABLE
=========================================
Index_Adjust : array [0..7] of integer = (-1,-1,-1,-1,2,4,6,8);
=============================
Appendix B : THE STEP TABLE
=============================
Steps_Table : array [0..88] of integer =(
7, 8, 9, 10, 11, 12, 13, 14, 16,
17, 19, 21, 23, 25, 28, 31, 34, 37,
41, 45, 50, 55, 60, 66, 73, 80, 88,
97, 107, 118, 130, 143, 157, 173, 190, 209,
230, 253, 279, 307, 337, 371, 408, 449, 494,
544, 598, 658, 724, 796, 876, 963, 1060, 1166,
1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749,
3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289,
16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 );
---
Vladan Bato (bat22@geocities.com)
http://www.geocities.com/SiliconValley/8682