2013-12-17 08:19:40 +00:00
#region = = = = = = = = = = = = = = = = = = Namespaces
using System ;
using System.Collections.Generic ;
using System.IO ;
using CodeImp.DoomBuilder.Config ;
using CodeImp.DoomBuilder.Geometry ;
using CodeImp.DoomBuilder.Map ;
using CodeImp.DoomBuilder.Types ;
#endregion
namespace CodeImp.DoomBuilder.IO
{
internal class ClipboardStreamReader
{
#region = = = = = = = = = = = = = = = = = = Variables
private struct SidedefData
{
public int OffsetX ;
public int OffsetY ;
public int SectorID ;
public string HighTexture ;
public string MiddleTexture ;
public string LowTexture ;
public Dictionary < string , UniValue > Fields ;
public Dictionary < string , bool > Flags ;
}
#endregion
#region = = = = = = = = = = = = = = = = = = Reading
// This reads from a stream
public MapSet Read ( MapSet map , Stream stream ) {
BinaryReader reader = new BinaryReader ( stream ) ;
// Read the map
Dictionary < int , Vertex > vertexlink = ReadVertices ( map , reader ) ;
Dictionary < int , Sector > sectorlink = ReadSectors ( map , reader ) ;
Dictionary < int , SidedefData > sidedeflink = ReadSidedefs ( reader ) ;
ReadLinedefs ( map , reader , vertexlink , sectorlink , sidedeflink ) ;
ReadThings ( map , reader ) ;
return map ;
}
private Dictionary < int , Vertex > ReadVertices ( MapSet map , BinaryReader reader ) {
int count = reader . ReadInt32 ( ) ;
// Create lookup table
Dictionary < int , Vertex > link = new Dictionary < int , Vertex > ( count ) ;
// Go for all collections
map . SetCapacity ( map . Vertices . Count + count , 0 , 0 , 0 , 0 ) ;
for ( int i = 0 ; i < count ; i + + ) {
float x = reader . ReadSingle ( ) ;
float y = reader . ReadSingle ( ) ;
float zc = reader . ReadSingle ( ) ;
float zf = reader . ReadSingle ( ) ;
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Vertex v = map . CreateVertex ( new Vector2D ( x , y ) ) ;
if ( v ! = null ) {
//zoffsets
v . ZCeiling = zc ;
v . ZFloor = zf ;
// Add custom fields
v . Fields . BeforeFieldsChange ( ) ;
foreach ( KeyValuePair < string , UniValue > group in fields ) {
v . Fields . Add ( group . Key , group . Value ) ;
}
// Add it to the lookup table
link . Add ( i , v ) ;
}
}
// Return lookup table
return link ;
}
private Dictionary < int , Sector > ReadSectors ( MapSet map , BinaryReader reader ) {
int count = reader . ReadInt32 ( ) ;
// Create lookup table
Dictionary < int , Sector > link = new Dictionary < int , Sector > ( count ) ;
// Go for all collections
map . SetCapacity ( 0 , 0 , 0 , map . Sectors . Count + count , 0 ) ;
for ( int i = 0 ; i < count ; i + + ) {
int tag = reader . ReadInt32 ( ) ;
int effect = reader . ReadInt32 ( ) ;
int hfloor = reader . ReadInt32 ( ) ;
int hceil = reader . ReadInt32 ( ) ;
int bright = reader . ReadInt32 ( ) ;
string tfloor = ReadString ( reader ) ;
string tceil = ReadString ( reader ) ;
2014-08-25 11:15:19 +00:00
//mxd. Slopes
float foffset = reader . ReadSingle ( ) ;
Vector3D fslope = new Vector3D ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
float coffset = reader . ReadSingle ( ) ;
Vector3D cslope = new Vector3D ( reader . ReadSingle ( ) , reader . ReadSingle ( ) , reader . ReadSingle ( ) ) ;
2013-12-17 08:19:40 +00:00
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
for ( int f = 0 ; f < numFlags ; f + + )
stringflags . Add ( ReadString ( reader ) , true ) ;
//add missing flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SectorFlags ) {
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Sector s = map . CreateSector ( ) ;
if ( s ! = null ) {
2014-08-25 11:15:19 +00:00
s . Update ( hfloor , hceil , tfloor , tceil , effect , stringflags , tag , bright , foffset , fslope , coffset , cslope ) ;
2013-12-17 08:19:40 +00:00
// Add custom fields
s . Fields . BeforeFieldsChange ( ) ;
foreach ( KeyValuePair < string , UniValue > group in fields ) {
s . Fields . Add ( group . Key , group . Value ) ;
}
// Add it to the lookup table
link . Add ( i , s ) ;
}
}
// Return lookup table
return link ;
}
// This reads the linedefs and sidedefs
private void ReadLinedefs ( MapSet map , BinaryReader reader , Dictionary < int , Vertex > vertexlink , Dictionary < int , Sector > sectorlink , Dictionary < int , SidedefData > sidedeflink ) {
int count = reader . ReadInt32 ( ) ;
// Go for all lines
map . SetCapacity ( 0 , map . Linedefs . Count + count , map . Sidedefs . Count + sidedeflink . Count , 0 , 0 ) ;
for ( int i = 0 ; i < count ; i + + ) {
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
int tag = reader . ReadInt32 ( ) ;
int v1 = reader . ReadInt32 ( ) ;
int v2 = reader . ReadInt32 ( ) ;
int s1 = reader . ReadInt32 ( ) ;
int s2 = reader . ReadInt32 ( ) ;
int special = reader . ReadInt32 ( ) ;
for ( int a = 0 ; a < Linedef . NUM_ARGS ; a + + ) {
args [ a ] = reader . ReadInt32 ( ) ;
}
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
for ( int f = 0 ; f < numFlags ; f + + )
stringflags . Add ( ReadString ( reader ) , true ) ;
//add missing flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . LinedefFlags ) {
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
//add missing activations
foreach ( LinedefActivateInfo activate in General . Map . Config . LinedefActivates ) {
if ( stringflags . ContainsKey ( activate . Key ) ) continue ;
stringflags . Add ( activate . Key , false ) ;
}
// Read custom fields
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
// Check if not zero-length
if ( Vector2D . ManhattanDistance ( vertexlink [ v1 ] . Position , vertexlink [ v2 ] . Position ) > 0.0001f ) {
// Create new linedef
Linedef l = map . CreateLinedef ( vertexlink [ v1 ] , vertexlink [ v2 ] ) ;
if ( l ! = null ) {
l . Update ( stringflags , 0 , tag , special , args ) ;
l . UpdateCache ( ) ;
// Add custom fields
l . Fields . BeforeFieldsChange ( ) ;
foreach ( KeyValuePair < string , UniValue > group in fields ) {
l . Fields . Add ( group . Key , group . Value ) ;
}
// Connect sidedefs to the line
if ( s1 > - 1 ) {
if ( s1 < sidedeflink . Count )
2014-02-26 14:11:06 +00:00
AddSidedef ( map , sidedeflink [ s1 ] , l , true , sectorlink ) ;
2013-12-17 08:19:40 +00:00
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid front sidedef " + s1 + ". Sidedef has been removed." ) ;
}
if ( s2 > - 1 ) {
if ( s2 < sidedeflink . Count )
2014-02-26 14:11:06 +00:00
AddSidedef ( map , sidedeflink [ s2 ] , l , false , sectorlink ) ;
2013-12-17 08:19:40 +00:00
else
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " references invalid back sidedef " + s1 + ". Sidedef has been removed." ) ;
}
}
} else {
General . ErrorLogger . Add ( ErrorType . Warning , "Linedef " + i + " is zero-length. Linedef has been removed." ) ;
}
}
}
2014-05-20 09:09:28 +00:00
private static void AddSidedef ( MapSet map , SidedefData data , Linedef ld , bool front , Dictionary < int , Sector > sectorlink ) {
2013-12-17 08:19:40 +00:00
// Create sidedef
if ( sectorlink . ContainsKey ( data . SectorID ) ) {
Sidedef s = map . CreateSidedef ( ld , front , sectorlink [ data . SectorID ] ) ;
if ( s ! = null ) {
s . Update ( data . OffsetX , data . OffsetY , data . HighTexture , data . MiddleTexture , data . LowTexture , data . Flags ) ;
// Add custom fields
foreach ( KeyValuePair < string , UniValue > group in data . Fields ) {
s . Fields . Add ( group . Key , group . Value ) ;
}
}
} else {
General . ErrorLogger . Add ( ErrorType . Warning , "Sidedef references invalid sector " + data . SectorID + ". Sidedef has been removed." ) ;
}
}
private Dictionary < int , SidedefData > ReadSidedefs ( BinaryReader reader ) {
Dictionary < int , SidedefData > sidedeflink = new Dictionary < int , SidedefData > ( ) ;
int count = reader . ReadInt32 ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
SidedefData data = new SidedefData ( ) ;
data . OffsetX = reader . ReadInt32 ( ) ;
data . OffsetY = reader . ReadInt32 ( ) ;
data . SectorID = reader . ReadInt32 ( ) ;
data . HighTexture = ReadString ( reader ) ;
data . MiddleTexture = ReadString ( reader ) ;
data . LowTexture = ReadString ( reader ) ;
//flags
2014-02-26 14:11:06 +00:00
data . Flags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
for ( int f = 0 ; f < numFlags ; f + + )
data . Flags . Add ( ReadString ( reader ) , true ) ;
//add missing flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . SidedefFlags ) {
if ( data . Flags . ContainsKey ( flag . Key ) ) continue ;
data . Flags . Add ( flag . Key , false ) ;
}
//custom fields
data . Fields = ReadCustomFields ( reader ) ;
sidedeflink . Add ( i , data ) ;
}
return sidedeflink ;
}
private void ReadThings ( MapSet map , BinaryReader reader ) {
int count = reader . ReadInt32 ( ) ;
// Go for all collections
map . SetCapacity ( 0 , 0 , 0 , 0 , map . Things . Count + count ) ;
for ( int i = 0 ; i < count ; i + + ) {
int [ ] args = new int [ Linedef . NUM_ARGS ] ;
int tag = reader . ReadInt32 ( ) ;
float x = reader . ReadSingle ( ) ;
float y = reader . ReadSingle ( ) ;
float height = reader . ReadSingle ( ) ;
int angledeg = reader . ReadInt32 ( ) ;
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
int pitch = reader . ReadInt32 ( ) ; //mxd
int roll = reader . ReadInt32 ( ) ; //mxd
float scaleX = reader . ReadSingle ( ) ; //mxd
float scaleY = reader . ReadSingle ( ) ; //mxd
2013-12-17 08:19:40 +00:00
int type = reader . ReadInt32 ( ) ;
int special = reader . ReadInt32 ( ) ;
for ( int a = 0 ; a < Linedef . NUM_ARGS ; a + + ) {
args [ a ] = reader . ReadInt32 ( ) ;
}
//flags
2014-02-26 14:11:06 +00:00
Dictionary < string , bool > stringflags = new Dictionary < string , bool > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int numFlags = reader . ReadInt32 ( ) ;
for ( int f = 0 ; f < numFlags ; f + + )
stringflags . Add ( ReadString ( reader ) , true ) ;
//add missing flags
foreach ( KeyValuePair < string , string > flag in General . Map . Config . ThingFlags ) {
if ( stringflags . ContainsKey ( flag . Key ) ) continue ;
stringflags . Add ( flag . Key , false ) ;
}
// Create new item
Dictionary < string , UniValue > fields = ReadCustomFields ( reader ) ;
Thing t = map . CreateThing ( ) ;
if ( t ! = null ) {
Model rendering (all modes): UDMF scale, pitch and roll are now displayed.
Thing Edit Form, UDMF: added controls for setting pitch, roll, scale, render style, fill color, alpha, health and score.
Visual mode, UDMF: UDMF scale is now applied when rendering sprites.
Added Thing Statistics form (Edit -> View Thing Types...), which shows all loaded thing types with some additional info.
Visual mode: sprites with negative ScaleX and positive ScaleY were not rendered properly.
Classic modes: display was not updated after loading a sprite.
Current testing engine change was not saved on closing the program when no other game configuration settings were changed.
2014-04-30 10:01:22 +00:00
t . Update ( type , x , y , height , angledeg , pitch , roll , scaleX , scaleY , stringflags , tag , special , args ) ;
2013-12-17 08:19:40 +00:00
// Add custom fields
t . Fields . BeforeFieldsChange ( ) ;
foreach ( KeyValuePair < string , UniValue > group in fields ) {
t . Fields . Add ( group . Key , group . Value ) ;
}
}
}
}
private Dictionary < string , UniValue > ReadCustomFields ( BinaryReader reader ) {
2014-02-26 14:11:06 +00:00
Dictionary < string , UniValue > fields = new Dictionary < string , UniValue > ( StringComparer . Ordinal ) ;
2013-12-17 08:19:40 +00:00
int fieldscount = reader . ReadInt32 ( ) ;
for ( int f = 0 ; f < fieldscount ; f + + ) {
string name = ReadString ( reader ) ;
UniversalType type = ( UniversalType ) reader . ReadInt32 ( ) ;
UniversalType valueType = ( UniversalType ) reader . ReadInt32 ( ) ;
switch ( valueType ) {
case UniversalType . Float :
fields . Add ( name , new UniValue ( type , reader . ReadSingle ( ) ) ) ;
break ;
case UniversalType . Boolean :
fields . Add ( name , new UniValue ( type , reader . ReadBoolean ( ) ) ) ;
break ;
case UniversalType . Integer :
fields . Add ( name , new UniValue ( type , reader . ReadInt32 ( ) ) ) ;
break ;
case UniversalType . String :
fields . Add ( name , new UniValue ( type , ReadString ( reader ) ) ) ;
break ;
default : //WOLOLO! ERRORS!
throw new Exception ( "Got unknown value type while reading custom fields from clipboard data! Field '" + name + "', type '" + type + "', primitive type '" + valueType + "'" ) ;
}
}
return fields ;
}
2014-05-20 09:09:28 +00:00
private static string ReadString ( BinaryReader reader ) {
2013-12-17 08:19:40 +00:00
int len = reader . ReadInt32 ( ) ;
if ( len = = 0 ) return string . Empty ;
char [ ] chars = new char [ len ] ;
2014-05-20 09:09:28 +00:00
for ( int i = 0 ; i < len ; + + i ) chars [ i ] = reader . ReadChar ( ) ;
2013-12-17 08:19:40 +00:00
return new string ( chars ) ;
}
#endregion
}
}