diff --git a/LibreMetaverse.GUI/LibreMetaverse.GUI.csproj b/LibreMetaverse.GUI/LibreMetaverse.GUI.csproj
index cd9cde1c..9139d362 100644
--- a/LibreMetaverse.GUI/LibreMetaverse.GUI.csproj
+++ b/LibreMetaverse.GUI/LibreMetaverse.GUI.csproj
@@ -15,6 +15,7 @@
Library
LibreMetaverse.GUI
true
+ AnyCPU;x64;x86
True
@@ -35,6 +36,44 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -53,6 +92,42 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.GUI.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.GUI.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.GUI/MiniMap.cs b/LibreMetaverse.GUI/MiniMap.cs
index 3d36924f..06780de6 100644
--- a/LibreMetaverse.GUI/MiniMap.cs
+++ b/LibreMetaverse.GUI/MiniMap.cs
@@ -30,6 +30,7 @@ using System.Drawing;
using System.Windows.Forms;
using OpenMetaverse.Imaging;
using OpenMetaverse.Assets;
+using LibreMetaverse.Imaging;
namespace OpenMetaverse.GUI
{
@@ -43,9 +44,6 @@ namespace OpenMetaverse.GUI
private UUID _MapImageID;
private GridClient _Client;
private Image _MapLayer;
- //warning CS0414: The private field `OpenMetaverse.GUI.MiniMap._MousePosition' is assigned but its value is never used
- //private Point _MousePosition;
- ToolTip _ToolTip;
///
/// Gets or sets the GridClient associated with this control
@@ -71,13 +69,6 @@ namespace OpenMetaverse.GUI
public MiniMap(GridClient client) : this ()
{
InitializeClient(client);
-
- _ToolTip = new ToolTip();
- _ToolTip.Active = true;
- _ToolTip.AutomaticDelay = 1;
-
- this.MouseHover += new System.EventHandler(MiniMap_MouseHover);
- this.MouseMove += new MouseEventHandler(MiniMap_MouseMove);
}
/// Sets the map layer to the specified bitmap image
@@ -187,23 +178,14 @@ namespace OpenMetaverse.GUI
}
}
- void MiniMap_MouseHover(object sender, System.EventArgs e)
- {
- _ToolTip.SetToolTip(this, "test");
- _ToolTip.Show("test", this);
- //TODO: tooltip popup with closest avatar's name, if within range
- }
-
- void MiniMap_MouseMove(object sender, MouseEventArgs e)
- {
- _ToolTip.Hide(this);
- //warning CS0414: The private field `OpenMetaverse.GUI.MiniMap._MousePosition' is assigned but its value is never used
- //_MousePosition = e.Location;
- }
-
void Network_OnCurrentSimChanged(object sender, SimChangedEventArgs e)
{
- if (_Client.Network.Connected) return;
+ FetchMapLayer();
+ }
+
+ private void FetchMapLayer()
+ {
+ if (!_Client.Network.Connected) { return; }
GridRegion region;
if (Client.Grid.GetGridRegion(Client.Network.CurrentSim.Name, GridLayerType.Objects, out region))
@@ -211,16 +193,21 @@ namespace OpenMetaverse.GUI
SetMapLayer(null);
_MapImageID = region.MapImageID;
- ManagedImage nullImage;
- Client.Assets.RequestImage(_MapImageID, ImageType.Baked,
- delegate(TextureRequestState state, AssetTexture asset)
+ Client.Assets.RequestImage(_MapImageID, ImageType.Baked,
+ delegate (TextureRequestState state, AssetTexture asset)
+ {
+ if (state == TextureRequestState.Finished)
{
- if(state == TextureRequestState.Finished)
- OpenJPEG.DecodeToImage(asset.AssetData, out nullImage, out _MapLayer);
- });
+ using (J2KReader reader = new J2KReader(asset.AssetData))
+ {
+ if (!reader.ReadHeader()) { return; }
+ _MapLayer = reader.DecodeToBitmap();
+ }
+ }
+ });
}
- }
+ }
}
}
diff --git a/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj b/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj
index e2449a96..ca2fe533 100644
--- a/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj
+++ b/LibreMetaverse.Rendering.Meshmerizer/LibreMetaverse.Rendering.Meshmerizer.csproj
@@ -14,6 +14,7 @@
Library
LibreMetaverse.Rendering.Meshmerizer
true
+ AnyCPU;x64;x86
True
@@ -32,6 +33,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -49,6 +84,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.Rendering.Simple/LibreMetaverse.Rendering.Simple.csproj b/LibreMetaverse.Rendering.Simple/LibreMetaverse.Rendering.Simple.csproj
index 3a537735..fb3f7d9a 100644
--- a/LibreMetaverse.Rendering.Simple/LibreMetaverse.Rendering.Simple.csproj
+++ b/LibreMetaverse.Rendering.Simple/LibreMetaverse.Rendering.Simple.csproj
@@ -14,6 +14,7 @@
Library
LibreMetaverse.Rendering.Simple
true
+ AnyCPU;x64;x86
True
@@ -32,6 +33,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -49,6 +84,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj b/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj
index 8442863e..d3ccdda6 100644
--- a/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj
+++ b/LibreMetaverse.StructuredData/LibreMetaverse.StructuredData.csproj
@@ -14,6 +14,7 @@
Library
LibreMetaverse.StructuredData
true
+ AnyCPU;x64;x86
True
@@ -34,6 +35,44 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -52,6 +91,42 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.StructuredData.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.StructuredData.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.Tests/LibreMetaverse.Tests.csproj b/LibreMetaverse.Tests/LibreMetaverse.Tests.csproj
index 0f532b19..1db47c37 100644
--- a/LibreMetaverse.Tests/LibreMetaverse.Tests.csproj
+++ b/LibreMetaverse.Tests/LibreMetaverse.Tests.csproj
@@ -15,6 +15,7 @@
LibreMetaverse.Tests
true
false
+ AnyCPU;x64;x86
True
@@ -35,6 +36,44 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -54,6 +93,44 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+
+
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+
+
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.Utilities/LibreMetaverse.Utilities.csproj b/LibreMetaverse.Utilities/LibreMetaverse.Utilities.csproj
index 50a39267..6286b383 100644
--- a/LibreMetaverse.Utilities/LibreMetaverse.Utilities.csproj
+++ b/LibreMetaverse.Utilities/LibreMetaverse.Utilities.csproj
@@ -14,6 +14,7 @@
Library
LibreMetaverse.Utilities
true
+ AnyCPU;x64;x86
True
@@ -34,6 +35,44 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+
+
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -52,6 +91,42 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.Utilities.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.Utilities.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/LibreMetaverse.sln b/LibreMetaverse.sln
index 28081ab0..20086a2b 100644
--- a/LibreMetaverse.sln
+++ b/LibreMetaverse.sln
@@ -35,109 +35,307 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VoiceTest", "Programs\Voice
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibreMetaverse.PrimMesher", "PrimMesher\LibreMetaverse.PrimMesher.csproj", "{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mapgenerator", "Programs\mapgenerator\mapgenerator.csproj", "{2867B4B3-0000-0000-0000-000000000000}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "mapgenerator", "Programs\mapgenerator\mapgenerator.csproj", "{2867B4B3-0000-0000-0000-000000000000}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
ReleaseNoGui|Any CPU = ReleaseNoGui|Any CPU
+ ReleaseNoGui|x64 = ReleaseNoGui|x64
+ ReleaseNoGui|x86 = ReleaseNoGui|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{95F42663-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95F42663-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95F42663-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {95F42663-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {95F42663-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {95F42663-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{95F42663-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95F42663-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {95F42663-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {95F42663-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {95F42663-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {95F42663-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{95F42663-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
+ {95F42663-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {95F42663-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {95F42663-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {95F42663-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{79B51DAA-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{79B51DAA-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {79B51DAA-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {79B51DAA-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {79B51DAA-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {79B51DAA-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{79B51DAA-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{79B51DAA-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {79B51DAA-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {79B51DAA-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {79B51DAA-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {79B51DAA-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {79B51DAA-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{89049BBC-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89049BBC-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {89049BBC-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {89049BBC-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {89049BBC-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {89049BBC-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{89049BBC-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89049BBC-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {89049BBC-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {89049BBC-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {89049BBC-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {89049BBC-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {89049BBC-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{27C70F3A-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{27C70F3A-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {27C70F3A-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {27C70F3A-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {27C70F3A-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {27C70F3A-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{27C70F3A-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{27C70F3A-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {27C70F3A-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {27C70F3A-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {27C70F3A-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {27C70F3A-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {27C70F3A-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{09C292AF-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{09C292AF-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {09C292AF-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {09C292AF-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {09C292AF-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {09C292AF-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{09C292AF-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{09C292AF-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {09C292AF-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {09C292AF-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {09C292AF-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {09C292AF-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{09C292AF-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
+ {09C292AF-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {09C292AF-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {09C292AF-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {09C292AF-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{95479B1D-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95479B1D-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {95479B1D-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {95479B1D-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {95479B1D-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {95479B1D-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{95479B1D-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95479B1D-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {95479B1D-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {95479B1D-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {95479B1D-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {95479B1D-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {95479B1D-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{29E206AC-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29E206AC-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {29E206AC-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {29E206AC-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {29E206AC-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {29E206AC-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{29E206AC-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E206AC-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {29E206AC-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {29E206AC-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {29E206AC-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {29E206AC-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {29E206AC-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{89D7A3E5-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89D7A3E5-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {89D7A3E5-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {89D7A3E5-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{89D7A3E5-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89D7A3E5-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {89D7A3E5-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {89D7A3E5-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {89D7A3E5-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{0CCC2C3D-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CCC2C3D-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0CCC2C3D-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {0CCC2C3D-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{0CCC2C3D-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CCC2C3D-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0CCC2C3D-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {0CCC2C3D-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {0CCC2C3D-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{1266CE08-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1266CE08-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1266CE08-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {1266CE08-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {1266CE08-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {1266CE08-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{1266CE08-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1266CE08-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1266CE08-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {1266CE08-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {1266CE08-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {1266CE08-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {1266CE08-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{B37B02AD-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B37B02AD-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B37B02AD-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {B37B02AD-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {B37B02AD-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {B37B02AD-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{B37B02AD-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B37B02AD-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B37B02AD-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {B37B02AD-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {B37B02AD-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {B37B02AD-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {B37B02AD-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{58443010-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58443010-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {58443010-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {58443010-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {58443010-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {58443010-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{58443010-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58443010-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {58443010-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {58443010-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {58443010-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {58443010-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{58443010-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{58443010-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {58443010-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {58443010-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {58443010-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {58443010-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{9F71FDB3-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F71FDB3-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9F71FDB3-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {9F71FDB3-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{9F71FDB3-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F71FDB3-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9F71FDB3-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {9F71FDB3-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {9F71FDB3-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{EE4EA934-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE4EA934-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EE4EA934-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {EE4EA934-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {EE4EA934-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {EE4EA934-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{EE4EA934-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE4EA934-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EE4EA934-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {EE4EA934-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {EE4EA934-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {EE4EA934-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {EE4EA934-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|x64.ActiveCfg = Debug|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|x64.Build.0 = Debug|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|x86.ActiveCfg = Debug|x86
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Debug|x86.Build.0 = Debug|x86
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|x64.ActiveCfg = Release|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|x64.Build.0 = Release|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|x86.ActiveCfg = Release|x86
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.Release|x86.Build.0 = Release|x86
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {2E2B643F-F18B-4791-BA4B-6E82D0E794B6}.ReleaseNoGui|x86.Build.0 = Release|x86
{2867B4B3-0000-0000-0000-000000000000}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2867B4B3-0000-0000-0000-000000000000}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2867B4B3-0000-0000-0000-000000000000}.Debug|x64.ActiveCfg = Debug|x64
+ {2867B4B3-0000-0000-0000-000000000000}.Debug|x64.Build.0 = Debug|x64
+ {2867B4B3-0000-0000-0000-000000000000}.Debug|x86.ActiveCfg = Debug|x86
+ {2867B4B3-0000-0000-0000-000000000000}.Debug|x86.Build.0 = Debug|x86
{2867B4B3-0000-0000-0000-000000000000}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2867B4B3-0000-0000-0000-000000000000}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2867B4B3-0000-0000-0000-000000000000}.Release|x64.ActiveCfg = Release|x64
+ {2867B4B3-0000-0000-0000-000000000000}.Release|x64.Build.0 = Release|x64
+ {2867B4B3-0000-0000-0000-000000000000}.Release|x86.ActiveCfg = Release|x86
+ {2867B4B3-0000-0000-0000-000000000000}.Release|x86.Build.0 = Release|x86
{2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.ActiveCfg = Release|Any CPU
{2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|Any CPU.Build.0 = Release|Any CPU
+ {2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|x64.ActiveCfg = Release|x64
+ {2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|x64.Build.0 = Release|x64
+ {2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|x86.ActiveCfg = Release|x86
+ {2867B4B3-0000-0000-0000-000000000000}.ReleaseNoGui|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs b/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs
index 60aea7b0..be3e1399 100644
--- a/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs
+++ b/LibreMetaverse/Assets/AssetTypes/AssetTexture.cs
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2006-2016, openmetaverse.co
+ * Copyright (c) 2021, Sjofn LLC.
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
@@ -25,7 +26,8 @@
*/
using System;
-using OpenMetaverse;
+using System.Runtime.InteropServices;
+using LibreMetaverse.Imaging;
using OpenMetaverse.Imaging;
namespace OpenMetaverse.Assets
@@ -41,9 +43,6 @@ namespace OpenMetaverse.Assets
/// A object containing image data
public ManagedImage Image;
- ///
- public OpenJPEG.J2KLayerInfo[] LayerInfo;
-
///
public int Components;
@@ -81,7 +80,10 @@ namespace OpenMetaverse.Assets
///
public override void Encode()
{
- AssetData = OpenJPEG.Encode(Image);
+ using (J2KWriter writer = new J2KWriter(Image.ExportBitmap()))
+ {
+ AssetData = writer.Encode();
+ }
}
///
@@ -91,36 +93,27 @@ namespace OpenMetaverse.Assets
/// True if the decoding was successful, otherwise false
public override bool Decode()
{
- if (AssetData != null && AssetData.Length > 0)
+ if (AssetData == null || AssetData.Length <= 0) { return false; }
+
+ this.Components = 0;
+
+ using (J2KReader reader = new J2KReader(AssetData))
{
- this.Components = 0;
-
- if (OpenJPEG.DecodeToImage(AssetData, out Image))
- {
- if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
- Components += 3;
- if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
- ++Components;
-
- return true;
- }
+ // *hack: decode from ManagedImage directly or better yet, get rid of ManagedImage entirely!
+ if (!reader.ReadHeader()) { return false; }
+ Image = new ManagedImage(reader.DecodeToBitmap());
}
- return false;
- }
+ if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ Components += 3;
+ if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ ++Components;
- ///
- /// Decodes the begin and end byte positions for each quality layer in
- /// the image
- ///
- ///
- public bool DecodeLayerBoundaries()
- {
- return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components);
+ return true;
}
}
}
diff --git a/LibreMetaverse/Imaging/BakeLayer.cs b/LibreMetaverse/Imaging/BakeLayer.cs
index a5598670..d91fe235 100644
--- a/LibreMetaverse/Imaging/BakeLayer.cs
+++ b/LibreMetaverse/Imaging/BakeLayer.cs
@@ -1,165 +1,165 @@
-/*
- * Copyright (c) 2007-2008, openmetaverse.co
- * All rights reserved.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the openmetaverse.co nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Reflection;
-using System.Collections.Generic;
-using System.IO;
-using System.Drawing;
-using OpenMetaverse.Assets;
-
-namespace OpenMetaverse.Imaging
-{
- ///
- /// A set of textures that are layered on texture of each other and "baked"
- /// in to a single texture, for avatar appearances
- ///
- public class Baker
- {
- #region Properties
- /// Final baked texture
- public AssetTexture BakedTexture => bakedTexture;
-
- /// Component layers
- public List Textures => textures;
-
- /// Width of the final baked image and scratchpad
- public int BakeWidth => bakeWidth;
-
- /// Height of the final baked image and scratchpad
- public int BakeHeight => bakeHeight;
-
- /// Bake type
- public BakeType BakeType => bakeType;
-
- /// Is this one of the 3 skin bakes
- private bool IsSkin => bakeType == BakeType.Head || bakeType == BakeType.LowerBody || bakeType == BakeType.UpperBody;
-
- #endregion
-
- #region Private fields
- /// Final baked texture
- private AssetTexture bakedTexture;
- /// Component layers
- private List textures = new List();
- /// Width of the final baked image and scratchpad
- private int bakeWidth;
- /// Height of the final baked image and scratchpad
- private int bakeHeight;
- /// Bake type
- private BakeType bakeType;
- #endregion
-
- #region Constructor
- ///
- /// Default constructor
- ///
- /// Bake type
- public Baker(BakeType bakeType)
- {
- this.bakeType = bakeType;
-
- if (bakeType == BakeType.Eyes)
- {
- bakeWidth = 128;
- bakeHeight = 128;
- }
- else
- {
- bakeWidth = 1024;
- bakeHeight = 1024;
- }
- }
- #endregion
-
- #region Public methods
- ///
- /// Adds layer for baking
- ///
- /// TexturaData struct that contains texture and its params
- public void AddTexture(AppearanceManager.TextureData tdata)
- {
- lock (textures)
- {
- textures.Add(tdata);
- }
- }
-
- public void Bake()
- {
- bakedTexture = new AssetTexture(new ManagedImage(bakeWidth, bakeHeight,
- ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump));
-
- // These are for head baking, they get special treatment
- AppearanceManager.TextureData skinTexture = new AppearanceManager.TextureData();
- List tattooTextures = new List();
- List alphaWearableTextures = new List();
-
- // Base color for eye bake is white, color of layer0 for others
- if (bakeType == BakeType.Eyes)
- {
- InitBakedLayerColor(Color4.White);
- }
- else if (textures.Count > 0)
- {
- InitBakedLayerColor(textures[0].Color);
- }
-
- // Sort out the special layers we need for head baking and alpha
- foreach (AppearanceManager.TextureData tex in textures)
- {
- if (tex.Texture == null)
- continue;
-
- switch (tex.TextureIndex)
- {
- case AvatarTextureIndex.HeadBodypaint:
- case AvatarTextureIndex.UpperBodypaint:
- case AvatarTextureIndex.LowerBodypaint:
- skinTexture = tex;
- break;
- case AvatarTextureIndex.HeadTattoo:
- case AvatarTextureIndex.UpperTattoo:
- case AvatarTextureIndex.LowerTattoo:
- tattooTextures.Add(tex);
- break;
- }
-
- if (tex.TextureIndex >= AvatarTextureIndex.LowerAlpha &&
- tex.TextureIndex <= AvatarTextureIndex.HairAlpha)
- {
- if (tex.Texture.Image.Alpha != null)
- {
- alphaWearableTextures.Add(tex.Texture.Image.Clone());
- }
- }
- }
-
- if (bakeType == BakeType.Head)
- {
+/*
+ * Copyright (c) 2007-2008, openmetaverse.co
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Reflection;
+using System.Collections.Generic;
+using System.IO;
+using System.Drawing;
+using OpenMetaverse.Assets;
+
+namespace OpenMetaverse.Imaging
+{
+ ///
+ /// A set of textures that are layered on texture of each other and "baked"
+ /// in to a single texture, for avatar appearances
+ ///
+ public class Baker
+ {
+ #region Properties
+ /// Final baked texture
+ public AssetTexture BakedTexture => bakedTexture;
+
+ /// Component layers
+ public List Textures => textures;
+
+ /// Width of the final baked image and scratchpad
+ public int BakeWidth => bakeWidth;
+
+ /// Height of the final baked image and scratchpad
+ public int BakeHeight => bakeHeight;
+
+ /// Bake type
+ public BakeType BakeType => bakeType;
+
+ /// Is this one of the 3 skin bakes
+ private bool IsSkin => bakeType == BakeType.Head || bakeType == BakeType.LowerBody || bakeType == BakeType.UpperBody;
+
+ #endregion
+
+ #region Private fields
+ /// Final baked texture
+ private AssetTexture bakedTexture;
+ /// Component layers
+ private List textures = new List();
+ /// Width of the final baked image and scratchpad
+ private int bakeWidth;
+ /// Height of the final baked image and scratchpad
+ private int bakeHeight;
+ /// Bake type
+ private BakeType bakeType;
+ #endregion
+
+ #region Constructor
+ ///
+ /// Default constructor
+ ///
+ /// Bake type
+ public Baker(BakeType bakeType)
+ {
+ this.bakeType = bakeType;
+
+ if (bakeType == BakeType.Eyes)
+ {
+ bakeWidth = 128;
+ bakeHeight = 128;
+ }
+ else
+ {
+ bakeWidth = 1024;
+ bakeHeight = 1024;
+ }
+ }
+ #endregion
+
+ #region Public methods
+ ///
+ /// Adds layer for baking
+ ///
+ /// TexturaData struct that contains texture and its params
+ public void AddTexture(AppearanceManager.TextureData tdata)
+ {
+ lock (textures)
+ {
+ textures.Add(tdata);
+ }
+ }
+
+ public void Bake()
+ {
+ bakedTexture = new AssetTexture(new ManagedImage(bakeWidth, bakeHeight,
+ ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump));
+
+ // These are for head baking, they get special treatment
+ AppearanceManager.TextureData skinTexture = new AppearanceManager.TextureData();
+ List tattooTextures = new List();
+ List alphaWearableTextures = new List();
+
+ // Base color for eye bake is white, color of layer0 for others
+ if (bakeType == BakeType.Eyes)
+ {
+ InitBakedLayerColor(Color4.White);
+ }
+ else if (textures.Count > 0)
+ {
+ InitBakedLayerColor(textures[0].Color);
+ }
+
+ // Sort out the special layers we need for head baking and alpha
+ foreach (AppearanceManager.TextureData tex in textures)
+ {
+ if (tex.Texture == null)
+ continue;
+
+ switch (tex.TextureIndex)
+ {
+ case AvatarTextureIndex.HeadBodypaint:
+ case AvatarTextureIndex.UpperBodypaint:
+ case AvatarTextureIndex.LowerBodypaint:
+ skinTexture = tex;
+ break;
+ case AvatarTextureIndex.HeadTattoo:
+ case AvatarTextureIndex.UpperTattoo:
+ case AvatarTextureIndex.LowerTattoo:
+ tattooTextures.Add(tex);
+ break;
+ }
+
+ if (tex.TextureIndex >= AvatarTextureIndex.LowerAlpha &&
+ tex.TextureIndex <= AvatarTextureIndex.HairAlpha)
+ {
+ if (tex.Texture.Image.Alpha != null)
+ {
+ alphaWearableTextures.Add(tex.Texture.Image.Clone());
+ }
+ }
+ }
+
+ if (bakeType == BakeType.Head)
+ {
if (DrawLayer(LoadResourceLayer("head_color.tga"), false) == true)
{
AddAlpha(bakedTexture.Image, LoadResourceLayer("head_alpha.tga"));
@@ -169,322 +169,322 @@ namespace OpenMetaverse.Imaging
else
{
Logger.Log("[Bake]: Unable to draw layer from texture file", Helpers.LogLevel.Debug);
- }
- }
-
- if (skinTexture.Texture == null)
- {
- if (bakeType == BakeType.UpperBody)
- {
- DrawLayer(LoadResourceLayer("upperbody_color.tga"), false);
- }
-
- if (bakeType == BakeType.LowerBody)
- {
- DrawLayer(LoadResourceLayer("lowerbody_color.tga"), false);
- }
- }
-
- // Layer each texture on top of one other, applying alpha masks as we go
- for (int i = 0; i < textures.Count; i++)
- {
- // Skip if we have no texture on this layer
- if (textures[i].Texture == null) continue;
-
- // Is this Alpha wearable and does it have an alpha channel?
- if (textures[i].TextureIndex >= AvatarTextureIndex.LowerAlpha &&
- textures[i].TextureIndex <= AvatarTextureIndex.HairAlpha)
- continue;
-
- // Don't draw skin and tattoo on head bake first
- // For head bake the skin and texture are drawn last, go figure
- if (bakeType == BakeType.Head &&
- (textures[i].TextureIndex == AvatarTextureIndex.HeadBodypaint ||
- textures[i].TextureIndex == AvatarTextureIndex.HeadTattoo))
- continue;
-
- ManagedImage texture = textures[i].Texture.Image.Clone();
- //File.WriteAllBytes(bakeType + "-texture-layer-" + textures[i].TextureIndex + "-" + i + ".tga", texture.ExportTGA());
-
- // Resize texture to the size of baked layer
- // FIXME: if texture is smaller than the layer, don't stretch it, tile it
- if (texture.Width != bakeWidth || texture.Height != bakeHeight)
- {
- try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
- catch (Exception) { continue; }
- }
-
- // Special case for hair layer for the head bake
- // If we don't have skin texture, we discard hair alpha
- // and apply hair(i==2) pattern over the texture
- if (skinTexture.Texture == null && bakeType == BakeType.Head && textures[i].TextureIndex == AvatarTextureIndex.Hair)
- {
- if (texture.Alpha != null)
- {
- for (int j = 0; j < texture.Alpha.Length; j++) texture.Alpha[j] = (byte)255;
- }
- MultiplyLayerFromAlpha(texture, LoadResourceLayer("head_hair.tga"));
- }
-
- // Aply tint and alpha masks except for skin that has a texture
- // on layer 0 which always overrides other skin settings
- if (!(textures[i].TextureIndex == AvatarTextureIndex.HeadBodypaint ||
- textures[i].TextureIndex == AvatarTextureIndex.UpperBodypaint ||
- textures[i].TextureIndex == AvatarTextureIndex.LowerBodypaint))
- {
- ApplyTint(texture, textures[i].Color);
-
- // For hair bake, we skip all alpha masks
- // and use one from the texture, for both
- // alpha and morph layers
- if (bakeType == BakeType.Hair)
- {
- if (texture.Alpha != null)
- {
- bakedTexture.Image.Bump = texture.Alpha;
- }
- else
- {
- for (int j = 0; j < bakedTexture.Image.Bump.Length; j++) bakedTexture.Image.Bump[j] = byte.MaxValue;
- }
- }
- // Apply parametrized alpha masks
- else if (textures[i].AlphaMasks != null && textures[i].AlphaMasks.Count > 0)
- {
- // Combined mask for the layer, fully transparent to begin with
- ManagedImage combinedMask = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha);
-
- int addedMasks = 0;
-
- // First add mask in normal blend mode
- foreach (KeyValuePair kvp in textures[i].AlphaMasks)
- {
- if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue;
-
- if (kvp.Key.MultiplyBlend == false && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
- {
- ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
- //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
- addedMasks++;
- }
- }
-
- // If there were no mask in normal blend mode make aplha fully opaque
- if (addedMasks == 0) for (int l = 0; l < combinedMask.Alpha.Length; l++) combinedMask.Alpha[l] = 255;
-
- // Add masks in multiply blend mode
- foreach (KeyValuePair kvp in textures[i].AlphaMasks)
- {
- if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue;
-
- if (kvp.Key.MultiplyBlend && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
- {
- ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
- //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
- addedMasks++;
- }
- }
-
- if (addedMasks > 0)
- {
- // Apply combined alpha mask to the cloned texture
- AddAlpha(texture, combinedMask);
- }
-
- // Is this layer used for morph mask? If it is, use its
- // alpha as the morth for the whole bake
- if (Textures[i].TextureIndex == AppearanceManager.MorphLayerForBakeType(bakeType))
- {
- bakedTexture.Image.Bump = texture.Alpha;
- }
-
- //File.WriteAllBytes(bakeType + "-masked-texture-" + i + ".tga", texture.ExportTGA());
- }
- }
-
- bool useAlpha = i == 0 && (BakeType == BakeType.Skirt || BakeType == BakeType.Hair);
- DrawLayer(texture, useAlpha);
- //File.WriteAllBytes(bakeType + "-layer-" + i + ".tga", texture.ExportTGA());
- }
-
- // For head and tattoo, we add skin last
- if (bakeType == BakeType.Head)
- {
- if (skinTexture.Texture != null)
- {
- ManagedImage texture = skinTexture.Texture.Image.Clone();
- if (texture.Width != bakeWidth || texture.Height != bakeHeight)
- {
- try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
- catch (Exception) { }
- }
- DrawLayer(texture, false);
- }
-
- foreach (AppearanceManager.TextureData tex in tattooTextures)
- {
- // Add head tattoo here (if available, order-dependant)
- if (tex.Texture != null)
- {
- ManagedImage texture = tex.Texture.Image.Clone();
- if (texture.Width != bakeWidth || texture.Height != bakeHeight)
- {
- try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
- catch (Exception) { }
- }
- DrawLayer(texture, false);
- }
- }
- }
-
- // Apply any alpha wearable textures to make parts of the avatar disappear
- Logger.Log("[XBakes]: Number of alpha wearable textures: " + alphaWearableTextures.Count.ToString(), Helpers.LogLevel.Debug);
- foreach (ManagedImage img in alphaWearableTextures)
- AddAlpha(bakedTexture.Image, img);
-
- // We are done, encode asset for finalized bake
- bakedTexture.Encode();
- //File.WriteAllBytes(bakeType + ".tga", bakedTexture.Image.ExportTGA());
- }
-
- private static object ResourceSync = new object();
-
- public static ManagedImage LoadResourceLayer(string fileName)
- {
- try
- {
- Bitmap bitmap = null;
- lock (ResourceSync)
- {
- using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR))
+ }
+ }
+
+ if (skinTexture.Texture == null)
+ {
+ if (bakeType == BakeType.UpperBody)
+ {
+ DrawLayer(LoadResourceLayer("upperbody_color.tga"), false);
+ }
+
+ if (bakeType == BakeType.LowerBody)
+ {
+ DrawLayer(LoadResourceLayer("lowerbody_color.tga"), false);
+ }
+ }
+
+ // Layer each texture on top of one other, applying alpha masks as we go
+ for (int i = 0; i < textures.Count; i++)
+ {
+ // Skip if we have no texture on this layer
+ if (textures[i].Texture == null) continue;
+
+ // Is this Alpha wearable and does it have an alpha channel?
+ if (textures[i].TextureIndex >= AvatarTextureIndex.LowerAlpha &&
+ textures[i].TextureIndex <= AvatarTextureIndex.HairAlpha)
+ continue;
+
+ // Don't draw skin and tattoo on head bake first
+ // For head bake the skin and texture are drawn last, go figure
+ if (bakeType == BakeType.Head &&
+ (textures[i].TextureIndex == AvatarTextureIndex.HeadBodypaint ||
+ textures[i].TextureIndex == AvatarTextureIndex.HeadTattoo))
+ continue;
+
+ ManagedImage texture = textures[i].Texture.Image.Clone();
+ //File.WriteAllBytes(bakeType + "-texture-layer-" + textures[i].TextureIndex + "-" + i + ".tga", texture.ExportTGA());
+
+ // Resize texture to the size of baked layer
+ // FIXME: if texture is smaller than the layer, don't stretch it, tile it
+ if (texture.Width != bakeWidth || texture.Height != bakeHeight)
+ {
+ try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
+ catch (Exception) { continue; }
+ }
+
+ // Special case for hair layer for the head bake
+ // If we don't have skin texture, we discard hair alpha
+ // and apply hair(i==2) pattern over the texture
+ if (skinTexture.Texture == null && bakeType == BakeType.Head && textures[i].TextureIndex == AvatarTextureIndex.Hair)
+ {
+ if (texture.Alpha != null)
{
- if (stream != null)
+ for (int j = 0; j < texture.Alpha.Length; j++) texture.Alpha[j] = (byte)255;
+ }
+ MultiplyLayerFromAlpha(texture, LoadResourceLayer("head_hair.tga"));
+ }
+
+ // Aply tint and alpha masks except for skin that has a texture
+ // on layer 0 which always overrides other skin settings
+ if (!(textures[i].TextureIndex == AvatarTextureIndex.HeadBodypaint ||
+ textures[i].TextureIndex == AvatarTextureIndex.UpperBodypaint ||
+ textures[i].TextureIndex == AvatarTextureIndex.LowerBodypaint))
+ {
+ ApplyTint(texture, textures[i].Color);
+
+ // For hair bake, we skip all alpha masks
+ // and use one from the texture, for both
+ // alpha and morph layers
+ if (bakeType == BakeType.Hair)
+ {
+ if (texture.Alpha != null)
+ {
+ bakedTexture.Image.Bump = texture.Alpha;
+ }
+ else
+ {
+ for (int j = 0; j < bakedTexture.Image.Bump.Length; j++) bakedTexture.Image.Bump[j] = byte.MaxValue;
+ }
+ }
+ // Apply parametrized alpha masks
+ else if (textures[i].AlphaMasks != null && textures[i].AlphaMasks.Count > 0)
+ {
+ // Combined mask for the layer, fully transparent to begin with
+ ManagedImage combinedMask = new ManagedImage(bakeWidth, bakeHeight, ManagedImage.ImageChannels.Alpha);
+
+ int addedMasks = 0;
+
+ // First add mask in normal blend mode
+ foreach (KeyValuePair kvp in textures[i].AlphaMasks)
+ {
+ if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue;
+
+ if (kvp.Key.MultiplyBlend == false && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
+ {
+ ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
+ //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
+ addedMasks++;
+ }
+ }
+
+ // If there were no mask in normal blend mode make aplha fully opaque
+ if (addedMasks == 0) for (int l = 0; l < combinedMask.Alpha.Length; l++) combinedMask.Alpha[l] = 255;
+
+ // Add masks in multiply blend mode
+ foreach (KeyValuePair kvp in textures[i].AlphaMasks)
+ {
+ if (!MaskBelongsToBake(kvp.Key.TGAFile)) continue;
+
+ if (kvp.Key.MultiplyBlend && (kvp.Value > 0f || !kvp.Key.SkipIfZero))
+ {
+ ApplyAlpha(combinedMask, kvp.Key, kvp.Value);
+ //File.WriteAllBytes(bakeType + "-layer-" + i + "-mask-" + addedMasks + ".tga", combinedMask.ExportTGA());
+ addedMasks++;
+ }
+ }
+
+ if (addedMasks > 0)
+ {
+ // Apply combined alpha mask to the cloned texture
+ AddAlpha(texture, combinedMask);
+ }
+
+ // Is this layer used for morph mask? If it is, use its
+ // alpha as the morth for the whole bake
+ if (Textures[i].TextureIndex == AppearanceManager.MorphLayerForBakeType(bakeType))
+ {
+ bakedTexture.Image.Bump = texture.Alpha;
+ }
+
+ //File.WriteAllBytes(bakeType + "-masked-texture-" + i + ".tga", texture.ExportTGA());
+ }
+ }
+
+ bool useAlpha = i == 0 && (BakeType == BakeType.Skirt || BakeType == BakeType.Hair);
+ DrawLayer(texture, useAlpha);
+ //File.WriteAllBytes(bakeType + "-layer-" + i + ".tga", texture.ExportTGA());
+ }
+
+ // For head and tattoo, we add skin last
+ if (bakeType == BakeType.Head)
+ {
+ if (skinTexture.Texture != null)
+ {
+ ManagedImage texture = skinTexture.Texture.Image.Clone();
+ if (texture.Width != bakeWidth || texture.Height != bakeHeight)
+ {
+ try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
+ catch (Exception) { }
+ }
+ DrawLayer(texture, false);
+ }
+
+ foreach (AppearanceManager.TextureData tex in tattooTextures)
+ {
+ // Add head tattoo here (if available, order-dependant)
+ if (tex.Texture != null)
+ {
+ ManagedImage texture = tex.Texture.Image.Clone();
+ if (texture.Width != bakeWidth || texture.Height != bakeHeight)
+ {
+ try { texture.ResizeNearestNeighbor(bakeWidth, bakeHeight); }
+ catch (Exception) { }
+ }
+ DrawLayer(texture, false);
+ }
+ }
+ }
+
+ // Apply any alpha wearable textures to make parts of the avatar disappear
+ Logger.Log("[XBakes]: Number of alpha wearable textures: " + alphaWearableTextures.Count.ToString(), Helpers.LogLevel.Debug);
+ foreach (ManagedImage img in alphaWearableTextures)
+ AddAlpha(bakedTexture.Image, img);
+
+ // We are done, encode asset for finalized bake
+ bakedTexture.Encode();
+ //File.WriteAllBytes(bakeType + ".tga", bakedTexture.Image.ExportTGA());
+ }
+
+ private static object ResourceSync = new object();
+
+ public static ManagedImage LoadResourceLayer(string fileName)
+ {
+ try
+ {
+ Bitmap bitmap = null;
+ lock (ResourceSync)
+ {
+ using (Stream stream = Helpers.GetResourceStream(fileName, Settings.RESOURCE_DIR))
+ {
+ if (stream != null)
{
bitmap = LoadTGAClass.LoadTGA(stream);
- }
- }
- }
- if (bitmap == null)
- {
- Logger.Log(String.Format("Failed loading resource file: {0}", fileName), Helpers.LogLevel.Error);
- return null;
- }
- else
- {
- return new ManagedImage(bitmap);
- }
- }
- catch (Exception e)
- {
- Logger.Log(String.Format("Failed loading resource file: {0} ({1})", fileName, e.Message),
- Helpers.LogLevel.Error, e);
- return null;
- }
- }
-
- ///
- /// Converts avatar texture index (face) to Bake type
- ///
- /// Face number (AvatarTextureIndex)
- /// BakeType, layer to which this texture belongs to
- public static BakeType BakeTypeFor(AvatarTextureIndex index)
- {
- switch (index)
- {
- case AvatarTextureIndex.HeadBodypaint:
- return BakeType.Head;
-
- case AvatarTextureIndex.UpperBodypaint:
- case AvatarTextureIndex.UpperGloves:
- case AvatarTextureIndex.UpperUndershirt:
- case AvatarTextureIndex.UpperShirt:
- case AvatarTextureIndex.UpperJacket:
- return BakeType.UpperBody;
-
- case AvatarTextureIndex.LowerBodypaint:
- case AvatarTextureIndex.LowerUnderpants:
- case AvatarTextureIndex.LowerSocks:
- case AvatarTextureIndex.LowerShoes:
- case AvatarTextureIndex.LowerPants:
- case AvatarTextureIndex.LowerJacket:
- return BakeType.LowerBody;
-
- case AvatarTextureIndex.EyesIris:
- return BakeType.Eyes;
-
- case AvatarTextureIndex.Skirt:
- return BakeType.Skirt;
-
- case AvatarTextureIndex.Hair:
- return BakeType.Hair;
-
- default:
- return BakeType.Unknown;
- }
- }
- #endregion
-
- #region Private layer compositing methods
-
- private bool MaskBelongsToBake(string mask)
- {
+ }
+ }
+ }
+ if (bitmap == null)
+ {
+ Logger.Log(String.Format("Failed loading resource file: {0}", fileName), Helpers.LogLevel.Error);
+ return null;
+ }
+ else
+ {
+ return new ManagedImage(bitmap);
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.Log(String.Format("Failed loading resource file: {0} ({1})", fileName, e.Message),
+ Helpers.LogLevel.Error, e);
+ return null;
+ }
+ }
+
+ ///
+ /// Converts avatar texture index (face) to Bake type
+ ///
+ /// Face number (AvatarTextureIndex)
+ /// BakeType, layer to which this texture belongs to
+ public static BakeType BakeTypeFor(AvatarTextureIndex index)
+ {
+ switch (index)
+ {
+ case AvatarTextureIndex.HeadBodypaint:
+ return BakeType.Head;
+
+ case AvatarTextureIndex.UpperBodypaint:
+ case AvatarTextureIndex.UpperGloves:
+ case AvatarTextureIndex.UpperUndershirt:
+ case AvatarTextureIndex.UpperShirt:
+ case AvatarTextureIndex.UpperJacket:
+ return BakeType.UpperBody;
+
+ case AvatarTextureIndex.LowerBodypaint:
+ case AvatarTextureIndex.LowerUnderpants:
+ case AvatarTextureIndex.LowerSocks:
+ case AvatarTextureIndex.LowerShoes:
+ case AvatarTextureIndex.LowerPants:
+ case AvatarTextureIndex.LowerJacket:
+ return BakeType.LowerBody;
+
+ case AvatarTextureIndex.EyesIris:
+ return BakeType.Eyes;
+
+ case AvatarTextureIndex.Skirt:
+ return BakeType.Skirt;
+
+ case AvatarTextureIndex.Hair:
+ return BakeType.Hair;
+
+ default:
+ return BakeType.Unknown;
+ }
+ }
+ #endregion
+
+ #region Private layer compositing methods
+
+ private bool MaskBelongsToBake(string mask)
+ {
return (bakeType != BakeType.LowerBody || !mask.Contains("upper"))
&& (bakeType != BakeType.LowerBody || !mask.Contains("shirt"))
- && (bakeType != BakeType.UpperBody || !mask.Contains("lower"));
- }
-
- private bool DrawLayer(ManagedImage source, bool addSourceAlpha)
- {
- if (source == null) return false;
-
- bool sourceHasColor;
- bool sourceHasAlpha;
- bool sourceHasBump;
- int i = 0;
-
- sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 &&
- source.Red != null && source.Green != null && source.Blue != null);
- sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null);
- sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null);
-
- addSourceAlpha = (addSourceAlpha && sourceHasAlpha);
-
- byte alpha = Byte.MaxValue;
- byte alphaInv = (byte)(Byte.MaxValue - alpha);
-
- byte[] bakedRed = bakedTexture.Image.Red;
- byte[] bakedGreen = bakedTexture.Image.Green;
- byte[] bakedBlue = bakedTexture.Image.Blue;
- byte[] bakedAlpha = bakedTexture.Image.Alpha;
- byte[] bakedBump = bakedTexture.Image.Bump;
-
- byte[] sourceRed = source.Red;
- byte[] sourceGreen = source.Green;
- byte[] sourceBlue = source.Blue;
- byte[] sourceAlpha = sourceHasAlpha ? source.Alpha : null;
- byte[] sourceBump = sourceHasBump ? source.Bump : null;
-
- bool loadedAlpha = false;
- for (int y = 0; y < bakeHeight; y++)
- {
- for (int x = 0; x < bakeWidth; x++)
- {
- loadedAlpha = false;
- alpha = 0;
+ && (bakeType != BakeType.UpperBody || !mask.Contains("lower"));
+ }
+
+ private bool DrawLayer(ManagedImage source, bool addSourceAlpha)
+ {
+ if (source == null) return false;
+
+ bool sourceHasColor;
+ bool sourceHasAlpha;
+ bool sourceHasBump;
+ int i = 0;
+
+ sourceHasColor = ((source.Channels & ManagedImage.ImageChannels.Color) != 0 &&
+ source.Red != null && source.Green != null && source.Blue != null);
+ sourceHasAlpha = ((source.Channels & ManagedImage.ImageChannels.Alpha) != 0 && source.Alpha != null);
+ sourceHasBump = ((source.Channels & ManagedImage.ImageChannels.Bump) != 0 && source.Bump != null);
+
+ addSourceAlpha = (addSourceAlpha && sourceHasAlpha);
+
+ byte alpha = Byte.MaxValue;
+ byte alphaInv = (byte)(Byte.MaxValue - alpha);
+
+ byte[] bakedRed = bakedTexture.Image.Red;
+ byte[] bakedGreen = bakedTexture.Image.Green;
+ byte[] bakedBlue = bakedTexture.Image.Blue;
+ byte[] bakedAlpha = bakedTexture.Image.Alpha;
+ byte[] bakedBump = bakedTexture.Image.Bump;
+
+ byte[] sourceRed = source.Red;
+ byte[] sourceGreen = source.Green;
+ byte[] sourceBlue = source.Blue;
+ byte[] sourceAlpha = sourceHasAlpha ? source.Alpha : null;
+ byte[] sourceBump = sourceHasBump ? source.Bump : null;
+
+ bool loadedAlpha = false;
+ for (int y = 0; y < bakeHeight; y++)
+ {
+ for (int x = 0; x < bakeWidth; x++)
+ {
+ loadedAlpha = false;
+ alpha = 0;
alphaInv = 0;
- if (sourceHasAlpha)
- {
+ if (sourceHasAlpha)
+ {
if (sourceAlpha.Length > i)
{
loadedAlpha = true;
alpha = sourceAlpha[i];
alphaInv = (byte)(Byte.MaxValue - alpha);
- }
- }
-
- if (sourceHasColor)
- {
+ }
+ }
+
+ if (sourceHasColor)
+ {
if ((bakedRed.Length > i) && (bakedGreen.Length > i) && (bakedBlue.Length > i))
{
if ((sourceRed.Length > i) && (sourceGreen.Length > i) && (sourceBlue.Length > i))
@@ -502,209 +502,209 @@ namespace OpenMetaverse.Imaging
bakedBlue[i] = sourceBlue[i];
}
}
- }
- }
-
- if (addSourceAlpha)
- {
+ }
+ }
+
+ if (addSourceAlpha)
+ {
if ((sourceAlpha.Length > i) && (bakedAlpha.Length > i))
{
if (sourceAlpha[i] < bakedAlpha[i])
{
bakedAlpha[i] = sourceAlpha[i];
}
- }
- }
-
+ }
+ }
+
if (sourceHasBump)
{
if (sourceBump.Length > i)
{
bakedBump[i] = sourceBump[i];
}
- }
-
- ++i;
- }
- }
-
- return true;
- }
-
- ///
- /// Make sure images exist, resize source if needed to match the destination
- ///
- /// Destination image
- /// Source image
- /// Sanitization was succefull
- private bool SanitizeLayers(ManagedImage dest, ManagedImage src)
- {
- if (dest == null || src == null) return false;
-
- if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
- {
- dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha);
- }
-
- if (dest.Width != src.Width || dest.Height != src.Height)
- {
- try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
- catch (Exception) { return false; }
- }
-
- return true;
- }
-
-
- private void ApplyAlpha(ManagedImage dest, VisualAlphaParam param, float val)
- {
- ManagedImage src = LoadResourceLayer(param.TGAFile);
-
- if (dest == null || src?.Alpha == null) return;
-
- if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
- {
- dest.ConvertChannels(ManagedImage.ImageChannels.Alpha | dest.Channels);
- }
-
- if (dest.Width != src.Width || dest.Height != src.Height)
- {
- try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
- catch (Exception) { return; }
- }
-
- for (int i = 0; i < dest.Alpha.Length; i++)
- {
- byte alpha = src.Alpha[i] <= ((1 - val) * 255) ? (byte)0 : (byte)255;
-
- if (param.MultiplyBlend)
- {
- dest.Alpha[i] = (byte)((dest.Alpha[i] * alpha) >> 8);
- }
- else
- {
- if (alpha > dest.Alpha[i])
- {
- dest.Alpha[i] = alpha;
- }
- }
- }
- }
-
- private void AddAlpha(ManagedImage dest, ManagedImage src)
- {
- if (!SanitizeLayers(dest, src)) return;
-
- for (int i = 0; i < dest.Alpha.Length; i++)
- {
- if (src.Alpha[i] < dest.Alpha[i])
- {
- dest.Alpha[i] = src.Alpha[i];
- }
- }
- }
-
- private void MultiplyLayerFromAlpha(ManagedImage dest, ManagedImage src)
- {
- if (!SanitizeLayers(dest, src)) return;
-
- for (int i = 0; i < dest.Red.Length; i++)
- {
- dest.Red[i] = (byte)((dest.Red[i] * src.Alpha[i]) >> 8);
- dest.Green[i] = (byte)((dest.Green[i] * src.Alpha[i]) >> 8);
- dest.Blue[i] = (byte)((dest.Blue[i] * src.Alpha[i]) >> 8);
- }
- }
-
- private void ApplyTint(ManagedImage dest, Color4 src)
- {
- if (dest == null) return;
-
- for (int i = 0; i < dest.Red.Length; i++)
- {
- dest.Red[i] = (byte)((dest.Red[i] * Utils.FloatToByte(src.R, 0f, 1f)) >> 8);
- dest.Green[i] = (byte)((dest.Green[i] * Utils.FloatToByte(src.G, 0f, 1f)) >> 8);
- dest.Blue[i] = (byte)((dest.Blue[i] * Utils.FloatToByte(src.B, 0f, 1f)) >> 8);
- }
- }
-
- ///
- /// Fills a baked layer as a solid *appearing* color. The colors are
- /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from
- /// compressing it too far since it seems to cause upload failures if
- /// the image is a pure solid color
- ///
- /// Color of the base of this layer
- private void InitBakedLayerColor(Color4 color)
- {
- InitBakedLayerColor(color.R, color.G, color.B);
- }
-
- ///
- /// Fills a baked layer as a solid *appearing* color. The colors are
- /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from
- /// compressing it too far since it seems to cause upload failures if
- /// the image is a pure solid color
- ///
- /// Red value
- /// Green value
- /// Blue value
- private void InitBakedLayerColor(float r, float g, float b)
- {
- byte rByte = Utils.FloatToByte(r, 0f, 1f);
- byte gByte = Utils.FloatToByte(g, 0f, 1f);
- byte bByte = Utils.FloatToByte(b, 0f, 1f);
-
- var rAlt = rByte;
- var gAlt = gByte;
- var bAlt = bByte;
-
- if (rByte < byte.MaxValue)
- rAlt++;
- else rAlt--;
-
- if (gByte < byte.MaxValue)
- gAlt++;
- else gAlt--;
-
- if (bByte < byte.MaxValue)
- bAlt++;
- else bAlt--;
-
- int i = 0;
-
- byte[] red = bakedTexture.Image.Red;
- byte[] green = bakedTexture.Image.Green;
- byte[] blue = bakedTexture.Image.Blue;
- byte[] alpha = bakedTexture.Image.Alpha;
- byte[] bump = bakedTexture.Image.Bump;
-
- for (int y = 0; y < bakeHeight; y++)
- {
- for (int x = 0; x < bakeWidth; x++)
- {
- if (((x ^ y) & 0x10) == 0)
- {
- red[i] = rAlt;
- green[i] = gByte;
- blue[i] = bByte;
- alpha[i] = byte.MaxValue;
- bump[i] = 0;
- }
- else
- {
- red[i] = rByte;
- green[i] = gAlt;
- blue[i] = bAlt;
- alpha[i] = byte.MaxValue;
- bump[i] = 0;
- }
-
- ++i;
- }
- }
-
- }
- #endregion
- }
-}
+ }
+
+ ++i;
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Make sure images exist, resize source if needed to match the destination
+ ///
+ /// Destination image
+ /// Source image
+ /// Sanitization was succefull
+ private bool SanitizeLayers(ManagedImage dest, ManagedImage src)
+ {
+ if (dest == null || src == null) return false;
+
+ if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
+ {
+ dest.ConvertChannels(dest.Channels | ManagedImage.ImageChannels.Alpha);
+ }
+
+ if (dest.Width != src.Width || dest.Height != src.Height)
+ {
+ try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
+ catch (Exception) { return false; }
+ }
+
+ return true;
+ }
+
+
+ private void ApplyAlpha(ManagedImage dest, VisualAlphaParam param, float val)
+ {
+ ManagedImage src = LoadResourceLayer(param.TGAFile);
+
+ if (dest == null || src?.Alpha == null) return;
+
+ if ((dest.Channels & ManagedImage.ImageChannels.Alpha) == 0)
+ {
+ dest.ConvertChannels(ManagedImage.ImageChannels.Alpha | dest.Channels);
+ }
+
+ if (dest.Width != src.Width || dest.Height != src.Height)
+ {
+ try { src.ResizeNearestNeighbor(dest.Width, dest.Height); }
+ catch (Exception) { return; }
+ }
+
+ for (int i = 0; i < dest.Alpha.Length; i++)
+ {
+ byte alpha = src.Alpha[i] <= ((1 - val) * 255) ? (byte)0 : (byte)255;
+
+ if (param.MultiplyBlend)
+ {
+ dest.Alpha[i] = (byte)((dest.Alpha[i] * alpha) >> 8);
+ }
+ else
+ {
+ if (alpha > dest.Alpha[i])
+ {
+ dest.Alpha[i] = alpha;
+ }
+ }
+ }
+ }
+
+ private void AddAlpha(ManagedImage dest, ManagedImage src)
+ {
+ if (!SanitizeLayers(dest, src)) return;
+
+ for (int i = 0; i < dest.Alpha.Length; i++)
+ {
+ if (src.Alpha[i] < dest.Alpha[i])
+ {
+ dest.Alpha[i] = src.Alpha[i];
+ }
+ }
+ }
+
+ private void MultiplyLayerFromAlpha(ManagedImage dest, ManagedImage src)
+ {
+ if (!SanitizeLayers(dest, src)) return;
+
+ for (int i = 0; i < dest.Red.Length; i++)
+ {
+ dest.Red[i] = (byte)((dest.Red[i] * src.Alpha[i]) >> 8);
+ dest.Green[i] = (byte)((dest.Green[i] * src.Alpha[i]) >> 8);
+ dest.Blue[i] = (byte)((dest.Blue[i] * src.Alpha[i]) >> 8);
+ }
+ }
+
+ private void ApplyTint(ManagedImage dest, Color4 src)
+ {
+ if (dest == null) return;
+
+ for (int i = 0; i < dest.Red.Length; i++)
+ {
+ dest.Red[i] = (byte)((dest.Red[i] * Utils.FloatToByte(src.R, 0f, 1f)) >> 8);
+ dest.Green[i] = (byte)((dest.Green[i] * Utils.FloatToByte(src.G, 0f, 1f)) >> 8);
+ dest.Blue[i] = (byte)((dest.Blue[i] * Utils.FloatToByte(src.B, 0f, 1f)) >> 8);
+ }
+ }
+
+ ///
+ /// Fills a baked layer as a solid *appearing* color. The colors are
+ /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from
+ /// compressing it too far since it seems to cause upload failures if
+ /// the image is a pure solid color
+ ///
+ /// Color of the base of this layer
+ private void InitBakedLayerColor(Color4 color)
+ {
+ InitBakedLayerColor(color.R, color.G, color.B);
+ }
+
+ ///
+ /// Fills a baked layer as a solid *appearing* color. The colors are
+ /// subtly dithered on a 16x16 grid to prevent the JPEG2000 stage from
+ /// compressing it too far since it seems to cause upload failures if
+ /// the image is a pure solid color
+ ///
+ /// Red value
+ /// Green value
+ /// Blue value
+ private void InitBakedLayerColor(float r, float g, float b)
+ {
+ byte rByte = Utils.FloatToByte(r, 0f, 1f);
+ byte gByte = Utils.FloatToByte(g, 0f, 1f);
+ byte bByte = Utils.FloatToByte(b, 0f, 1f);
+
+ var rAlt = rByte;
+ var gAlt = gByte;
+ var bAlt = bByte;
+
+ if (rByte < byte.MaxValue)
+ rAlt++;
+ else rAlt--;
+
+ if (gByte < byte.MaxValue)
+ gAlt++;
+ else gAlt--;
+
+ if (bByte < byte.MaxValue)
+ bAlt++;
+ else bAlt--;
+
+ int i = 0;
+
+ byte[] red = bakedTexture.Image.Red;
+ byte[] green = bakedTexture.Image.Green;
+ byte[] blue = bakedTexture.Image.Blue;
+ byte[] alpha = bakedTexture.Image.Alpha;
+ byte[] bump = bakedTexture.Image.Bump;
+
+ for (int y = 0; y < bakeHeight; y++)
+ {
+ for (int x = 0; x < bakeWidth; x++)
+ {
+ if (((x ^ y) & 0x10) == 0)
+ {
+ red[i] = rAlt;
+ green[i] = gByte;
+ blue[i] = bByte;
+ alpha[i] = byte.MaxValue;
+ bump[i] = 0;
+ }
+ else
+ {
+ red[i] = rByte;
+ green[i] = gAlt;
+ blue[i] = bAlt;
+ alpha[i] = byte.MaxValue;
+ bump[i] = 0;
+ }
+
+ ++i;
+ }
+ }
+
+ }
+ #endregion
+ }
+}
diff --git a/LibreMetaverse/Imaging/ImageHelper.cs b/LibreMetaverse/Imaging/ImageHelper.cs
new file mode 100644
index 00000000..7bc036f5
--- /dev/null
+++ b/LibreMetaverse/Imaging/ImageHelper.cs
@@ -0,0 +1,251 @@
+/**
+ * Copyright (c) 2021, Sjofn LLC.
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using OpenJpegDotNet;
+
+namespace LibreMetaverse.Imaging
+{
+
+ internal static class ImageHelper
+ {
+
+ #region Methods
+
+ public static OpenJpegDotNet.Image FromRaw(byte[] raw, int width, int height, int stride, int channels, bool interleaved)
+ {
+ if (raw == null)
+ throw new ArgumentNullException(nameof(raw));
+
+ var byteAllocated = 1;
+ var colorSpace = ColorSpace.Srgb;
+ var precision = 24u / (uint)channels;
+ var gap = stride - width * channels;
+
+ using (var compressionParameters = new CompressionParameters())
+ {
+ OpenJpeg.SetDefaultEncoderParameters(compressionParameters);
+
+ var subsamplingDx = compressionParameters.SubsamplingDx;
+ var subsamplingDy = compressionParameters.SubsamplingDy;
+
+ var componentParametersArray = new ImageComponentParameters[channels];
+ for (var i = 0; i < channels; i++)
+ {
+ componentParametersArray[i] = new ImageComponentParameters
+ {
+ Precision = precision,
+ Bpp = precision,
+ Signed = false,
+ Dx = (uint)subsamplingDx,
+ Dy = (uint)subsamplingDy,
+ Width = (uint)width,
+ Height = (uint)height
+ };
+ }
+
+ var image = OpenJpeg.ImageCreate((uint)channels, componentParametersArray, colorSpace);
+ if (image == null)
+ return null;
+
+ image.X0 = (uint)compressionParameters.ImageOffsetX0;
+ image.Y0 = (uint)compressionParameters.ImageOffsetY0;
+ image.X1 = image.X0 == 0 ? (uint)(width - 1) * (uint)subsamplingDx + 1 : image.X0 + (uint)(width - 1) * (uint)subsamplingDx + 1;
+ image.Y1 = image.Y0 == 0 ? (uint)(height - 1) * (uint)subsamplingDy + 1 : image.Y0 + (uint)(height - 1) * (uint)subsamplingDy + 1;
+
+ unsafe
+ {
+ fixed (byte* pRaw = &raw[0])
+ {
+ // Bitmap data is interleave.
+ // Convert it to planer
+ if (byteAllocated == 1)
+ {
+ if (interleaved)
+ {
+ for (var i = 0; i < channels; i++)
+ {
+ var target = image.Components[i].Data;
+ var pTarget = (int*)target;
+ var source = pRaw + i;
+ for (var y = 0; y < height; y++)
+ {
+ for (var x = 0; x < width; x++)
+ {
+ *pTarget = *source;
+ pTarget++;
+ source += channels;
+ }
+
+ source += gap;
+ }
+ }
+ }
+ else
+ {
+ for (var i = 0; i < channels; i++)
+ {
+ var target = image.Components[i].Data;
+ var pTarget = (int*)target;
+ var source = pRaw + i * (stride * height);
+ for (var y = 0; y < height; y++)
+ {
+ for (var x = 0; x < width; x++)
+ {
+ *pTarget = *source;
+ pTarget++;
+ source++;
+ }
+
+ source += gap;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return image;
+ }
+ }
+
+ public static OpenJpegDotNet.Image FromBitmap(Bitmap bitmap)
+ {
+ if (bitmap == null)
+ throw new ArgumentNullException(nameof(bitmap));
+
+ var width = bitmap.Width;
+ var height = bitmap.Height;
+ var format = bitmap.PixelFormat;
+ int channels;
+ var byteAllocated = 0;
+ ColorSpace colorSpace;
+ switch (format)
+ {
+ case PixelFormat.Format24bppRgb:
+ channels = 3;
+ colorSpace = ColorSpace.Srgb;
+ byteAllocated = 1;
+ break;
+ case PixelFormat.Format32bppArgb:
+ channels = 4;
+ colorSpace = ColorSpace.Srgb;
+ byteAllocated = 1;
+ break;
+ case PixelFormat.Format8bppIndexed:
+ channels = 1;
+ colorSpace = ColorSpace.Srgb;
+ byteAllocated = 1;
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+ var precision = 24u / (uint)channels;
+
+ BitmapData bitmapData = null;
+
+ try
+ {
+ bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, format);
+ var stride = bitmapData.Stride;
+ var gap = stride - width * channels;
+ var scan0 = bitmapData.Scan0;
+
+ using (var compressionParameters = new CompressionParameters())
+ {
+ OpenJpeg.SetDefaultEncoderParameters(compressionParameters);
+
+ var subsamplingDx = compressionParameters.SubsamplingDx;
+ var subsamplingDy = compressionParameters.SubsamplingDy;
+
+ var componentParametersArray = new ImageComponentParameters[channels];
+ for (var i = 0; i < channels; i++)
+ {
+ componentParametersArray[i] = new ImageComponentParameters
+ {
+ Precision = precision,
+ Bpp = precision,
+ Signed = false,
+ Dx = (uint)subsamplingDx,
+ Dy = (uint)subsamplingDy,
+ Width = (uint)width,
+ Height = (uint)height
+ };
+ }
+
+ var image = OpenJpeg.ImageCreate((uint)channels, componentParametersArray, colorSpace);
+ if (image == null)
+ return null;
+
+ image.X0 = (uint)compressionParameters.ImageOffsetX0;
+ image.Y0 = (uint)compressionParameters.ImageOffsetY0;
+ image.X1 = image.X0 == 0 ? (uint)(width - 1) * (uint)subsamplingDx + 1 : image.X0 + (uint)(width - 1) * (uint)subsamplingDx + 1;
+ image.Y1 = image.Y0 == 0 ? (uint)(height - 1) * (uint)subsamplingDy + 1 : image.Y0 + (uint)(height - 1) * (uint)subsamplingDy + 1;
+
+ unsafe
+ {
+ // Bitmap data is interleave.
+ // Convert it to planer
+ if (byteAllocated == 1)
+ {
+ for (var i = 0; i < channels; i++)
+ {
+ var target = image.Components[i].Data;
+ var pTarget = (int*)target;
+ var source = (byte*)scan0;
+ source += i;
+ for (var y = 0; y < height; y++)
+ {
+ for (var x = 0; x < width; x++)
+ {
+ *pTarget = *source;
+ pTarget++;
+ source += channels;
+ }
+
+ source += gap;
+ }
+ }
+ }
+ }
+
+ return image;
+ }
+ }
+ finally
+ {
+ if (bitmapData != null)
+ bitmap.UnlockBits(bitmapData);
+ }
+ }
+
+ #endregion
+
+ }
+
+}
\ No newline at end of file
diff --git a/LibreMetaverse/Imaging/J2KBuffer.cs b/LibreMetaverse/Imaging/J2KBuffer.cs
new file mode 100644
index 00000000..3b8e18af
--- /dev/null
+++ b/LibreMetaverse/Imaging/J2KBuffer.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace LibreMetaverse.Imaging
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct J2KBuffer
+ {
+
+ public IntPtr Data;
+
+ public int Length;
+
+ public int Position;
+
+ }
+}
diff --git a/LibreMetaverse/Imaging/J2KReader.cs b/LibreMetaverse/Imaging/J2KReader.cs
new file mode 100644
index 00000000..ac3f27e4
--- /dev/null
+++ b/LibreMetaverse/Imaging/J2KReader.cs
@@ -0,0 +1,259 @@
+/**
+ * Copyright (c) 2021, Sjofn LLC.
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using OpenJpegDotNet;
+
+namespace LibreMetaverse.Imaging
+{
+ public sealed class J2KReader : IDisposable
+ {
+
+ #region Fields
+
+ private readonly J2KBuffer _Buffer;
+
+ private readonly IntPtr _UserData;
+
+ private readonly DelegateHandler _ReadCallback;
+
+ private readonly DelegateHandler _SeekCallback;
+
+ private readonly DelegateHandler _SkipCallback;
+
+ private Codec _Codec;
+
+ private DecompressionParameters _DecompressionParameters;
+
+ private OpenJpegDotNet.Image _Image;
+
+ private readonly Stream _Stream;
+
+ #endregion
+
+ #region Constructors
+
+ public J2KReader(byte[] data)
+ {
+ this._Buffer = new J2KBuffer
+ {
+ Data = Marshal.AllocHGlobal(data.Length),
+ Length = data.Length,
+ Position = 0
+ };
+
+ Marshal.Copy(data, 0, this._Buffer.Data, this._Buffer.Length);
+
+ var size = Marshal.SizeOf(this._Buffer);
+ this._UserData = Marshal.AllocHGlobal(size);
+ Marshal.StructureToPtr(this._Buffer, this._UserData, false);
+
+ this._ReadCallback = new DelegateHandler(Read);
+ this._SeekCallback = new DelegateHandler(Seek);
+ this._SkipCallback = new DelegateHandler(Skip);
+
+ this._Stream = OpenJpeg.StreamDefaultCreate(true);
+ OpenJpeg.StreamSetUserData(this._Stream, this._UserData);
+ OpenJpeg.StreamSetUserDataLength(this._Stream, this._Buffer.Length);
+ OpenJpeg.StreamSetReadFunction(this._Stream, this._ReadCallback);
+ OpenJpeg.StreamSetSeekFunction(this._Stream, this._SeekCallback);
+ OpenJpeg.StreamSetSkipFunction(this._Stream, this._SkipCallback);
+ }
+
+ #endregion
+
+ #region Properties
+
+ public int Height
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gets a value indicating whether this instance has been disposed.
+ ///
+ /// true if this instance has been disposed; otherwise, false.
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public int Width
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Methods
+
+ public bool ReadHeader()
+ {
+ this._Codec?.Dispose();
+ this._DecompressionParameters?.Dispose();
+ this._Image?.Dispose();
+
+ this._Codec = null;
+ this._DecompressionParameters = null;
+ this._Image = null;
+
+ this._Codec = OpenJpeg.CreateDecompress(CodecFormat.J2k);
+ this._DecompressionParameters = new DecompressionParameters();
+ OpenJpeg.SetDefaultDecoderParameters(this._DecompressionParameters);
+
+ if (!OpenJpeg.SetupDecoder(this._Codec, this._DecompressionParameters))
+ return false;
+
+ if (!OpenJpeg.ReadHeader(this._Stream, this._Codec, out var image))
+ return false;
+
+ this.Width = (int)(image.X1 - image.X0);
+ this.Height = (int)(image.Y1 - image.Y0);
+ this._Image = image;
+
+ return true;
+ }
+
+ public OpenJpegDotNet.Image Decode()
+ {
+ if (this._Image == null || this._Image.IsDisposed)
+ throw new InvalidOperationException();
+
+ if (!OpenJpeg.Decode(this._Codec, this._Stream, this._Image))
+ throw new InvalidOperationException();
+
+ return this._Image;
+ }
+
+ public Bitmap DecodeToBitmap()
+ {
+ if (this._Image == null || this._Image.IsDisposed)
+ throw new InvalidOperationException();
+
+ if (!OpenJpeg.Decode(this._Codec, this._Stream, this._Image))
+ throw new InvalidOperationException();
+
+ return this._Image.ToBitmap();
+ }
+
+ #region Event Handlers
+
+ private static ulong Read(IntPtr buffer, ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var bytesToRead = (int)Math.Min((ulong)(buf->Length - buf->Position), bytes);
+ if (bytesToRead > 0)
+ {
+ NativeMethods.cstd_memcpy(buffer, IntPtr.Add(buf->Data, buf->Position), bytesToRead);
+ buf->Position += bytesToRead;
+ return (ulong)bytesToRead;
+ }
+ else
+ {
+ return unchecked((ulong)-1);
+ }
+ }
+ }
+
+ private static int Seek(ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var position = Math.Min((ulong)buf->Length, bytes);
+ buf->Position = (int)position;
+ return 1;
+ }
+ }
+
+ private static long Skip(ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var bytesToSkip = (int)Math.Min((ulong)buf->Length, bytes);
+ if (bytesToSkip > 0)
+ {
+ buf->Position += bytesToSkip;
+ return bytesToSkip;
+ }
+ else
+ {
+ return unchecked(-1);
+ }
+ }
+ }
+
+ #endregion
+
+ #endregion
+
+ #region IDisposable Members
+
+ ///
+ /// Releases all resources used by this .
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ //GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases all resources used by this .
+ ///
+ /// Indicate value whether method was called.
+ private void Dispose(bool disposing)
+ {
+ if (this.IsDisposed)
+ {
+ return;
+ }
+
+ this.IsDisposed = true;
+
+ if (disposing)
+ {
+ this._Codec?.Dispose();
+ this._DecompressionParameters?.Dispose();
+ this._Stream.Dispose();
+
+ Marshal.FreeHGlobal(this._Buffer.Data);
+ Marshal.FreeHGlobal(this._UserData);
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/LibreMetaverse/Imaging/J2KWriter.cs b/LibreMetaverse/Imaging/J2KWriter.cs
new file mode 100644
index 00000000..8492de78
--- /dev/null
+++ b/LibreMetaverse/Imaging/J2KWriter.cs
@@ -0,0 +1,254 @@
+/**
+ * Copyright (c) 2021, Sjofn LLC.
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using OpenJpegDotNet;
+
+namespace LibreMetaverse.Imaging
+{
+ public sealed class J2KWriter : IDisposable
+ {
+
+ #region Fields
+
+ private readonly J2KBuffer _Buffer;
+
+ private readonly IntPtr _UserData;
+
+ private readonly DelegateHandler _WriteCallback;
+
+ private readonly DelegateHandler _SeekCallback;
+
+ private readonly DelegateHandler _SkipCallback;
+
+ private Codec _Codec;
+
+ private CompressionParameters _CompressionParameters;
+
+ private OpenJpegDotNet.Image _Image;
+
+ private readonly Stream _Stream;
+
+ #endregion
+
+ #region Constructors
+
+ public J2KWriter(Bitmap bitmap)
+ {
+ _Image = ImageHelper.FromBitmap(bitmap);
+ int datalen = (int)(_Image.X1 * _Image.Y1 * _Image.NumberOfComponents + 1024);
+
+ this._Buffer = new J2KBuffer
+ {
+ Data = Marshal.AllocHGlobal(datalen),
+ Length = datalen,
+ Position = 0
+ };
+
+ var size = Marshal.SizeOf(this._Buffer);
+ this._UserData = Marshal.AllocHGlobal(size);
+ Marshal.StructureToPtr(this._Buffer, this._UserData, false);
+
+ this._WriteCallback = new DelegateHandler(Write);
+ this._SeekCallback = new DelegateHandler(Seek);
+ this._SkipCallback = new DelegateHandler(Skip);
+
+ this._Stream = OpenJpeg.StreamCreate((ulong)_Buffer.Length, false);
+ OpenJpeg.StreamSetUserData(this._Stream, this._UserData);
+ OpenJpeg.StreamSetUserDataLength(this._Stream, this._Buffer.Length);
+ OpenJpeg.StreamSetWriteFunction(this._Stream, this._WriteCallback);
+ OpenJpeg.StreamSetSeekFunction(this._Stream, this._SeekCallback);
+ OpenJpeg.StreamSetSkipFunction(this._Stream, this._SkipCallback);
+
+ var compressionParameters = new CompressionParameters();
+ OpenJpeg.SetDefaultEncoderParameters(compressionParameters);
+ compressionParameters.TcpNumLayers = 1;
+ compressionParameters.CodingParameterDistortionAllocation = 1;
+
+ _Codec = OpenJpeg.CreateCompress(CodecFormat.J2k);
+ OpenJpeg.SetupEncoder(_Codec, compressionParameters, _Image);
+ }
+
+ #endregion
+
+ #region Properties
+
+ public int Height
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Gets a value indicating whether this instance has been disposed.
+ ///
+ /// true if this instance has been disposed; otherwise, false.
+ public bool IsDisposed
+ {
+ get;
+ private set;
+ }
+
+ public int Width
+ {
+ get;
+ private set;
+ }
+
+ #endregion
+
+ #region Methods
+
+ public byte[] Encode()
+ {
+ OpenJpeg.StartCompress(_Codec, _Image, _Stream);
+ OpenJpeg.Encode(_Codec, _Stream);
+ OpenJpeg.EndCompress(_Codec, _Stream);
+
+ var datast = Marshal.PtrToStructure(_UserData);
+ var output = new byte[datast.Position];
+ Marshal.Copy(_Buffer.Data, output, 0, output.Length);
+
+ return output;
+ }
+
+ #region Event Handlers
+
+ private static int Seek(ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var position = Math.Min((ulong)buf->Length, bytes);
+ buf->Position = (int)position;
+ return 1;
+ }
+ }
+
+ private static long Skip(ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var bytesToSkip = (int)Math.Min((ulong)buf->Length, bytes);
+ if (bytesToSkip > 0)
+ {
+ buf->Position += bytesToSkip;
+ return bytesToSkip;
+ }
+ else
+ {
+ return unchecked(-1);
+ }
+ }
+ }
+
+ private static ulong Write(IntPtr buffer, ulong bytes, IntPtr userData)
+ {
+ unsafe
+ {
+ var buf = (J2KBuffer*)userData;
+ var bytesToRead = (int)Math.Min((ulong)buf->Length, bytes);
+ if (bytesToRead > 0)
+ {
+ NativeMethods.cstd_memcpy(buffer, IntPtr.Add(buf->Data, buf->Position), bytesToRead);
+ buf->Position += bytesToRead;
+ return (ulong)bytesToRead;
+ }
+ else
+ {
+ return unchecked((ulong)-1);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Helpers
+
+ private CompressionParameters SetupEncoderParameters(OpenJpegDotNet.IO.Parameter parameter)
+ {
+ var compressionParameters = new CompressionParameters();
+ OpenJpeg.SetDefaultEncoderParameters(compressionParameters);
+
+ if (parameter.Compression.HasValue)
+ compressionParameters.TcpRates[0] = 1000f / Math.Min(Math.Max(parameter.Compression.Value, 1), 1000);
+
+ compressionParameters.TcpNumLayers = 1;
+ compressionParameters.CodingParameterDistortionAllocation = 1;
+
+ if (!parameter.Compression.HasValue)
+ compressionParameters.TcpRates[0] = 4;
+
+ return compressionParameters;
+ }
+
+ #endregion
+
+ #endregion
+
+ #region IDisposable Members
+
+ ///
+ /// Releases all resources used by this .
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ //GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases all resources used by this .
+ ///
+ /// Indicate value whether method was called.
+ private void Dispose(bool disposing)
+ {
+ if (this.IsDisposed)
+ {
+ return;
+ }
+
+ this.IsDisposed = true;
+
+ if (disposing)
+ {
+ this._Codec?.Dispose();
+ this._CompressionParameters?.Dispose();
+ this._Stream.Dispose();
+
+ Marshal.FreeHGlobal(this._Buffer.Data);
+ Marshal.FreeHGlobal(this._UserData);
+ }
+ }
+
+ #endregion
+
+ }
+}
diff --git a/LibreMetaverse/Imaging/NativeMethods.cs b/LibreMetaverse/Imaging/NativeMethods.cs
new file mode 100644
index 00000000..8cbc5403
--- /dev/null
+++ b/LibreMetaverse/Imaging/NativeMethods.cs
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2021, Sjofn LLC.
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace LibreMetaverse.Imaging
+{
+ internal sealed partial class NativeMethods
+ {
+
+ #region Fields
+
+ // Native library file name.
+ // If Linux, it will be converted to libOpenJpegDotNetNative.so
+ // If MacOSX, it will be converted to libOpenJpegDotNetNative.dylib
+ // If Windows, it will be available after call LoadLibrary.
+ // And this file name must not contain period. If it does,
+ // CLR does not add extension (.dll) and CLR fails to load library
+ internal const string NativeLibrary = "OpenJpegDotNetNative";
+
+ public const CallingConvention CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
+
+ private static readonly WindowsLibraryLoader WindowsLibraryLoader = new WindowsLibraryLoader();
+
+ #endregion
+
+ #region Constructors
+
+ static NativeMethods()
+ {
+ WindowsLibraryLoader.LoadLibraries(new[]
+ {
+ $"{NativeLibrary}"
+ });
+ }
+
+ #endregion
+
+ #region cstd
+
+ [DllImport(NativeLibrary, CallingConvention = CallingConvention)]
+ public static extern IntPtr cstd_memcpy(IntPtr dest, IntPtr src, int count);
+
+ #endregion
+
+ }
+}
diff --git a/LibreMetaverse/Imaging/OpenJPEG.cs b/LibreMetaverse/Imaging/OpenJPEG.cs
deleted file mode 100644
index b687f9fe..00000000
--- a/LibreMetaverse/Imaging/OpenJPEG.cs
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (c) 2006-2016, openmetaverse.co
- * All rights reserved.
- *
- * - Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * - Neither the name of the openmetaverse.co nor the names
- * of its contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Runtime.InteropServices;
-using Rectangle = System.Drawing.Rectangle;
-
-namespace OpenMetaverse.Imaging
-{
-#if !NO_UNSAFE
- ///
- /// A Wrapper around openjpeg to encode and decode images to and from byte arrays
- ///
- public class OpenJPEG
- {
- /// TGA Header size
- public const int TGA_HEADER_SIZE = 32;
-
- #region JPEG2000 Structs
-
- ///
- /// Defines the beginning and ending file positions of a layer in an
- /// LRCP-progression JPEG2000 file
- ///
- [System.Diagnostics.DebuggerDisplay("Start = {Start} End = {End} Size = {End - Start}")]
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- public struct J2KLayerInfo
- {
- public int Start;
- public int End;
- }
-
- ///
- /// This structure is used to marshal both encoded and decoded images.
- /// MUST MATCH THE STRUCT IN dotnet.h!
- ///
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct MarshalledImage
- {
- public IntPtr encoded; // encoded image data
- public int length; // encoded image length
- public int dummy; // padding for 64-bit alignment
-
- public IntPtr decoded; // decoded image, contiguous components
-
- public int width; // width of decoded image
- public int height; // height of decoded image
- public int layers; // layer count
- public int resolutions; // resolution count
- public int components; // component count
- public int packet_count; // packet count
- public IntPtr packets; // pointer to the packets array
- }
-
- ///
- /// Information about a single packet in a JPEG2000 stream
- ///
- [StructLayout(LayoutKind.Sequential, Pack = 4)]
- private struct MarshalledPacket
- {
- /// Packet start position
- public int start_pos;
- /// Packet header end position
- public int end_ph_pos;
- /// Packet end position
- public int end_pos;
-
- public override string ToString()
- {
- return String.Format("start_pos: {0} end_ph_pos: {1} end_pos: {2}",
- start_pos, end_ph_pos, end_pos);
- }
- }
-
- #endregion JPEG2000 Structs
-
- #region Unmanaged Function Declarations
-
-
- // allocate encoded buffer based on length field
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetAllocEncoded(ref MarshalledImage image);
-
- // allocate decoded buffer based on width and height fields
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetAllocDecoded(ref MarshalledImage image);
-
- // free buffers
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetFree(ref MarshalledImage image);
-
- // encode raw to jpeg2000
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetEncode(ref MarshalledImage image, bool lossless);
-
- // decode jpeg2000 to raw
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetDecode(ref MarshalledImage image);
-
- // decode jpeg2000 to raw, get jpeg2000 file info
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetDecodeWithInfo(ref MarshalledImage image);
-
- // invoke 64 bit openjpeg calls
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetAllocEncoded64(ref MarshalledImage image);
-
- // allocate decoded buffer based on width and height fields
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetAllocDecoded64(ref MarshalledImage image);
-
- // free buffers
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetFree64(ref MarshalledImage image);
-
- // encode raw to jpeg2000
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetEncode64(ref MarshalledImage image, bool lossless);
-
- // decode jpeg2000 to raw
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetDecode64(ref MarshalledImage image);
-
- // decode jpeg2000 to raw, get jpeg2000 file info
- [System.Security.SuppressUnmanagedCodeSecurity]
- [DllImport("openjpeg-dotnet-x86_64.dll", CallingConvention = CallingConvention.Cdecl)]
- private static extern bool DotNetDecodeWithInfo64(ref MarshalledImage image);
- #endregion Unmanaged Function Declarations
-
- /// OpenJPEG is not threadsafe, so this object is used to lock
- /// during calls into unmanaged code
- private static object OpenJPEGLock = new object();
-
- ///
- /// Encode a object into a byte array
- ///
- /// The object to encode
- /// true to enable lossless conversion, only useful for small images ie: sculptmaps
- /// A byte array containing the encoded Image object
- public static byte[] Encode(ManagedImage image, bool lossless)
- {
- if ((image.Channels & ManagedImage.ImageChannels.Color) == 0 ||
- ((image.Channels & ManagedImage.ImageChannels.Bump) != 0 && (image.Channels & ManagedImage.ImageChannels.Alpha) == 0))
- throw new ArgumentException("JPEG2000 encoding is not supported for this channel combination");
-
- byte[] encoded = null;
- MarshalledImage marshalled = new MarshalledImage();
-
- // allocate and copy to input buffer
- marshalled.width = image.Width;
- marshalled.height = image.Height;
- marshalled.components = 3;
- if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) marshalled.components++;
- if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) marshalled.components++;
-
- lock (OpenJPEGLock)
- {
-
- bool allocSuccess = (IntPtr.Size == 8) ? DotNetAllocDecoded64(ref marshalled) : DotNetAllocDecoded(ref marshalled);
-
- if (!allocSuccess)
- throw new Exception("DotNetAllocDecoded failed");
-
- int n = image.Width * image.Height;
-
- if ((image.Channels & ManagedImage.ImageChannels.Color) != 0)
- {
- Marshal.Copy(image.Red, 0, marshalled.decoded, n);
- Marshal.Copy(image.Green, 0, (IntPtr)(marshalled.decoded.ToInt64() + n), n);
- Marshal.Copy(image.Blue, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 2), n);
- }
-
- if ((image.Channels & ManagedImage.ImageChannels.Alpha) != 0) Marshal.Copy(image.Alpha, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 3), n);
- if ((image.Channels & ManagedImage.ImageChannels.Bump) != 0) Marshal.Copy(image.Bump, 0, (IntPtr)(marshalled.decoded.ToInt64() + n * 4), n);
-
- // codec will allocate output buffer
- bool encodeSuccess = (IntPtr.Size == 8) ? DotNetEncode64(ref marshalled, lossless) : DotNetEncode(ref marshalled, lossless);
- if (!encodeSuccess)
- throw new Exception("DotNetEncode failed");
-
- // copy output buffer
- encoded = new byte[marshalled.length];
- Marshal.Copy(marshalled.encoded, encoded, 0, marshalled.length);
-
- // free buffers
- if (IntPtr.Size == 8)
- DotNetFree64(ref marshalled);
- else
- DotNetFree(ref marshalled);
- }
-
- return encoded;
- }
-
- ///
- /// Encode a object into a byte array
- ///
- /// The object to encode
- /// a byte array of the encoded image
- public static byte[] Encode(ManagedImage image)
- {
- return Encode(image, false);
- }
-
- ///
- /// Decode JPEG2000 data to an and
- ///
- ///
- /// JPEG2000 encoded data
- /// ManagedImage object to decode to
- /// Image object to decode to
- /// True if the decode succeeds, otherwise false
- public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage, out Image image)
- {
- managedImage = null;
- image = null;
-
- if (DecodeToImage(encoded, out managedImage))
- {
- try
- {
- image = managedImage.ExportBitmap();
- return true;
- }
- catch (Exception ex)
- {
- Logger.Log("Failed to export and load TGA data from decoded image", Helpers.LogLevel.Error, ex);
- return false;
- }
- }
- else
- {
- return false;
- }
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- public static bool DecodeToImage(byte[] encoded, out ManagedImage managedImage)
- {
- MarshalledImage marshalled = new MarshalledImage();
-
- // Allocate and copy to input buffer
- marshalled.length = encoded.Length;
-
- lock (OpenJPEGLock)
- {
- if (IntPtr.Size == 8)
- DotNetAllocEncoded64(ref marshalled);
- else
- DotNetAllocEncoded(ref marshalled);
-
- Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length);
-
- // Codec will allocate output buffer
- if (IntPtr.Size == 8)
- DotNetDecode64(ref marshalled);
- else
- DotNetDecode(ref marshalled);
-
- int n = marshalled.width * marshalled.height;
-
- switch (marshalled.components)
- {
- case 1: // Grayscale
- managedImage = new ManagedImage(marshalled.width, marshalled.height,
- ManagedImage.ImageChannels.Color);
- Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n);
- Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n);
- Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n);
- break;
-
- case 2: // Grayscale + alpha
- managedImage = new ManagedImage(marshalled.width, marshalled.height,
- ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha);
- Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n);
- Buffer.BlockCopy(managedImage.Red, 0, managedImage.Green, 0, n);
- Buffer.BlockCopy(managedImage.Red, 0, managedImage.Blue, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Alpha, 0, n);
- break;
-
- case 3: // RGB
- managedImage = new ManagedImage(marshalled.width, marshalled.height,
- ManagedImage.ImageChannels.Color);
- Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n);
- break;
-
- case 4: // RGBA
- managedImage = new ManagedImage(marshalled.width, marshalled.height,
- ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha);
- Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n);
- break;
-
- case 5: // RGBAB
- managedImage = new ManagedImage(marshalled.width, marshalled.height,
- ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha | ManagedImage.ImageChannels.Bump);
- Marshal.Copy(marshalled.decoded, managedImage.Red, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)n), managedImage.Green, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 2)), managedImage.Blue, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 3)), managedImage.Alpha, 0, n);
- Marshal.Copy((IntPtr)(marshalled.decoded.ToInt64() + (long)(n * 4)), managedImage.Bump, 0, n);
- break;
-
- default:
- Logger.Log("Decoded image with unhandled number of components: " + marshalled.components,
- Helpers.LogLevel.Error);
-
- if (IntPtr.Size == 8)
- DotNetFree64(ref marshalled);
- else
- DotNetFree(ref marshalled);
-
- managedImage = null;
- return false;
- }
-
- if (IntPtr.Size == 8)
- DotNetFree64(ref marshalled);
- else
- DotNetFree(ref marshalled);
- }
-
- return true;
- }
-
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] layerInfo, out int components)
- {
- bool success = false;
- layerInfo = null;
- components = 0;
- MarshalledImage marshalled = new MarshalledImage();
-
- // Allocate and copy to input buffer
- marshalled.length = encoded.Length;
-
- lock (OpenJPEGLock)
- {
- if (IntPtr.Size == 8)
- DotNetAllocEncoded64(ref marshalled);
- else
- DotNetAllocEncoded(ref marshalled);
-
- Marshal.Copy(encoded, 0, marshalled.encoded, encoded.Length);
-
- // Run the decode
- bool decodeSuccess = (IntPtr.Size == 8) ? DotNetDecodeWithInfo64(ref marshalled) : DotNetDecodeWithInfo(ref marshalled);
- if (decodeSuccess)
- {
- components = marshalled.components;
-
- // Sanity check
- if (marshalled.layers * marshalled.resolutions * marshalled.components == marshalled.packet_count)
- {
- // Manually marshal the array of opj_packet_info structs
- MarshalledPacket[] packets = new MarshalledPacket[marshalled.packet_count];
- int offset = 0;
-
- for (int i = 0; i < marshalled.packet_count; i++)
- {
- MarshalledPacket packet;
- packet.start_pos = Marshal.ReadInt32(marshalled.packets, offset);
- offset += 4;
- packet.end_ph_pos = Marshal.ReadInt32(marshalled.packets, offset);
- offset += 4;
- packet.end_pos = Marshal.ReadInt32(marshalled.packets, offset);
- offset += 4;
- //double distortion = (double)Marshal.ReadInt64(marshalled.packets, offset);
- offset += 8;
-
- packets[i] = packet;
- }
-
- layerInfo = new J2KLayerInfo[marshalled.layers];
-
- for (int i = 0; i < marshalled.layers; i++)
- {
- int packetsPerLayer = marshalled.packet_count / marshalled.layers;
- MarshalledPacket startPacket = packets[packetsPerLayer * i];
- MarshalledPacket endPacket = packets[(packetsPerLayer * (i + 1)) - 1];
- layerInfo[i].Start = startPacket.start_pos;
- layerInfo[i].End = endPacket.end_pos;
- }
-
- // More sanity checking
- if (layerInfo.Length == 0 || layerInfo[layerInfo.Length - 1].End <= encoded.Length - 1)
- {
- success = true;
-
- for (int i = 0; i < layerInfo.Length; i++)
- {
- if (layerInfo[i].Start >= layerInfo[i].End ||
- (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End))
- {
- System.Text.StringBuilder output = new System.Text.StringBuilder(
- "Inconsistent packet data in JPEG2000 stream:\n");
- for (int j = 0; j < layerInfo.Length; j++)
- output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End);
- Logger.DebugLog(output.ToString());
-
- success = false;
- break;
- }
- }
-
- if (!success)
- {
- for (int i = 0; i < layerInfo.Length; i++)
- {
- if (i < layerInfo.Length - 1)
- layerInfo[i].End = layerInfo[i + 1].Start - 1;
- else
- layerInfo[i].End = marshalled.length;
- }
-
- Logger.DebugLog("Corrected JPEG2000 packet data");
- success = true;
-
- for (int i = 0; i < layerInfo.Length; i++)
- {
- if (layerInfo[i].Start >= layerInfo[i].End ||
- (i > 0 && layerInfo[i].Start <= layerInfo[i - 1].End))
- {
- System.Text.StringBuilder output = new System.Text.StringBuilder(
- "Still inconsistent packet data in JPEG2000 stream, giving up:\n");
- for (int j = 0; j < layerInfo.Length; j++)
- output.AppendFormat("Layer {0}: Start: {1} End: {2}\n", j, layerInfo[j].Start, layerInfo[j].End);
- Logger.DebugLog(output.ToString());
-
- success = false;
- break;
- }
- }
- }
- }
- else
- {
- Logger.Log(String.Format(
- "Last packet end in JPEG2000 stream extends beyond the end of the file. filesize={0} layerend={1}",
- encoded.Length, layerInfo[layerInfo.Length - 1].End), Helpers.LogLevel.Warning);
- }
- }
- else
- {
- Logger.Log(String.Format(
- "Packet count mismatch in JPEG2000 stream. layers={0} resolutions={1} components={2} packets={3}",
- marshalled.layers, marshalled.resolutions, marshalled.components, marshalled.packet_count),
- Helpers.LogLevel.Warning);
- }
- }
-
- if (IntPtr.Size == 8)
- DotNetFree64(ref marshalled);
- else
- DotNetFree(ref marshalled);
- }
-
- return success;
- }
-
- ///
- /// Encode a object into a byte array
- ///
- /// The source object to encode
- /// true to enable lossless decoding
- /// A byte array containing the source Bitmap object
- public unsafe static byte[] EncodeFromImage(Bitmap bitmap, bool lossless)
- {
- BitmapData bd;
- ManagedImage decoded;
-
- int bitmapWidth = bitmap.Width;
- int bitmapHeight = bitmap.Height;
- int pixelCount = bitmapWidth * bitmapHeight;
- int i;
-
- if ((bitmap.PixelFormat & PixelFormat.Alpha) != 0 || (bitmap.PixelFormat & PixelFormat.PAlpha) != 0)
- {
- // Four layers, RGBA
- decoded = new ManagedImage(bitmapWidth, bitmapHeight,
- ManagedImage.ImageChannels.Color | ManagedImage.ImageChannels.Alpha);
- bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight),
- ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- byte* pixel = (byte*)bd.Scan0;
-
- for (i = 0; i < pixelCount; i++)
- {
- // GDI+ gives us BGRA and we need to turn that in to RGBA
- decoded.Blue[i] = *(pixel++);
- decoded.Green[i] = *(pixel++);
- decoded.Red[i] = *(pixel++);
- decoded.Alpha[i] = *(pixel++);
- }
- }
- else if (bitmap.PixelFormat == PixelFormat.Format16bppGrayScale)
- {
- // One layer
- decoded = new ManagedImage(bitmapWidth, bitmapHeight,
- ManagedImage.ImageChannels.Color);
- bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight),
- ImageLockMode.ReadOnly, PixelFormat.Format16bppGrayScale);
- byte* pixel = (byte*)bd.Scan0;
-
- for (i = 0; i < pixelCount; i++)
- {
- // Normalize 16-bit data down to 8-bit
- ushort origVal = (byte)(*(pixel) + (*(pixel + 1) << 8));
- byte val = (byte)(((double)origVal / (double)UInt32.MaxValue) * (double)Byte.MaxValue);
-
- decoded.Red[i] = val;
- decoded.Green[i] = val;
- decoded.Blue[i] = val;
- pixel += 2;
- }
- }
- else
- {
- // Three layers, RGB
- decoded = new ManagedImage(bitmapWidth, bitmapHeight,
- ManagedImage.ImageChannels.Color);
- bd = bitmap.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight),
- ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
- byte* pixel = (byte*)bd.Scan0;
-
- for (i = 0; i < pixelCount; i++)
- {
- decoded.Blue[i] = *(pixel++);
- decoded.Green[i] = *(pixel++);
- decoded.Red[i] = *(pixel++);
- }
- }
-
- bitmap.UnlockBits(bd);
- byte[] encoded = Encode(decoded, lossless);
- return encoded;
- }
- }
-#endif
-}
diff --git a/LibreMetaverse/ImportExport/ColladalLoader.cs b/LibreMetaverse/ImportExport/ColladalLoader.cs
index d3f5494a..110bd9a8 100644
--- a/LibreMetaverse/ImportExport/ColladalLoader.cs
+++ b/LibreMetaverse/ImportExport/ColladalLoader.cs
@@ -164,7 +164,10 @@ namespace OpenMetaverse.ImportExport
bitmap = resized;
}
- material.TextureData = OpenJPEG.EncodeFromImage(bitmap, false);
+ using (var writer = new LibreMetaverse.Imaging.J2KWriter(bitmap))
+ {
+ material.TextureData = writer.Encode();
+ }
Logger.Log("Successfully encoded " + fname, Helpers.LogLevel.Info);
}
diff --git a/LibreMetaverse/LibreMetaverse.csproj b/LibreMetaverse/LibreMetaverse.csproj
index 0925d89b..3e59cd34 100644
--- a/LibreMetaverse/LibreMetaverse.csproj
+++ b/LibreMetaverse/LibreMetaverse.csproj
@@ -14,6 +14,7 @@
LibreMetaverse
true
netstandard2.0;netstandard2.1;net50
+ AnyCPU;x64;x86
True
@@ -32,6 +33,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -50,10 +85,47 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverse.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
diff --git a/LibreMetaverse/WindowsLibraryLoader.cs b/LibreMetaverse/WindowsLibraryLoader.cs
new file mode 100644
index 00000000..f4aeacfc
--- /dev/null
+++ b/LibreMetaverse/WindowsLibraryLoader.cs
@@ -0,0 +1,307 @@
+/**
+ * Copyright (c) 2021, Sjofn LLC.
+ * All rights reserved.
+ *
+ * - Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * - Neither the name of the openmetaverse.co nor the names
+ * of its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace LibreMetaverse
+{
+ internal sealed class WindowsLibraryLoader
+ {
+ #region Fields
+
+ private const string ProcessorArchitecture = "PROCESSOR_ARCHITECTURE";
+ private const string DllFileExtension = ".dll";
+ private const string DllDirectory = "dll";
+ private readonly Dictionary _ProcessorArchitectureAddressWidthPlatforms =
+ new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ {"x86", 4},
+ {"AMD64", 8},
+ {"IA64", 8},
+ {"ARM", 4}
+ };
+
+ private readonly Dictionary _ProcessorArchitecturePlatforms =
+ new Dictionary(StringComparer.OrdinalIgnoreCase)
+ {
+ {"x86", "x86"},
+ {"AMD64", "x64"},
+ {"IA64", "Itanium"},
+ {"ARM", "WinCE"}
+ };
+
+ private readonly object _SyncLock = new object();
+ private static readonly IDictionary LoadedLibraries = new Dictionary();
+
+ [DllImport("kernel32", EntryPoint = "LoadLibrary", CallingConvention = CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
+ private static extern IntPtr Win32LoadLibrary(string dllPath);
+
+ #endregion
+
+ #region Properties
+
+ public static bool IsCurrentPlatformSupported()
+ {
+ return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+ }
+
+ public static bool IsWindows()
+ {
+ return Environment.OSVersion.Platform == PlatformID.Win32NT ||
+ Environment.OSVersion.Platform == PlatformID.Win32S ||
+ Environment.OSVersion.Platform == PlatformID.Win32Windows ||
+ Environment.OSVersion.Platform == PlatformID.WinCE;
+ }
+
+ #endregion
+
+ #region Methods
+
+ #region Helpers
+
+ private static string FixUpDllFileName(string fileName)
+ {
+ if (string.IsNullOrEmpty(fileName))
+ return fileName;
+
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ return fileName;
+
+ if (!fileName.EndsWith(DllFileExtension, StringComparison.OrdinalIgnoreCase))
+ return $"{fileName}{DllFileExtension}";
+
+ return fileName;
+ }
+
+ private ProcessArchitectureInfo GetProcessArchitecture()
+ {
+ // BUG: Will this always be reliable?
+ var processArchitecture = Environment.GetEnvironmentVariable(ProcessorArchitecture);
+ var processInfo = new ProcessArchitectureInfo();
+ if (!string.IsNullOrEmpty(processArchitecture))
+ {
+ // Sanity check
+ processInfo.Architecture = processArchitecture;
+ }
+ else
+ {
+ processInfo.AddWarning("Failed to detect processor architecture, falling back to x86.");
+ processInfo.Architecture = (IntPtr.Size == 8) ? "x64" : "x86";
+ }
+
+ var addressWidth = this._ProcessorArchitectureAddressWidthPlatforms[processInfo.Architecture];
+ if (addressWidth != IntPtr.Size)
+ {
+ if (String.Equals(processInfo.Architecture, "AMD64", StringComparison.OrdinalIgnoreCase) && IntPtr.Size == 4)
+ {
+ // fall back to x86 if detected x64 but has an address width of 32 bits.
+ processInfo.Architecture = "x86";
+ processInfo.AddWarning("Expected the detected processing architecture of {0} to have an address width of {1} Bytes but was {2} Bytes, falling back to x86.", processInfo.Architecture, addressWidth, IntPtr.Size);
+ }
+ else
+ {
+ // no fallback possible
+ processInfo.AddWarning("Expected the detected processing architecture of {0} to have an address width of {1} Bytes but was {2} Bytes.", processInfo.Architecture, addressWidth, IntPtr.Size);
+
+ }
+ }
+
+ return processInfo;
+ }
+
+ private string GetPlatformName(string processorArchitecture)
+ {
+ if (String.IsNullOrEmpty(processorArchitecture))
+ return null;
+
+ string platformName;
+ if (this._ProcessorArchitecturePlatforms.TryGetValue(processorArchitecture, out platformName))
+ {
+ return platformName;
+ }
+
+ return null;
+ }
+
+ public void LoadLibraries(IEnumerable dlls)
+ {
+ if (!IsWindows())
+ return;
+
+ foreach (var dll in dlls)
+ LoadLibrary(dll);
+ }
+
+ private void LoadLibrary(string dllName)
+ {
+ if (!IsCurrentPlatformSupported())
+ return;
+
+ try
+ {
+ lock (this._SyncLock)
+ {
+ if (LoadedLibraries.ContainsKey(dllName))
+ return;
+
+ var processArch = GetProcessArchitecture();
+ IntPtr dllHandle;
+
+ // Try loading from executing assembly domain
+ var executingAssembly = GetType().GetTypeInfo().Assembly;
+ var baseDirectory = Path.GetDirectoryName(executingAssembly.Location);
+ dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
+ if (dllHandle != IntPtr.Zero) return;
+
+ // Gets the pathname of the base directory that the assembly resolver uses to probe for assemblies.
+ // https://github.com/dotnet/corefx/issues/2221
+ baseDirectory = AppContext.BaseDirectory;
+ dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
+ if (dllHandle != IntPtr.Zero) return;
+
+ // Finally try the working directory
+ baseDirectory = Path.GetFullPath(Directory.GetCurrentDirectory());
+ dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
+ if (dllHandle != IntPtr.Zero) return;
+
+ var errorMessage = new StringBuilder();
+ errorMessage.Append($"Failed to find dll \"{dllName}\", for processor architecture {processArch.Architecture}.");
+ if (processArch.HasWarnings)
+ {
+ // include process detection warnings
+ errorMessage.Append($"\r\nWarnings: \r\n{processArch.WarningText()}");
+ }
+
+ throw new Exception(errorMessage.ToString());
+ }
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(e.Message);
+ }
+ }
+
+ private IntPtr LoadLibraryInternal(string dllName, string baseDirectory, ProcessArchitectureInfo processArchInfo)
+ {
+ var platformName = GetPlatformName(processArchInfo.Architecture);
+ var expectedDllDirectory = Path.Combine(
+ Path.Combine(baseDirectory, DllDirectory), platformName);
+ return this.LoadLibraryRaw(dllName, expectedDllDirectory);
+ }
+
+ private IntPtr LoadLibraryRaw(string dllName, string baseDirectory)
+ {
+ var libraryHandle = IntPtr.Zero;
+ var fileName = FixUpDllFileName(Path.Combine(baseDirectory, dllName));
+
+ // Show where we're trying to load the file from
+ Debug.WriteLine($"Trying to load native library \"{fileName}\"...");
+
+ if (File.Exists(fileName))
+ {
+ // Attempt to load dll
+ try
+ {
+ libraryHandle = Win32LoadLibrary(fileName);
+ if (libraryHandle != IntPtr.Zero)
+ {
+ // library has been loaded
+ Debug.WriteLine($"Successfully loaded native library \"{fileName}\".");
+ LoadedLibraries.Add(dllName, libraryHandle);
+ }
+ else
+ {
+ Debug.WriteLine($"Failed to load native library \"{fileName}\".\r\nCheck windows event log.");
+ }
+ }
+ catch (Exception e)
+ {
+ var lastError = Marshal.GetLastWin32Error();
+ Debug.WriteLine($"Failed to load native library \"{fileName}\".\r\nLast Error:{lastError}\r\nCheck inner exception and\\or windows event log.\r\nInner Exception: {e}");
+ }
+ }
+ else
+ {
+ Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "The native library \"{0}\" does not exist.", fileName));
+ }
+
+ return libraryHandle;
+ }
+
+ #endregion
+
+ #endregion
+
+ private class ProcessArchitectureInfo
+ {
+ #region Constructors
+
+ public ProcessArchitectureInfo()
+ {
+ this.Warnings = new List();
+ }
+
+ #endregion
+
+ #region Properties
+
+ public string Architecture
+ {
+ get; set;
+ }
+
+ private List Warnings
+ {
+ get;
+ }
+
+ #endregion
+
+ #region Methods
+
+ public void AddWarning(string format, params object[] args)
+ {
+ Warnings.Add(String.Format(format, args));
+ }
+
+ public bool HasWarnings => Warnings.Count > 0;
+
+ public string WarningText()
+ {
+ return string.Join("\r\n", Warnings.ToArray());
+ }
+
+ #endregion
+ }
+ }
+}
diff --git a/LibreMetaverseTypes/LibreMetaverse.Types.csproj b/LibreMetaverseTypes/LibreMetaverse.Types.csproj
index 529950b5..0c77d7ae 100644
--- a/LibreMetaverseTypes/LibreMetaverse.Types.csproj
+++ b/LibreMetaverseTypes/LibreMetaverse.Types.csproj
@@ -14,6 +14,7 @@
Library
LibreMetaverse
true
+ AnyCPU;x64;x86
True
@@ -32,6 +33,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -50,6 +85,42 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverseTypes.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ LibreMetaverseTypes.XML
+ False
+ 4096
+ True
+ ..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/PrimMesher/LibreMetaverse.PrimMesher.csproj b/PrimMesher/LibreMetaverse.PrimMesher.csproj
index 3fe00fcf..6ddbd2c1 100644
--- a/PrimMesher/LibreMetaverse.PrimMesher.csproj
+++ b/PrimMesher/LibreMetaverse.PrimMesher.csproj
@@ -17,6 +17,7 @@
Copyright © OpenMetaverse Developers 2008, 2017. Copyright © Sjofn LLC 2018-2021. All rights reserved.
LICENSE.txt
https://github.com/cinderblocks/libremetaverse
+ AnyCPU;x64;x86
true
@@ -27,6 +28,24 @@
prompt
4
+
+ true
+ full
+ false
+ ..\bin\
+ TRACE;DEBUG;VERTEX_INDEXER
+ prompt
+ 4
+
+
+ true
+ full
+ false
+ ..\bin\
+ TRACE;DEBUG;VERTEX_INDEXER
+ prompt
+ 4
+
pdbonly
true
@@ -35,6 +54,22 @@
prompt
4
+
+ pdbonly
+ true
+ ..\bin\
+ TRACE;VERTEX_INDEXER
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ ..\bin\
+ TRACE;VERTEX_INDEXER
+ prompt
+ 4
+
diff --git a/Programs/Baker/Baker.csproj b/Programs/Baker/Baker.csproj
index 446e5bcf..3e2fbc97 100644
--- a/Programs/Baker/Baker.csproj
+++ b/Programs/Baker/Baker.csproj
@@ -23,6 +23,7 @@
False
+ AnyCPU;x64;x86
diff --git a/Programs/GridProxy/GridProxy.csproj b/Programs/GridProxy/GridProxy.csproj
index 7ea00e54..b008b54a 100644
--- a/Programs/GridProxy/GridProxy.csproj
+++ b/Programs/GridProxy/GridProxy.csproj
@@ -14,6 +14,7 @@
GridProxy
true
netcoreapp3.1;net5
+ AnyCPU;x64;x86
True
@@ -32,6 +33,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE;DEBUG
+ True
+ 4096
+ False
+ ..\..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
True
285212672
@@ -49,6 +84,40 @@
1591,1574,0419
AnyCPU
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
+
+ True
+ 285212672
+ False
+ TRACE
+ False
+ 4096
+ True
+ ..\..\bin\
+ False
+ False
+ False
+ 4
+ False
+ 1591,1574,0419
+ AnyCPU
+
diff --git a/Programs/VoiceTest/VoiceTest.csproj b/Programs/VoiceTest/VoiceTest.csproj
index 1ed2fb74..0d4efb79 100644
--- a/Programs/VoiceTest/VoiceTest.csproj
+++ b/Programs/VoiceTest/VoiceTest.csproj
@@ -25,6 +25,7 @@
netcoreapp3.1;net50
+ AnyCPU;x64;x86
diff --git a/Programs/examples/IRCGateway/IRCGateway.csproj b/Programs/examples/IRCGateway/IRCGateway.csproj
index 1ef8ddaa..cff458cc 100644
--- a/Programs/examples/IRCGateway/IRCGateway.csproj
+++ b/Programs/examples/IRCGateway/IRCGateway.csproj
@@ -25,6 +25,7 @@
netcoreapp3.1;net5
+ AnyCPU;x64;x86
diff --git a/Programs/examples/PacketDump/PacketDump.csproj b/Programs/examples/PacketDump/PacketDump.csproj
index 8ae634ed..6f791584 100644
--- a/Programs/examples/PacketDump/PacketDump.csproj
+++ b/Programs/examples/PacketDump/PacketDump.csproj
@@ -25,6 +25,7 @@
netcoreapp3.1
+ AnyCPU;x64;x86
diff --git a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
index 26bcf6f3..0fc152a9 100644
--- a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
@@ -5,6 +5,7 @@ using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Assets;
+using LibreMetaverse.Imaging;
namespace OpenMetaverse.TestClient
{
@@ -91,10 +92,14 @@ namespace OpenMetaverse.TestClient
File.WriteAllBytes(assetTexture.AssetID + ".jp2", assetTexture.AssetData);
Console.WriteLine("Wrote JPEG2000 image " + assetTexture.AssetID + ".jp2");
- ManagedImage imgData;
- OpenJPEG.DecodeToImage(assetTexture.AssetData, out imgData);
- byte[] tgaFile = imgData.ExportTGA();
- File.WriteAllBytes(assetTexture.AssetID + ".tga", tgaFile);
+ using (J2KReader reader = new J2KReader(assetTexture.AssetData))
+ {
+ reader.ReadHeader();
+ System.Drawing.Bitmap bitmap = reader.DecodeToBitmap();
+ ManagedImage imgData = new ManagedImage(bitmap);
+ byte[] tgaFile = imgData.ExportTGA();
+ File.WriteAllBytes(assetTexture.AssetID + ".tga", tgaFile);
+ }
Console.WriteLine("Wrote TGA image " + assetTexture.AssetID + ".tga");
}
catch (Exception e)
diff --git a/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs
index 28fe8478..de21ef1d 100644
--- a/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/UploadImageCommand.cs
@@ -77,7 +77,7 @@ namespace OpenMetaverse.TestClient
private byte[] LoadImage(string fileName)
{
- byte[] UploadData;
+ byte[] UploadData = { };
string lowfilename = fileName.ToLower();
Bitmap bitmap = null;
@@ -85,22 +85,22 @@ namespace OpenMetaverse.TestClient
{
if (lowfilename.EndsWith(".jp2") || lowfilename.EndsWith(".j2c"))
{
- Image image;
- ManagedImage managedImage;
-
// Upload JPEG2000 images untouched
UploadData = System.IO.File.ReadAllBytes(fileName);
-
- OpenJPEG.DecodeToImage(UploadData, out managedImage, out image);
- bitmap = (Bitmap)image;
+
+ using (var reader = new LibreMetaverse.Imaging.J2KReader(UploadData))
+ {
+ reader.ReadHeader();
+ bitmap = reader.DecodeToBitmap();
+ }
}
else
{
- if (lowfilename.EndsWith(".tga"))
+ if (lowfilename.EndsWith(".tga")) {
bitmap = LoadTGAClass.LoadTGA(fileName);
- else
+ } else {
bitmap = (Bitmap)Image.FromFile(fileName);
-
+ }
int oldwidth = bitmap.Width;
int oldheight = bitmap.Height;
@@ -137,8 +137,10 @@ namespace OpenMetaverse.TestClient
bitmap.Dispose();
bitmap = resized;
}
-
- UploadData = OpenJPEG.EncodeFromImage(bitmap, false);
+ using (var writer = new LibreMetaverse.Imaging.J2KWriter(bitmap))
+ {
+ UploadData = writer.Encode();
+ }
}
}
catch (Exception ex)
diff --git a/Programs/examples/TestClient/TestClient.csproj b/Programs/examples/TestClient/TestClient.csproj
index c4e276aa..2aceae33 100644
--- a/Programs/examples/TestClient/TestClient.csproj
+++ b/Programs/examples/TestClient/TestClient.csproj
@@ -24,6 +24,7 @@
false
netcoreapp3.1;net50
+ AnyCPU;x64;x86
diff --git a/Programs/mapgenerator/mapgenerator.csproj b/Programs/mapgenerator/mapgenerator.csproj
index 39880496..383be7cc 100644
--- a/Programs/mapgenerator/mapgenerator.csproj
+++ b/Programs/mapgenerator/mapgenerator.csproj
@@ -26,6 +26,7 @@
+ AnyCPU;x64;x86
diff --git a/bin/OpenMetaverse.dll.config b/bin/OpenMetaverse.dll.config
deleted file mode 100755
index ccafc0ff..00000000
--- a/bin/OpenMetaverse.dll.config
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/bin/Tao.OpenGl.dll.config b/bin/Tao.OpenGl.dll.config
deleted file mode 100644
index a788d0f0..00000000
--- a/bin/Tao.OpenGl.dll.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so
deleted file mode 100755
index 193eca4b..00000000
Binary files a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-i686.so and /dev/null differ
diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so
deleted file mode 100755
index 7a9bdfcd..00000000
Binary files a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1-x86_64.so and /dev/null differ
diff --git a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib b/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib
deleted file mode 100755
index 91f7264f..00000000
Binary files a/bin/libopenjpeg-dotnet-2-1.5.0-dotnet-1.dylib and /dev/null differ
diff --git a/bin/openjpeg-dotnet-x86_64.dll b/bin/openjpeg-dotnet-x86_64.dll
deleted file mode 100755
index 9e8cd215..00000000
Binary files a/bin/openjpeg-dotnet-x86_64.dll and /dev/null differ
diff --git a/bin/openjpeg-dotnet.dll b/bin/openjpeg-dotnet.dll
deleted file mode 100755
index 6377b8d9..00000000
Binary files a/bin/openjpeg-dotnet.dll and /dev/null differ