From ee040bdd719057f6cb4b61aad8fb75b5fdef7174 Mon Sep 17 00:00:00 2001 From: RaduMCosma Date: Fri, 30 Oct 2015 04:41:37 +0200 Subject: [PATCH] Initial commit --- .gitattributes | 63 + .gitignore | 212 + Unity Studio.sln | 20 + Unity Studio/7zip/Common/CRC.cs | 55 + Unity Studio/7zip/Common/CommandLineParser.cs | 274 + Unity Studio/7zip/Common/InBuffer.cs | 72 + Unity Studio/7zip/Common/OutBuffer.cs | 47 + Unity Studio/7zip/Compress/LZ/IMatchFinder.cs | 24 + Unity Studio/7zip/Compress/LZ/LzBinTree.cs | 367 ++ Unity Studio/7zip/Compress/LZ/LzInWindow.cs | 132 + Unity Studio/7zip/Compress/LZ/LzOutWindow.cs | 110 + Unity Studio/7zip/Compress/LZMA/LzmaBase.cs | 76 + .../7zip/Compress/LZMA/LzmaDecoder.cs | 398 ++ .../7zip/Compress/LZMA/LzmaEncoder.cs | 1480 +++++ .../7zip/Compress/RangeCoder/RangeCoder.cs | 234 + .../7zip/Compress/RangeCoder/RangeCoderBit.cs | 117 + .../Compress/RangeCoder/RangeCoderBitTree.cs | 157 + Unity Studio/7zip/ICoder.cs | 157 + Unity Studio/7zip/SevenZipHelper.cs | 126 + Unity Studio/AboutBox.Designer.cs | 188 + Unity Studio/AboutBox.cs | 109 + Unity Studio/AboutBox.resx | 603 ++ Unity Studio/AboutBox1.Designer.cs | 186 + Unity Studio/AboutBox1.cs | 104 + Unity Studio/AboutBox1.resx | 607 ++ Unity Studio/AssetPreloadData.cs | 26 + Unity Studio/AssetsFile.cs | 319 + Unity Studio/AudioClip.cs | 152 + Unity Studio/BuildSettings.cs | 38 + Unity Studio/BundleFile.cs | 135 + Unity Studio/ClassIDReference.cs | 252 + Unity Studio/EndianStream.cs | 198 + Unity Studio/FBXExport.Designer.cs | 331 + Unity Studio/FBXExport.cs | 53 + Unity Studio/FBXExport.resx | 123 + Unity Studio/FMOD/fmod.cs | 5510 +++++++++++++++++ Unity Studio/FMOD/fmod_dsp.cs | 739 +++ Unity Studio/FMOD/fmod_errors.cs | 120 + Unity Studio/FMOD/fmod_memoryinfo.cs | 199 + Unity Studio/Font.cs | 132 + Unity Studio/GOHierarchy.cs | 17 + Unity Studio/GameObject.cs | 77 + Unity Studio/Lz4DecoderStream.cs | 544 ++ Unity Studio/Material.cs | 88 + Unity Studio/Mesh.cs | 1040 ++++ Unity Studio/MeshFilter.cs | 31 + Unity Studio/PlayerSettings.cs | 40 + Unity Studio/Program.cs | 21 + Unity Studio/Properties/AssemblyInfo.cs | 36 + Unity Studio/Properties/Resources.Designer.cs | 73 + Unity Studio/Properties/Resources.resx | 124 + Unity Studio/Properties/Settings.Designer.cs | 170 + Unity Studio/Properties/Settings.settings | 42 + Unity Studio/RectTransform.cs | 30 + Unity Studio/Renderer.cs | 54 + Unity Studio/Resources/preview.png | Bin 0 -> 280460 bytes Unity Studio/SkinnedMeshRenderer.cs | 115 + Unity Studio/TextAsset.cs | 60 + Unity Studio/Texture2D.cs | 328 + Unity Studio/Transform.cs | 42 + Unity Studio/Unity Studio.csproj | 233 + Unity Studio/UnityStudioForm.Designer.cs | 782 +++ Unity Studio/UnityStudioForm.bak | 2817 +++++++++ Unity Studio/UnityStudioForm.cs | 2853 +++++++++ Unity Studio/UnityStudioForm.resx | 838 +++ Unity Studio/app.config | 48 + Unity Studio/helpers.cs | 123 + Unity Studio/unity.ico | Bin 0 -> 29363 bytes 68 files changed, 24871 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Unity Studio.sln create mode 100644 Unity Studio/7zip/Common/CRC.cs create mode 100644 Unity Studio/7zip/Common/CommandLineParser.cs create mode 100644 Unity Studio/7zip/Common/InBuffer.cs create mode 100644 Unity Studio/7zip/Common/OutBuffer.cs create mode 100644 Unity Studio/7zip/Compress/LZ/IMatchFinder.cs create mode 100644 Unity Studio/7zip/Compress/LZ/LzBinTree.cs create mode 100644 Unity Studio/7zip/Compress/LZ/LzInWindow.cs create mode 100644 Unity Studio/7zip/Compress/LZ/LzOutWindow.cs create mode 100644 Unity Studio/7zip/Compress/LZMA/LzmaBase.cs create mode 100644 Unity Studio/7zip/Compress/LZMA/LzmaDecoder.cs create mode 100644 Unity Studio/7zip/Compress/LZMA/LzmaEncoder.cs create mode 100644 Unity Studio/7zip/Compress/RangeCoder/RangeCoder.cs create mode 100644 Unity Studio/7zip/Compress/RangeCoder/RangeCoderBit.cs create mode 100644 Unity Studio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs create mode 100644 Unity Studio/7zip/ICoder.cs create mode 100644 Unity Studio/7zip/SevenZipHelper.cs create mode 100644 Unity Studio/AboutBox.Designer.cs create mode 100644 Unity Studio/AboutBox.cs create mode 100644 Unity Studio/AboutBox.resx create mode 100644 Unity Studio/AboutBox1.Designer.cs create mode 100644 Unity Studio/AboutBox1.cs create mode 100644 Unity Studio/AboutBox1.resx create mode 100644 Unity Studio/AssetPreloadData.cs create mode 100644 Unity Studio/AssetsFile.cs create mode 100644 Unity Studio/AudioClip.cs create mode 100644 Unity Studio/BuildSettings.cs create mode 100644 Unity Studio/BundleFile.cs create mode 100644 Unity Studio/ClassIDReference.cs create mode 100644 Unity Studio/EndianStream.cs create mode 100644 Unity Studio/FBXExport.Designer.cs create mode 100644 Unity Studio/FBXExport.cs create mode 100644 Unity Studio/FBXExport.resx create mode 100644 Unity Studio/FMOD/fmod.cs create mode 100644 Unity Studio/FMOD/fmod_dsp.cs create mode 100644 Unity Studio/FMOD/fmod_errors.cs create mode 100644 Unity Studio/FMOD/fmod_memoryinfo.cs create mode 100644 Unity Studio/Font.cs create mode 100644 Unity Studio/GOHierarchy.cs create mode 100644 Unity Studio/GameObject.cs create mode 100644 Unity Studio/Lz4DecoderStream.cs create mode 100644 Unity Studio/Material.cs create mode 100644 Unity Studio/Mesh.cs create mode 100644 Unity Studio/MeshFilter.cs create mode 100644 Unity Studio/PlayerSettings.cs create mode 100644 Unity Studio/Program.cs create mode 100644 Unity Studio/Properties/AssemblyInfo.cs create mode 100644 Unity Studio/Properties/Resources.Designer.cs create mode 100644 Unity Studio/Properties/Resources.resx create mode 100644 Unity Studio/Properties/Settings.Designer.cs create mode 100644 Unity Studio/Properties/Settings.settings create mode 100644 Unity Studio/RectTransform.cs create mode 100644 Unity Studio/Renderer.cs create mode 100644 Unity Studio/Resources/preview.png create mode 100644 Unity Studio/SkinnedMeshRenderer.cs create mode 100644 Unity Studio/TextAsset.cs create mode 100644 Unity Studio/Texture2D.cs create mode 100644 Unity Studio/Transform.cs create mode 100644 Unity Studio/Unity Studio.csproj create mode 100644 Unity Studio/UnityStudioForm.Designer.cs create mode 100644 Unity Studio/UnityStudioForm.bak create mode 100644 Unity Studio/UnityStudioForm.cs create mode 100644 Unity Studio/UnityStudioForm.resx create mode 100644 Unity Studio/app.config create mode 100644 Unity Studio/helpers.cs create mode 100644 Unity Studio/unity.ico diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b06e864 --- /dev/null +++ b/.gitignore @@ -0,0 +1,212 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +## TODO: Comment the next line if you want to checkin your +## web deploy settings but do note that will include unencrypted +## passwords +#*.pubxml + +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml diff --git a/Unity Studio.sln b/Unity Studio.sln new file mode 100644 index 0000000..7185562 --- /dev/null +++ b/Unity Studio.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unity Studio", "Unity Studio\Unity Studio.csproj", "{24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.ActiveCfg = Debug|x86 + {24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Debug|x86.Build.0 = Debug|x86 + {24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.ActiveCfg = Release|x86 + {24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Unity Studio/7zip/Common/CRC.cs b/Unity Studio/7zip/Common/CRC.cs new file mode 100644 index 0000000..82cc857 --- /dev/null +++ b/Unity Studio/7zip/Common/CRC.cs @@ -0,0 +1,55 @@ +// Common/CRC.cs + +namespace SevenZip +{ + class CRC + { + public static readonly uint[] Table; + + static CRC() + { + Table = new uint[256]; + const uint kPoly = 0xEDB88320; + for (uint i = 0; i < 256; i++) + { + uint r = i; + for (int j = 0; j < 8; j++) + if ((r & 1) != 0) + r = (r >> 1) ^ kPoly; + else + r >>= 1; + Table[i] = r; + } + } + + uint _value = 0xFFFFFFFF; + + public void Init() { _value = 0xFFFFFFFF; } + + public void UpdateByte(byte b) + { + _value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8); + } + + public void Update(byte[] data, uint offset, uint size) + { + for (uint i = 0; i < size; i++) + _value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8); + } + + public uint GetDigest() { return _value ^ 0xFFFFFFFF; } + + static uint CalculateDigest(byte[] data, uint offset, uint size) + { + CRC crc = new CRC(); + // crc.Init(); + crc.Update(data, offset, size); + return crc.GetDigest(); + } + + static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size) + { + return (CalculateDigest(data, offset, size) == digest); + } + } +} diff --git a/Unity Studio/7zip/Common/CommandLineParser.cs b/Unity Studio/7zip/Common/CommandLineParser.cs new file mode 100644 index 0000000..8eabf59 --- /dev/null +++ b/Unity Studio/7zip/Common/CommandLineParser.cs @@ -0,0 +1,274 @@ +// CommandLineParser.cs + +using System; +using System.Collections; + +namespace SevenZip.CommandLineParser +{ + public enum SwitchType + { + Simple, + PostMinus, + LimitedPostString, + UnLimitedPostString, + PostChar + } + + public class SwitchForm + { + public string IDString; + public SwitchType Type; + public bool Multi; + public int MinLen; + public int MaxLen; + public string PostCharSet; + + public SwitchForm(string idString, SwitchType type, bool multi, + int minLen, int maxLen, string postCharSet) + { + IDString = idString; + Type = type; + Multi = multi; + MinLen = minLen; + MaxLen = maxLen; + PostCharSet = postCharSet; + } + public SwitchForm(string idString, SwitchType type, bool multi, int minLen): + this(idString, type, multi, minLen, 0, "") + { + } + public SwitchForm(string idString, SwitchType type, bool multi): + this(idString, type, multi, 0) + { + } + } + + public class SwitchResult + { + public bool ThereIs; + public bool WithMinus; + public ArrayList PostStrings = new ArrayList(); + public int PostCharIndex; + public SwitchResult() + { + ThereIs = false; + } + } + + public class Parser + { + public ArrayList NonSwitchStrings = new ArrayList(); + SwitchResult[] _switches; + + public Parser(int numSwitches) + { + _switches = new SwitchResult[numSwitches]; + for (int i = 0; i < numSwitches; i++) + _switches[i] = new SwitchResult(); + } + + bool ParseString(string srcString, SwitchForm[] switchForms) + { + int len = srcString.Length; + if (len == 0) + return false; + int pos = 0; + if (!IsItSwitchChar(srcString[pos])) + return false; + while (pos < len) + { + if (IsItSwitchChar(srcString[pos])) + pos++; + const int kNoLen = -1; + int matchedSwitchIndex = 0; + int maxLen = kNoLen; + for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++) + { + int switchLen = switchForms[switchIndex].IDString.Length; + if (switchLen <= maxLen || pos + switchLen > len) + continue; + if (String.Compare(switchForms[switchIndex].IDString, 0, + srcString, pos, switchLen, true) == 0) + { + matchedSwitchIndex = switchIndex; + maxLen = switchLen; + } + } + if (maxLen == kNoLen) + throw new Exception("maxLen == kNoLen"); + SwitchResult matchedSwitch = _switches[matchedSwitchIndex]; + SwitchForm switchForm = switchForms[matchedSwitchIndex]; + if ((!switchForm.Multi) && matchedSwitch.ThereIs) + throw new Exception("switch must be single"); + matchedSwitch.ThereIs = true; + pos += maxLen; + int tailSize = len - pos; + SwitchType type = switchForm.Type; + switch (type) + { + case SwitchType.PostMinus: + { + if (tailSize == 0) + matchedSwitch.WithMinus = false; + else + { + matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus); + if (matchedSwitch.WithMinus) + pos++; + } + break; + } + case SwitchType.PostChar: + { + if (tailSize < switchForm.MinLen) + throw new Exception("switch is not full"); + string charSet = switchForm.PostCharSet; + const int kEmptyCharValue = -1; + if (tailSize == 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + int index = charSet.IndexOf(srcString[pos]); + if (index < 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + matchedSwitch.PostCharIndex = index; + pos++; + } + } + break; + } + case SwitchType.LimitedPostString: + case SwitchType.UnLimitedPostString: + { + int minLen = switchForm.MinLen; + if (tailSize < minLen) + throw new Exception("switch is not full"); + if (type == SwitchType.UnLimitedPostString) + { + matchedSwitch.PostStrings.Add(srcString.Substring(pos)); + return true; + } + String stringSwitch = srcString.Substring(pos, minLen); + pos += minLen; + for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++) + { + char c = srcString[pos]; + if (IsItSwitchChar(c)) + break; + stringSwitch += c; + } + matchedSwitch.PostStrings.Add(stringSwitch); + break; + } + } + } + return true; + + } + + public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings) + { + int numCommandStrings = commandStrings.Length; + bool stopSwitch = false; + for (int i = 0; i < numCommandStrings; i++) + { + string s = commandStrings[i]; + if (stopSwitch) + NonSwitchStrings.Add(s); + else + if (s == kStopSwitchParsing) + stopSwitch = true; + else + if (!ParseString(s, switchForms)) + NonSwitchStrings.Add(s); + } + } + + public SwitchResult this[int index] { get { return _switches[index]; } } + + public static int ParseCommand(CommandForm[] commandForms, string commandString, + out string postString) + { + for (int i = 0; i < commandForms.Length; i++) + { + string id = commandForms[i].IDString; + if (commandForms[i].PostStringMode) + { + if (commandString.IndexOf(id) == 0) + { + postString = commandString.Substring(id.Length); + return i; + } + } + else + if (commandString == id) + { + postString = ""; + return i; + } + } + postString = ""; + return -1; + } + + static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms, + string commandString, ArrayList indices) + { + indices.Clear(); + int numUsedChars = 0; + for (int i = 0; i < numForms; i++) + { + CommandSubCharsSet charsSet = forms[i]; + int currentIndex = -1; + int len = charsSet.Chars.Length; + for (int j = 0; j < len; j++) + { + char c = charsSet.Chars[j]; + int newIndex = commandString.IndexOf(c); + if (newIndex >= 0) + { + if (currentIndex >= 0) + return false; + if (commandString.IndexOf(c, newIndex + 1) >= 0) + return false; + currentIndex = j; + numUsedChars++; + } + } + if (currentIndex == -1 && !charsSet.EmptyAllowed) + return false; + indices.Add(currentIndex); + } + return (numUsedChars == commandString.Length); + } + const char kSwitchID1 = '-'; + const char kSwitchID2 = '/'; + + const char kSwitchMinus = '-'; + const string kStopSwitchParsing = "--"; + + static bool IsItSwitchChar(char c) + { + return (c == kSwitchID1 || c == kSwitchID2); + } + } + + public class CommandForm + { + public string IDString = ""; + public bool PostStringMode = false; + public CommandForm(string idString, bool postStringMode) + { + IDString = idString; + PostStringMode = postStringMode; + } + } + + class CommandSubCharsSet + { + public string Chars = ""; + public bool EmptyAllowed = false; + } +} diff --git a/Unity Studio/7zip/Common/InBuffer.cs b/Unity Studio/7zip/Common/InBuffer.cs new file mode 100644 index 0000000..7c51f0b --- /dev/null +++ b/Unity Studio/7zip/Common/InBuffer.cs @@ -0,0 +1,72 @@ +// InBuffer.cs + +namespace SevenZip.Buffer +{ + public class InBuffer + { + byte[] m_Buffer; + uint m_Pos; + uint m_Limit; + uint m_BufferSize; + System.IO.Stream m_Stream; + bool m_StreamWasExhausted; + ulong m_ProcessedSize; + + public InBuffer(uint bufferSize) + { + m_Buffer = new byte[bufferSize]; + m_BufferSize = bufferSize; + } + + public void Init(System.IO.Stream stream) + { + m_Stream = stream; + m_ProcessedSize = 0; + m_Limit = 0; + m_Pos = 0; + m_StreamWasExhausted = false; + } + + public bool ReadBlock() + { + if (m_StreamWasExhausted) + return false; + m_ProcessedSize += m_Pos; + int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize); + m_Pos = 0; + m_Limit = (uint)aNumProcessedBytes; + m_StreamWasExhausted = (aNumProcessedBytes == 0); + return (!m_StreamWasExhausted); + } + + + public void ReleaseStream() + { + // m_Stream.Close(); + m_Stream = null; + } + + public bool ReadByte(byte b) // check it + { + if (m_Pos >= m_Limit) + if (!ReadBlock()) + return false; + b = m_Buffer[m_Pos++]; + return true; + } + + public byte ReadByte() + { + // return (byte)m_Stream.ReadByte(); + if (m_Pos >= m_Limit) + if (!ReadBlock()) + return 0xFF; + return m_Buffer[m_Pos++]; + } + + public ulong GetProcessedSize() + { + return m_ProcessedSize + m_Pos; + } + } +} diff --git a/Unity Studio/7zip/Common/OutBuffer.cs b/Unity Studio/7zip/Common/OutBuffer.cs new file mode 100644 index 0000000..2da16e1 --- /dev/null +++ b/Unity Studio/7zip/Common/OutBuffer.cs @@ -0,0 +1,47 @@ +// OutBuffer.cs + +namespace SevenZip.Buffer +{ + public class OutBuffer + { + byte[] m_Buffer; + uint m_Pos; + uint m_BufferSize; + System.IO.Stream m_Stream; + ulong m_ProcessedSize; + + public OutBuffer(uint bufferSize) + { + m_Buffer = new byte[bufferSize]; + m_BufferSize = bufferSize; + } + + public void SetStream(System.IO.Stream stream) { m_Stream = stream; } + public void FlushStream() { m_Stream.Flush(); } + public void CloseStream() { m_Stream.Close(); } + public void ReleaseStream() { m_Stream = null; } + + public void Init() + { + m_ProcessedSize = 0; + m_Pos = 0; + } + + public void WriteByte(byte b) + { + m_Buffer[m_Pos++] = b; + if (m_Pos >= m_BufferSize) + FlushData(); + } + + public void FlushData() + { + if (m_Pos == 0) + return; + m_Stream.Write(m_Buffer, 0, (int)m_Pos); + m_Pos = 0; + } + + public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; } + } +} diff --git a/Unity Studio/7zip/Compress/LZ/IMatchFinder.cs b/Unity Studio/7zip/Compress/LZ/IMatchFinder.cs new file mode 100644 index 0000000..10ca2b3 --- /dev/null +++ b/Unity Studio/7zip/Compress/LZ/IMatchFinder.cs @@ -0,0 +1,24 @@ +// IMatchFinder.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + interface IInWindowStream + { + void SetStream(System.IO.Stream inStream); + void Init(); + void ReleaseStream(); + Byte GetIndexByte(Int32 index); + UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit); + UInt32 GetNumAvailableBytes(); + } + + interface IMatchFinder : IInWindowStream + { + void Create(UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter); + UInt32 GetMatches(UInt32[] distances); + void Skip(UInt32 num); + } +} diff --git a/Unity Studio/7zip/Compress/LZ/LzBinTree.cs b/Unity Studio/7zip/Compress/LZ/LzBinTree.cs new file mode 100644 index 0000000..c1c006b --- /dev/null +++ b/Unity Studio/7zip/Compress/LZ/LzBinTree.cs @@ -0,0 +1,367 @@ +// LzBinTree.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + public class BinTree : InWindow, IMatchFinder + { + UInt32 _cyclicBufferPos; + UInt32 _cyclicBufferSize = 0; + UInt32 _matchMaxLen; + + UInt32[] _son; + UInt32[] _hash; + + UInt32 _cutValue = 0xFF; + UInt32 _hashMask; + UInt32 _hashSizeSum = 0; + + bool HASH_ARRAY = true; + + const UInt32 kHash2Size = 1 << 10; + const UInt32 kHash3Size = 1 << 16; + const UInt32 kBT2HashSize = 1 << 16; + const UInt32 kStartMaxLen = 1; + const UInt32 kHash3Offset = kHash2Size; + const UInt32 kEmptyHashValue = 0; + const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1; + + UInt32 kNumHashDirectBytes = 0; + UInt32 kMinMatchCheck = 4; + UInt32 kFixHashSize = kHash2Size + kHash3Size; + + public void SetType(int numHashBytes) + { + HASH_ARRAY = (numHashBytes > 2); + if (HASH_ARRAY) + { + kNumHashDirectBytes = 0; + kMinMatchCheck = 4; + kFixHashSize = kHash2Size + kHash3Size; + } + else + { + kNumHashDirectBytes = 2; + kMinMatchCheck = 2 + 1; + kFixHashSize = 0; + } + } + + public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); } + public new void ReleaseStream() { base.ReleaseStream(); } + + public new void Init() + { + base.Init(); + for (UInt32 i = 0; i < _hashSizeSum; i++) + _hash[i] = kEmptyHashValue; + _cyclicBufferPos = 0; + ReduceOffsets(-1); + } + + public new void MovePos() + { + if (++_cyclicBufferPos >= _cyclicBufferSize) + _cyclicBufferPos = 0; + base.MovePos(); + if (_pos == kMaxValForNormalize) + Normalize(); + } + + public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); } + + public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) + { return base.GetMatchLen(index, distance, limit); } + + public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); } + + public void Create(UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter) + { + if (historySize > kMaxValForNormalize - 256) + throw new Exception(); + _cutValue = 16 + (matchMaxLen >> 1); + + UInt32 windowReservSize = (historySize + keepAddBufferBefore + + matchMaxLen + keepAddBufferAfter) / 2 + 256; + + base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); + + _matchMaxLen = matchMaxLen; + + UInt32 cyclicBufferSize = historySize + 1; + if (_cyclicBufferSize != cyclicBufferSize) + _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2]; + + UInt32 hs = kBT2HashSize; + + if (HASH_ARRAY) + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; + if (hs > (1 << 24)) + hs >>= 1; + _hashMask = hs; + hs++; + hs += kFixHashSize; + } + if (hs != _hashSizeSum) + _hash = new UInt32[_hashSizeSum = hs]; + } + + public UInt32 GetMatches(UInt32[] distances) + { + UInt32 lenLimit; + if (_pos + _matchMaxLen <= _streamPos) + lenLimit = _matchMaxLen; + else + { + lenLimit = _streamPos - _pos; + if (lenLimit < kMinMatchCheck) + { + MovePos(); + return 0; + } + } + + UInt32 offset = 0; + UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + UInt32 cur = _bufferOffset + _pos; + UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize; + UInt32 hashValue, hash2Value = 0, hash3Value = 0; + + if (HASH_ARRAY) + { + UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + hash2Value = temp & (kHash2Size - 1); + temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); + hash3Value = temp & (kHash3Size - 1); + hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; + } + else + hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); + + UInt32 curMatch = _hash[kFixHashSize + hashValue]; + if (HASH_ARRAY) + { + UInt32 curMatch2 = _hash[hash2Value]; + UInt32 curMatch3 = _hash[kHash3Offset + hash3Value]; + _hash[hash2Value] = _pos; + _hash[kHash3Offset + hash3Value] = _pos; + if (curMatch2 > matchMinPos) + if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) + { + distances[offset++] = maxLen = 2; + distances[offset++] = _pos - curMatch2 - 1; + } + if (curMatch3 > matchMinPos) + if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) + { + if (curMatch3 == curMatch2) + offset -= 2; + distances[offset++] = maxLen = 3; + distances[offset++] = _pos - curMatch3 - 1; + curMatch2 = curMatch3; + } + if (offset != 0 && curMatch2 == curMatch) + { + offset -= 2; + maxLen = kStartMaxLen; + } + } + + _hash[kFixHashSize + hashValue] = _pos; + + UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; + UInt32 ptr1 = (_cyclicBufferPos << 1); + + UInt32 len0, len1; + len0 = len1 = kNumHashDirectBytes; + + if (kNumHashDirectBytes != 0) + { + if (curMatch > matchMinPos) + { + if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] != + _bufferBase[cur + kNumHashDirectBytes]) + { + distances[offset++] = maxLen = kNumHashDirectBytes; + distances[offset++] = _pos - curMatch - 1; + } + } + } + + UInt32 count = _cutValue; + + while(true) + { + if(curMatch <= matchMinPos || count-- == 0) + { + _son[ptr0] = _son[ptr1] = kEmptyHashValue; + break; + } + UInt32 delta = _pos - curMatch; + UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? + (_cyclicBufferPos - delta) : + (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + + UInt32 pby1 = _bufferOffset + curMatch; + UInt32 len = Math.Min(len0, len1); + if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) + { + while(++len != lenLimit) + if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) + break; + if (maxLen < len) + { + distances[offset++] = maxLen = len; + distances[offset++] = delta - 1; + if (len == lenLimit) + { + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; + } + } + } + if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) + { + _son[ptr1] = curMatch; + ptr1 = cyclicPos + 1; + curMatch = _son[ptr1]; + len1 = len; + } + else + { + _son[ptr0] = curMatch; + ptr0 = cyclicPos; + curMatch = _son[ptr0]; + len0 = len; + } + } + MovePos(); + return offset; + } + + public void Skip(UInt32 num) + { + do + { + UInt32 lenLimit; + if (_pos + _matchMaxLen <= _streamPos) + lenLimit = _matchMaxLen; + else + { + lenLimit = _streamPos - _pos; + if (lenLimit < kMinMatchCheck) + { + MovePos(); + continue; + } + } + + UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; + UInt32 cur = _bufferOffset + _pos; + + UInt32 hashValue; + + if (HASH_ARRAY) + { + UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1]; + UInt32 hash2Value = temp & (kHash2Size - 1); + _hash[hash2Value] = _pos; + temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8); + UInt32 hash3Value = temp & (kHash3Size - 1); + _hash[kHash3Offset + hash3Value] = _pos; + hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask; + } + else + hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8); + + UInt32 curMatch = _hash[kFixHashSize + hashValue]; + _hash[kFixHashSize + hashValue] = _pos; + + UInt32 ptr0 = (_cyclicBufferPos << 1) + 1; + UInt32 ptr1 = (_cyclicBufferPos << 1); + + UInt32 len0, len1; + len0 = len1 = kNumHashDirectBytes; + + UInt32 count = _cutValue; + while (true) + { + if (curMatch <= matchMinPos || count-- == 0) + { + _son[ptr0] = _son[ptr1] = kEmptyHashValue; + break; + } + + UInt32 delta = _pos - curMatch; + UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ? + (_cyclicBufferPos - delta) : + (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; + + UInt32 pby1 = _bufferOffset + curMatch; + UInt32 len = Math.Min(len0, len1); + if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) + { + while (++len != lenLimit) + if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) + break; + if (len == lenLimit) + { + _son[ptr1] = _son[cyclicPos]; + _son[ptr0] = _son[cyclicPos + 1]; + break; + } + } + if (_bufferBase[pby1 + len] < _bufferBase[cur + len]) + { + _son[ptr1] = curMatch; + ptr1 = cyclicPos + 1; + curMatch = _son[ptr1]; + len1 = len; + } + else + { + _son[ptr0] = curMatch; + ptr0 = cyclicPos; + curMatch = _son[ptr0]; + len0 = len; + } + } + MovePos(); + } + while (--num != 0); + } + + void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue) + { + for (UInt32 i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } + } + + void Normalize() + { + UInt32 subValue = _pos - _cyclicBufferSize; + NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); + NormalizeLinks(_hash, _hashSizeSum, subValue); + ReduceOffsets((Int32)subValue); + } + + public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; } + } +} diff --git a/Unity Studio/7zip/Compress/LZ/LzInWindow.cs b/Unity Studio/7zip/Compress/LZ/LzInWindow.cs new file mode 100644 index 0000000..52d23ce --- /dev/null +++ b/Unity Studio/7zip/Compress/LZ/LzInWindow.cs @@ -0,0 +1,132 @@ +// LzInWindow.cs + +using System; + +namespace SevenZip.Compression.LZ +{ + public class InWindow + { + public Byte[] _bufferBase = null; // pointer to buffer with data + System.IO.Stream _stream; + UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done + bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream + + UInt32 _pointerToLastSafePosition; + + public UInt32 _bufferOffset; + + public UInt32 _blockSize; // Size of Allocated memory block + public UInt32 _pos; // offset (from _buffer) of curent byte + UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos + UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos + public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream + + public void MoveBlock() + { + UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore; + // we need one additional byte, since MovePos moves on 1 byte. + if (offset > 0) + offset--; + + UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset; + + // check negative offset ???? + for (UInt32 i = 0; i < numBytes; i++) + _bufferBase[i] = _bufferBase[offset + i]; + _bufferOffset -= offset; + } + + public virtual void ReadBlock() + { + if (_streamEndWasReached) + return; + while (true) + { + int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos); + if (size == 0) + return; + int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size); + if (numReadBytes == 0) + { + _posLimit = _streamPos; + UInt32 pointerToPostion = _bufferOffset + _posLimit; + if (pointerToPostion > _pointerToLastSafePosition) + _posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset); + + _streamEndWasReached = true; + return; + } + _streamPos += (UInt32)numReadBytes; + if (_streamPos >= _pos + _keepSizeAfter) + _posLimit = _streamPos - _keepSizeAfter; + } + } + + void Free() { _bufferBase = null; } + + public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv) + { + _keepSizeBefore = keepSizeBefore; + _keepSizeAfter = keepSizeAfter; + UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv; + if (_bufferBase == null || _blockSize != blockSize) + { + Free(); + _blockSize = blockSize; + _bufferBase = new Byte[_blockSize]; + } + _pointerToLastSafePosition = _blockSize - keepSizeAfter; + } + + public void SetStream(System.IO.Stream stream) { _stream = stream; } + public void ReleaseStream() { _stream = null; } + + public void Init() + { + _bufferOffset = 0; + _pos = 0; + _streamPos = 0; + _streamEndWasReached = false; + ReadBlock(); + } + + public void MovePos() + { + _pos++; + if (_pos > _posLimit) + { + UInt32 pointerToPostion = _bufferOffset + _pos; + if (pointerToPostion > _pointerToLastSafePosition) + MoveBlock(); + ReadBlock(); + } + } + + public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; } + + // index + limit have not to exceed _keepSizeAfter; + public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit) + { + if (_streamEndWasReached) + if ((_pos + index) + limit > _streamPos) + limit = _streamPos - (UInt32)(_pos + index); + distance++; + // Byte *pby = _buffer + (size_t)_pos + index; + UInt32 pby = _bufferOffset + _pos + (UInt32)index; + + UInt32 i; + for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++); + return i; + } + + public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; } + + public void ReduceOffsets(Int32 subValue) + { + _bufferOffset += (UInt32)subValue; + _posLimit -= (UInt32)subValue; + _pos -= (UInt32)subValue; + _streamPos -= (UInt32)subValue; + } + } +} diff --git a/Unity Studio/7zip/Compress/LZ/LzOutWindow.cs b/Unity Studio/7zip/Compress/LZ/LzOutWindow.cs new file mode 100644 index 0000000..c998584 --- /dev/null +++ b/Unity Studio/7zip/Compress/LZ/LzOutWindow.cs @@ -0,0 +1,110 @@ +// LzOutWindow.cs + +namespace SevenZip.Compression.LZ +{ + public class OutWindow + { + byte[] _buffer = null; + uint _pos; + uint _windowSize = 0; + uint _streamPos; + System.IO.Stream _stream; + + public uint TrainSize = 0; + + public void Create(uint windowSize) + { + if (_windowSize != windowSize) + { + // System.GC.Collect(); + _buffer = new byte[windowSize]; + } + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + } + + public void Init(System.IO.Stream stream, bool solid) + { + ReleaseStream(); + _stream = stream; + if (!solid) + { + _streamPos = 0; + _pos = 0; + TrainSize = 0; + } + } + + public bool Train(System.IO.Stream stream) + { + long len = stream.Length; + uint size = (len < _windowSize) ? (uint)len : _windowSize; + TrainSize = size; + stream.Position = len - size; + _streamPos = _pos = 0; + while (size > 0) + { + uint curSize = _windowSize - _pos; + if (size < curSize) + curSize = size; + int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize); + if (numReadBytes == 0) + return false; + size -= (uint)numReadBytes; + _pos += (uint)numReadBytes; + _streamPos += (uint)numReadBytes; + if (_pos == _windowSize) + _streamPos = _pos = 0; + } + return true; + } + + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + uint size = _pos - _streamPos; + if (size == 0) + return; + _stream.Write(_buffer, (int)_streamPos, (int)size); + if (_pos >= _windowSize) + _pos = 0; + _streamPos = _pos; + } + + public void CopyBlock(uint distance, uint len) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + for (; len > 0; len--) + { + if (pos >= _windowSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + if (_pos >= _windowSize) + Flush(); + } + } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + if (_pos >= _windowSize) + Flush(); + } + + public byte GetByte(uint distance) + { + uint pos = _pos - distance - 1; + if (pos >= _windowSize) + pos += _windowSize; + return _buffer[pos]; + } + } +} diff --git a/Unity Studio/7zip/Compress/LZMA/LzmaBase.cs b/Unity Studio/7zip/Compress/LZMA/LzmaBase.cs new file mode 100644 index 0000000..c7bca86 --- /dev/null +++ b/Unity Studio/7zip/Compress/LZMA/LzmaBase.cs @@ -0,0 +1,76 @@ +// LzmaBase.cs + +namespace SevenZip.Compression.LZMA +{ + internal abstract class Base + { + public const uint kNumRepDistances = 4; + public const uint kNumStates = 12; + + // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; + // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; + // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; + // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + + public struct State + { + public uint Index; + public void Init() { Index = 0; } + public void UpdateChar() + { + if (Index < 4) Index = 0; + else if (Index < 10) Index -= 3; + else Index -= 6; + } + public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); } + public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); } + public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); } + public bool IsCharState() { return Index < 7; } + } + + public const int kNumPosSlotBits = 6; + public const int kDicLogSizeMin = 0; + // public const int kDicLogSizeMax = 30; + // public const uint kDistTableSizeMax = kDicLogSizeMax * 2; + + public const int kNumLenToPosStatesBits = 2; // it's for speed optimization + public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits; + + public const uint kMatchMinLen = 2; + + public static uint GetLenToPosState(uint len) + { + len -= kMatchMinLen; + if (len < kNumLenToPosStates) + return len; + return (uint)(kNumLenToPosStates - 1); + } + + public const int kNumAlignBits = 4; + public const uint kAlignTableSize = 1 << kNumAlignBits; + public const uint kAlignMask = (kAlignTableSize - 1); + + public const uint kStartPosModelIndex = 4; + public const uint kEndPosModelIndex = 14; + public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; + + public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2); + + public const uint kNumLitPosStatesBitsEncodingMax = 4; + public const uint kNumLitContextBitsMax = 8; + + public const int kNumPosStatesBitsMax = 4; + public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax); + public const int kNumPosStatesBitsEncodingMax = 4; + public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); + + public const int kNumLowLenBits = 3; + public const int kNumMidLenBits = 3; + public const int kNumHighLenBits = 8; + public const uint kNumLowLenSymbols = 1 << kNumLowLenBits; + public const uint kNumMidLenSymbols = 1 << kNumMidLenBits; + public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols + + (1 << kNumHighLenBits); + public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1; + } +} diff --git a/Unity Studio/7zip/Compress/LZMA/LzmaDecoder.cs b/Unity Studio/7zip/Compress/LZMA/LzmaDecoder.cs new file mode 100644 index 0000000..a9be39f --- /dev/null +++ b/Unity Studio/7zip/Compress/LZMA/LzmaDecoder.cs @@ -0,0 +1,398 @@ +// LzmaDecoder.cs + +using System; + +namespace SevenZip.Compression.LZMA +{ + using RangeCoder; + + public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream + { + class LenDecoder + { + BitDecoder m_Choice = new BitDecoder(); + BitDecoder m_Choice2 = new BitDecoder(); + BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax]; + BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits); + uint m_NumPosStates = 0; + + public void Create(uint numPosStates) + { + for (uint posState = m_NumPosStates; posState < numPosStates; posState++) + { + m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits); + m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits); + } + m_NumPosStates = numPosStates; + } + + public void Init() + { + m_Choice.Init(); + for (uint posState = 0; posState < m_NumPosStates; posState++) + { + m_LowCoder[posState].Init(); + m_MidCoder[posState].Init(); + } + m_Choice2.Init(); + m_HighCoder.Init(); + } + + public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState) + { + if (m_Choice.Decode(rangeDecoder) == 0) + return m_LowCoder[posState].Decode(rangeDecoder); + else + { + uint symbol = Base.kNumLowLenSymbols; + if (m_Choice2.Decode(rangeDecoder) == 0) + symbol += m_MidCoder[posState].Decode(rangeDecoder); + else + { + symbol += Base.kNumMidLenSymbols; + symbol += m_HighCoder.Decode(rangeDecoder); + } + return symbol; + } + } + } + + class LiteralDecoder + { + struct Decoder2 + { + BitDecoder[] m_Decoders; + public void Create() { m_Decoders = new BitDecoder[0x300]; } + public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder) + { + uint symbol = 1; + do + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); + while (symbol < 0x100); + return (byte)symbol; + } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte) + { + uint symbol = 1; + do + { + uint matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + if (matchBit != bit) + { + while (symbol < 0x100) + symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder); + break; + } + } + while (symbol < 0x100); + return (byte)symbol; + } + } + + Decoder2[] m_Coders; + int m_NumPrevBits; + int m_NumPosBits; + uint m_PosMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (m_Coders != null && m_NumPrevBits == numPrevBits && + m_NumPosBits == numPosBits) + return; + m_NumPosBits = numPosBits; + m_PosMask = ((uint)1 << numPosBits) - 1; + m_NumPrevBits = numPrevBits; + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new Decoder2[numStates]; + for (uint i = 0; i < numStates; i++) + m_Coders[i].Create(); + } + + public void Init() + { + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + for (uint i = 0; i < numStates; i++) + m_Coders[i].Init(); + } + + uint GetState(uint pos, byte prevByte) + { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); } + + public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte) + { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } + + public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte) + { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } + }; + + LZ.OutWindow m_OutWindow = new LZ.OutWindow(); + RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder(); + + BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates]; + BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates]; + BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + + BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits); + + LenDecoder m_LenDecoder = new LenDecoder(); + LenDecoder m_RepLenDecoder = new LenDecoder(); + + LiteralDecoder m_LiteralDecoder = new LiteralDecoder(); + + uint m_DictionarySize; + uint m_DictionarySizeCheck; + + uint m_PosStateMask; + + public Decoder() + { + m_DictionarySize = 0xFFFFFFFF; + for (int i = 0; i < Base.kNumLenToPosStates; i++) + m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits); + } + + void SetDictionarySize(uint dictionarySize) + { + if (m_DictionarySize != dictionarySize) + { + m_DictionarySize = dictionarySize; + m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1); + uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12)); + m_OutWindow.Create(blockSize); + } + } + + void SetLiteralProperties(int lp, int lc) + { + if (lp > 8) + throw new InvalidParamException(); + if (lc > 8) + throw new InvalidParamException(); + m_LiteralDecoder.Create(lp, lc); + } + + void SetPosBitsProperties(int pb) + { + if (pb > Base.kNumPosStatesBitsMax) + throw new InvalidParamException(); + uint numPosStates = (uint)1 << pb; + m_LenDecoder.Create(numPosStates); + m_RepLenDecoder.Create(numPosStates); + m_PosStateMask = numPosStates - 1; + } + + bool _solid = false; + void Init(System.IO.Stream inStream, System.IO.Stream outStream) + { + m_RangeDecoder.Init(inStream); + m_OutWindow.Init(outStream, _solid); + + uint i; + for (i = 0; i < Base.kNumStates; i++) + { + for (uint j = 0; j <= m_PosStateMask; j++) + { + uint index = (i << Base.kNumPosStatesBitsMax) + j; + m_IsMatchDecoders[index].Init(); + m_IsRep0LongDecoders[index].Init(); + } + m_IsRepDecoders[i].Init(); + m_IsRepG0Decoders[i].Init(); + m_IsRepG1Decoders[i].Init(); + m_IsRepG2Decoders[i].Init(); + } + + m_LiteralDecoder.Init(); + for (i = 0; i < Base.kNumLenToPosStates; i++) + m_PosSlotDecoder[i].Init(); + // m_PosSpecDecoder.Init(); + for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++) + m_PosDecoders[i].Init(); + + m_LenDecoder.Init(); + m_RepLenDecoder.Init(); + m_PosAlignDecoder.Init(); + } + + public void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress) + { + Init(inStream, outStream); + + Base.State state = new Base.State(); + state.Init(); + uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0; + + UInt64 nowPos64 = 0; + UInt64 outSize64 = (UInt64)outSize; + if (nowPos64 < outSize64) + { + if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0) + throw new DataErrorException(); + state.UpdateChar(); + byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0); + m_OutWindow.PutByte(b); + nowPos64++; + } + while (nowPos64 < outSize64) + { + // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64); + // while(nowPos64 < next) + { + uint posState = (uint)nowPos64 & m_PosStateMask; + if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) + { + byte b; + byte prevByte = m_OutWindow.GetByte(0); + if (!state.IsCharState()) + b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder, + (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0)); + else + b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte); + m_OutWindow.PutByte(b); + state.UpdateChar(); + nowPos64++; + } + else + { + uint len; + if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1) + { + if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0) + { + if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0) + { + state.UpdateShortRep(); + m_OutWindow.PutByte(m_OutWindow.GetByte(rep0)); + nowPos64++; + continue; + } + } + else + { + UInt32 distance; + if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0) + { + distance = rep1; + } + else + { + if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen; + state.UpdateRep(); + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState); + state.UpdateMatch(); + uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder); + if (posSlot >= Base.kStartPosModelIndex) + { + int numDirectBits = (int)((posSlot >> 1) - 1); + rep0 = ((2 | (posSlot & 1)) << numDirectBits); + if (posSlot < Base.kEndPosModelIndex) + rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders, + rep0 - posSlot - 1, m_RangeDecoder, numDirectBits); + else + { + rep0 += (m_RangeDecoder.DecodeDirectBits( + numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits); + rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder); + } + } + else + rep0 = posSlot; + } + if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck) + { + if (rep0 == 0xFFFFFFFF) + break; + throw new DataErrorException(); + } + m_OutWindow.CopyBlock(rep0, len); + nowPos64 += len; + } + } + } + m_OutWindow.Flush(); + m_OutWindow.ReleaseStream(); + m_RangeDecoder.ReleaseStream(); + } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 5) + throw new InvalidParamException(); + int lc = properties[0] % 9; + int remainder = properties[0] / 9; + int lp = remainder % 5; + int pb = remainder / 5; + if (pb > Base.kNumPosStatesBitsMax) + throw new InvalidParamException(); + UInt32 dictionarySize = 0; + for (int i = 0; i < 4; i++) + dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); + SetDictionarySize(dictionarySize); + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + } + + public bool Train(System.IO.Stream stream) + { + _solid = true; + return m_OutWindow.Train(stream); + } + + /* + public override bool CanRead { get { return true; }} + public override bool CanWrite { get { return true; }} + public override bool CanSeek { get { return true; }} + public override long Length { get { return 0; }} + public override long Position + { + get { return 0; } + set { } + } + public override void Flush() { } + public override int Read(byte[] buffer, int offset, int count) + { + return 0; + } + public override void Write(byte[] buffer, int offset, int count) + { + } + public override long Seek(long offset, System.IO.SeekOrigin origin) + { + return 0; + } + public override void SetLength(long value) {} + */ + } +} diff --git a/Unity Studio/7zip/Compress/LZMA/LzmaEncoder.cs b/Unity Studio/7zip/Compress/LZMA/LzmaEncoder.cs new file mode 100644 index 0000000..0237c51 --- /dev/null +++ b/Unity Studio/7zip/Compress/LZMA/LzmaEncoder.cs @@ -0,0 +1,1480 @@ +// LzmaEncoder.cs + +using System; + +namespace SevenZip.Compression.LZMA +{ + using RangeCoder; + + public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties + { + enum EMatchFinderType + { + BT2, + BT4, + }; + + const UInt32 kIfinityPrice = 0xFFFFFFF; + + static Byte[] g_FastPos = new Byte[1 << 11]; + + static Encoder() + { + const Byte kFastSlots = 22; + int c = 2; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++) + { + UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1)); + for (UInt32 j = 0; j < k; j++, c++) + g_FastPos[c] = slotFast; + } + } + + static UInt32 GetPosSlot(UInt32 pos) + { + if (pos < (1 << 11)) + return g_FastPos[pos]; + if (pos < (1 << 21)) + return (UInt32)(g_FastPos[pos >> 10] + 20); + return (UInt32)(g_FastPos[pos >> 20] + 40); + } + + static UInt32 GetPosSlot2(UInt32 pos) + { + if (pos < (1 << 17)) + return (UInt32)(g_FastPos[pos >> 6] + 12); + if (pos < (1 << 27)) + return (UInt32)(g_FastPos[pos >> 16] + 32); + return (UInt32)(g_FastPos[pos >> 26] + 52); + } + + Base.State _state = new Base.State(); + Byte _previousByte; + UInt32[] _repDistances = new UInt32[Base.kNumRepDistances]; + + void BaseInit() + { + _state.Init(); + _previousByte = 0; + for (UInt32 i = 0; i < Base.kNumRepDistances; i++) + _repDistances[i] = 0; + } + + const int kDefaultDictionaryLogSize = 22; + const UInt32 kNumFastBytesDefault = 0x20; + + class LiteralEncoder + { + public struct Encoder2 + { + BitEncoder[] m_Encoders; + + public void Create() { m_Encoders = new BitEncoder[0x300]; } + + public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); } + + public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol) + { + uint context = 1; + for (int i = 7; i >= 0; i--) + { + uint bit = (uint)((symbol >> i) & 1); + m_Encoders[context].Encode(rangeEncoder, bit); + context = (context << 1) | bit; + } + } + + public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) + { + uint context = 1; + bool same = true; + for (int i = 7; i >= 0; i--) + { + uint bit = (uint)((symbol >> i) & 1); + uint state = context; + if (same) + { + uint matchBit = (uint)((matchByte >> i) & 1); + state += ((1 + matchBit) << 8); + same = (matchBit == bit); + } + m_Encoders[state].Encode(rangeEncoder, bit); + context = (context << 1) | bit; + } + } + + public uint GetPrice(bool matchMode, byte matchByte, byte symbol) + { + uint price = 0; + uint context = 1; + int i = 7; + if (matchMode) + { + for (; i >= 0; i--) + { + uint matchBit = (uint)(matchByte >> i) & 1; + uint bit = (uint)(symbol >> i) & 1; + price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit); + context = (context << 1) | bit; + if (matchBit != bit) + { + i--; + break; + } + } + } + for (; i >= 0; i--) + { + uint bit = (uint)(symbol >> i) & 1; + price += m_Encoders[context].GetPrice(bit); + context = (context << 1) | bit; + } + return price; + } + } + + Encoder2[] m_Coders; + int m_NumPrevBits; + int m_NumPosBits; + uint m_PosMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits) + return; + m_NumPosBits = numPosBits; + m_PosMask = ((uint)1 << numPosBits) - 1; + m_NumPrevBits = numPrevBits; + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + m_Coders = new Encoder2[numStates]; + for (uint i = 0; i < numStates; i++) + m_Coders[i].Create(); + } + + public void Init() + { + uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits); + for (uint i = 0; i < numStates; i++) + m_Coders[i].Init(); + } + + public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte) + { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; } + } + + class LenEncoder + { + RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder(); + RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder(); + RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax]; + RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits); + + public LenEncoder() + { + for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++) + { + _lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits); + _midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits); + } + } + + public void Init(UInt32 numPosStates) + { + _choice.Init(); + _choice2.Init(); + for (UInt32 posState = 0; posState < numPosStates; posState++) + { + _lowCoder[posState].Init(); + _midCoder[posState].Init(); + } + _highCoder.Init(); + } + + public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + { + if (symbol < Base.kNumLowLenSymbols) + { + _choice.Encode(rangeEncoder, 0); + _lowCoder[posState].Encode(rangeEncoder, symbol); + } + else + { + symbol -= Base.kNumLowLenSymbols; + _choice.Encode(rangeEncoder, 1); + if (symbol < Base.kNumMidLenSymbols) + { + _choice2.Encode(rangeEncoder, 0); + _midCoder[posState].Encode(rangeEncoder, symbol); + } + else + { + _choice2.Encode(rangeEncoder, 1); + _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols); + } + } + } + + public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st) + { + UInt32 a0 = _choice.GetPrice0(); + UInt32 a1 = _choice.GetPrice1(); + UInt32 b0 = a1 + _choice2.GetPrice0(); + UInt32 b1 = a1 + _choice2.GetPrice1(); + UInt32 i = 0; + for (i = 0; i < Base.kNumLowLenSymbols; i++) + { + if (i >= numSymbols) + return; + prices[st + i] = a0 + _lowCoder[posState].GetPrice(i); + } + for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++) + { + if (i >= numSymbols) + return; + prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols); + } + for (; i < numSymbols; i++) + prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols); + } + }; + + const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; + + class LenPriceTableEncoder : LenEncoder + { + UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax]; + UInt32 _tableSize; + UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax]; + + public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; } + + public UInt32 GetPrice(UInt32 symbol, UInt32 posState) + { + return _prices[posState * Base.kNumLenSymbols + symbol]; + } + + void UpdateTable(UInt32 posState) + { + SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols); + _counters[posState] = _tableSize; + } + + public void UpdateTables(UInt32 numPosStates) + { + for (UInt32 posState = 0; posState < numPosStates; posState++) + UpdateTable(posState); + } + + public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState) + { + base.Encode(rangeEncoder, symbol, posState); + if (--_counters[posState] == 0) + UpdateTable(posState); + } + } + + const UInt32 kNumOpts = 1 << 12; + class Optimal + { + public Base.State State; + + public bool Prev1IsChar; + public bool Prev2; + + public UInt32 PosPrev2; + public UInt32 BackPrev2; + + public UInt32 Price; + public UInt32 PosPrev; + public UInt32 BackPrev; + + public UInt32 Backs0; + public UInt32 Backs1; + public UInt32 Backs2; + public UInt32 Backs3; + + public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; } + public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; } + public bool IsShortRep() { return (BackPrev == 0); } + }; + Optimal[] _optimum = new Optimal[kNumOpts]; + LZ.IMatchFinder _matchFinder = null; + RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder(); + + RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates]; + RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax]; + + RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates]; + + RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex]; + RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits); + + LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder(); + LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder(); + + LiteralEncoder _literalEncoder = new LiteralEncoder(); + + UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2]; + + UInt32 _numFastBytes = kNumFastBytesDefault; + UInt32 _longestMatchLength; + UInt32 _numDistancePairs; + + UInt32 _additionalOffset; + + UInt32 _optimumEndIndex; + UInt32 _optimumCurrentIndex; + + bool _longestMatchWasFound; + + UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)]; + UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits]; + UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize]; + UInt32 _alignPriceCount; + + UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2); + + int _posStateBits = 2; + UInt32 _posStateMask = (4 - 1); + int _numLiteralPosStateBits = 0; + int _numLiteralContextBits = 3; + + UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize); + UInt32 _dictionarySizePrev = 0xFFFFFFFF; + UInt32 _numFastBytesPrev = 0xFFFFFFFF; + + Int64 nowPos64; + bool _finished; + System.IO.Stream _inStream; + + EMatchFinderType _matchFinderType = EMatchFinderType.BT4; + bool _writeEndMark = false; + + bool _needReleaseMFStream; + + void Create() + { + if (_matchFinder == null) + { + LZ.BinTree bt = new LZ.BinTree(); + int numHashBytes = 4; + if (_matchFinderType == EMatchFinderType.BT2) + numHashBytes = 2; + bt.SetType(numHashBytes); + _matchFinder = bt; + } + _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits); + + if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes) + return; + _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1); + _dictionarySizePrev = _dictionarySize; + _numFastBytesPrev = _numFastBytes; + } + + public Encoder() + { + for (int i = 0; i < kNumOpts; i++) + _optimum[i] = new Optimal(); + for (int i = 0; i < Base.kNumLenToPosStates; i++) + _posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits); + } + + void SetWriteEndMarkerMode(bool writeEndMarker) + { + _writeEndMark = writeEndMarker; + } + + void Init() + { + BaseInit(); + _rangeEncoder.Init(); + + uint i; + for (i = 0; i < Base.kNumStates; i++) + { + for (uint j = 0; j <= _posStateMask; j++) + { + uint complexState = (i << Base.kNumPosStatesBitsMax) + j; + _isMatch[complexState].Init(); + _isRep0Long[complexState].Init(); + } + _isRep[i].Init(); + _isRepG0[i].Init(); + _isRepG1[i].Init(); + _isRepG2[i].Init(); + } + _literalEncoder.Init(); + for (i = 0; i < Base.kNumLenToPosStates; i++) + _posSlotEncoder[i].Init(); + for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++) + _posEncoders[i].Init(); + + _lenEncoder.Init((UInt32)1 << _posStateBits); + _repMatchLenEncoder.Init((UInt32)1 << _posStateBits); + + _posAlignEncoder.Init(); + + _longestMatchWasFound = false; + _optimumEndIndex = 0; + _optimumCurrentIndex = 0; + _additionalOffset = 0; + } + + void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs) + { + lenRes = 0; + numDistancePairs = _matchFinder.GetMatches(_matchDistances); + if (numDistancePairs > 0) + { + lenRes = _matchDistances[numDistancePairs - 2]; + if (lenRes == _numFastBytes) + lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1], + Base.kMatchMaxLen - lenRes); + } + _additionalOffset++; + } + + + void MovePos(UInt32 num) + { + if (num > 0) + { + _matchFinder.Skip(num); + _additionalOffset += num; + } + } + + UInt32 GetRepLen1Price(Base.State state, UInt32 posState) + { + return _isRepG0[state.Index].GetPrice0() + + _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0(); + } + + UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState) + { + UInt32 price; + if (repIndex == 0) + { + price = _isRepG0[state.Index].GetPrice0(); + price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + } + else + { + price = _isRepG0[state.Index].GetPrice1(); + if (repIndex == 1) + price += _isRepG1[state.Index].GetPrice0(); + else + { + price += _isRepG1[state.Index].GetPrice1(); + price += _isRepG2[state.Index].GetPrice(repIndex - 2); + } + } + return price; + } + + UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState) + { + UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState); + return price + GetPureRepPrice(repIndex, state, posState); + } + + UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) + { + UInt32 price; + UInt32 lenToPosState = Base.GetLenToPosState(len); + if (pos < Base.kNumFullDistances) + price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos]; + else + price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] + + _alignPrices[pos & Base.kAlignMask]; + return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState); + } + + UInt32 Backward(out UInt32 backRes, UInt32 cur) + { + _optimumEndIndex = cur; + UInt32 posMem = _optimum[cur].PosPrev; + UInt32 backMem = _optimum[cur].BackPrev; + do + { + if (_optimum[cur].Prev1IsChar) + { + _optimum[posMem].MakeAsChar(); + _optimum[posMem].PosPrev = posMem - 1; + if (_optimum[cur].Prev2) + { + _optimum[posMem - 1].Prev1IsChar = false; + _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2; + _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2; + } + } + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = _optimum[posPrev].BackPrev; + posMem = _optimum[posPrev].PosPrev; + + _optimum[posPrev].BackPrev = backCur; + _optimum[posPrev].PosPrev = cur; + cur = posPrev; + } + while (cur > 0); + backRes = _optimum[0].BackPrev; + _optimumCurrentIndex = _optimum[0].PosPrev; + return _optimumCurrentIndex; + } + + UInt32[] reps = new UInt32[Base.kNumRepDistances]; + UInt32[] repLens = new UInt32[Base.kNumRepDistances]; + + + UInt32 GetOptimum(UInt32 position, out UInt32 backRes) + { + if (_optimumEndIndex != _optimumCurrentIndex) + { + UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex; + backRes = _optimum[_optimumCurrentIndex].BackPrev; + _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev; + return lenRes; + } + _optimumCurrentIndex = _optimumEndIndex = 0; + + UInt32 lenMain, numDistancePairs; + if (!_longestMatchWasFound) + { + ReadMatchDistances(out lenMain, out numDistancePairs); + } + else + { + lenMain = _longestMatchLength; + numDistancePairs = _numDistancePairs; + _longestMatchWasFound = false; + } + + UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1; + if (numAvailableBytes < 2) + { + backRes = 0xFFFFFFFF; + return 1; + } + if (numAvailableBytes > Base.kMatchMaxLen) + numAvailableBytes = Base.kMatchMaxLen; + + UInt32 repMaxIndex = 0; + UInt32 i; + for (i = 0; i < Base.kNumRepDistances; i++) + { + reps[i] = _repDistances[i]; + repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen); + if (repLens[i] > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= _numFastBytes) + { + backRes = repMaxIndex; + UInt32 lenRes = repLens[repMaxIndex]; + MovePos(lenRes - 1); + return lenRes; + } + + if (lenMain >= _numFastBytes) + { + backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances; + MovePos(lenMain - 1); + return lenMain; + } + + Byte currentByte = _matchFinder.GetIndexByte(0 - 1); + Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1)); + + if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2) + { + backRes = (UInt32)0xFFFFFFFF; + return 1; + } + + _optimum[0].State = _state; + + UInt32 posState = (position & _posStateMask); + + _optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() + + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte); + _optimum[1].MakeAsChar(); + + UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1(); + + if (matchByte == currentByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState); + if (shortRepPrice < _optimum[1].Price) + { + _optimum[1].Price = shortRepPrice; + _optimum[1].MakeAsShortRep(); + } + } + + UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]); + + if(lenEnd < 2) + { + backRes = _optimum[1].BackPrev; + return 1; + } + + _optimum[1].PosPrev = 0; + + _optimum[0].Backs0 = reps[0]; + _optimum[0].Backs1 = reps[1]; + _optimum[0].Backs2 = reps[2]; + _optimum[0].Backs3 = reps[3]; + + UInt32 len = lenEnd; + do + _optimum[len--].Price = kIfinityPrice; + while (len >= 2); + + for (i = 0; i < Base.kNumRepDistances; i++) + { + UInt32 repLen = repLens[i]; + if (repLen < 2) + continue; + UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState); + do + { + UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); + Optimal optimum = _optimum[repLen]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = 0; + optimum.BackPrev = i; + optimum.Prev1IsChar = false; + } + } + while (--repLen >= 2); + } + + UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0(); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= lenMain) + { + UInt32 offs = 0; + while (len > _matchDistances[offs]) + offs += 2; + for (; ; len++) + { + UInt32 distance = _matchDistances[offs + 1]; + UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState); + Optimal optimum = _optimum[len]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = 0; + optimum.BackPrev = distance + Base.kNumRepDistances; + optimum.Prev1IsChar = false; + } + if (len == _matchDistances[offs]) + { + offs += 2; + if (offs == numDistancePairs) + break; + } + } + } + + UInt32 cur = 0; + + while (true) + { + cur++; + if (cur == lenEnd) + return Backward(out backRes, cur); + UInt32 newLen; + ReadMatchDistances(out newLen, out numDistancePairs); + if (newLen >= _numFastBytes) + { + _numDistancePairs = numDistancePairs; + _longestMatchLength = newLen; + _longestMatchWasFound = true; + return Backward(out backRes, cur); + } + position++; + UInt32 posPrev = _optimum[cur].PosPrev; + Base.State state; + if (_optimum[cur].Prev1IsChar) + { + posPrev--; + if (_optimum[cur].Prev2) + { + state = _optimum[_optimum[cur].PosPrev2].State; + if (_optimum[cur].BackPrev2 < Base.kNumRepDistances) + state.UpdateRep(); + else + state.UpdateMatch(); + } + else + state = _optimum[posPrev].State; + state.UpdateChar(); + } + else + state = _optimum[posPrev].State; + if (posPrev == cur - 1) + { + if (_optimum[cur].IsShortRep()) + state.UpdateShortRep(); + else + state.UpdateChar(); + } + else + { + UInt32 pos; + if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2) + { + posPrev = _optimum[cur].PosPrev2; + pos = _optimum[cur].BackPrev2; + state.UpdateRep(); + } + else + { + pos = _optimum[cur].BackPrev; + if (pos < Base.kNumRepDistances) + state.UpdateRep(); + else + state.UpdateMatch(); + } + Optimal opt = _optimum[posPrev]; + if (pos < Base.kNumRepDistances) + { + if (pos == 0) + { + reps[0] = opt.Backs0; + reps[1] = opt.Backs1; + reps[2] = opt.Backs2; + reps[3] = opt.Backs3; + } + else if (pos == 1) + { + reps[0] = opt.Backs1; + reps[1] = opt.Backs0; + reps[2] = opt.Backs2; + reps[3] = opt.Backs3; + } + else if (pos == 2) + { + reps[0] = opt.Backs2; + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs3; + } + else + { + reps[0] = opt.Backs3; + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs2; + } + } + else + { + reps[0] = (pos - Base.kNumRepDistances); + reps[1] = opt.Backs0; + reps[2] = opt.Backs1; + reps[3] = opt.Backs2; + } + } + _optimum[cur].State = state; + _optimum[cur].Backs0 = reps[0]; + _optimum[cur].Backs1 = reps[1]; + _optimum[cur].Backs2 = reps[2]; + _optimum[cur].Backs3 = reps[3]; + UInt32 curPrice = _optimum[cur].Price; + + currentByte = _matchFinder.GetIndexByte(0 - 1); + matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1)); + + posState = (position & _posStateMask); + + UInt32 curAnd1Price = curPrice + + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() + + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)). + GetPrice(!state.IsCharState(), matchByte, currentByte); + + Optimal nextOptimum = _optimum[cur + 1]; + + bool nextIsChar = false; + if (curAnd1Price < nextOptimum.Price) + { + nextOptimum.Price = curAnd1Price; + nextOptimum.PosPrev = cur; + nextOptimum.MakeAsChar(); + nextIsChar = true; + } + + matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1(); + repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1(); + + if (matchByte == currentByte && + !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState); + if (shortRepPrice <= nextOptimum.Price) + { + nextOptimum.Price = shortRepPrice; + nextOptimum.PosPrev = cur; + nextOptimum.MakeAsShortRep(); + nextIsChar = true; + } + } + + UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1; + numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull); + numAvailableBytes = numAvailableBytesFull; + + if (numAvailableBytes < 2) + continue; + if (numAvailableBytes > _numFastBytes) + numAvailableBytes = _numFastBytes; + if (!nextIsChar && matchByte != currentByte) + { + // try Literal + rep0 + UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateChar(); + UInt32 posStateNext = (position + 1) & _posStateMask; + UInt32 nextRepMatchPrice = curAnd1Price + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() + + _isRep[state2.Index].GetPrice1(); + { + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice( + 0, lenTest2, state2, posStateNext); + Optimal optimum = _optimum[offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = false; + } + } + } + } + + UInt32 startLen = 2; // speed optimization + + for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++) + { + UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes); + if (lenTest < 2) + continue; + UInt32 lenTestTemp = lenTest; + do + { + while (lenEnd < cur + lenTest) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); + Optimal optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur; + optimum.BackPrev = repIndex; + optimum.Prev1IsChar = false; + } + } + while(--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + // if (_maxMode) + if (lenTest < numAvailableBytesFull) + { + UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateRep(); + UInt32 posStateNext = (position + lenTest) & _posStateMask; + UInt32 curAndLenCharPrice = + repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() + + _literalEncoder.GetSubCoder(position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true, + _matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))), + _matchFinder.GetIndexByte((Int32)lenTest - 1)); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1(); + UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1(); + + // for(; lenTest2 >= 2; lenTest2--) + { + UInt32 offset = lenTest + 1 + lenTest2; + while(lenEnd < cur + offset) + _optimum[++lenEnd].Price = kIfinityPrice; + UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + Optimal optimum = _optimum[cur + offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + lenTest + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = true; + optimum.PosPrev2 = cur; + optimum.BackPrev2 = repIndex; + } + } + } + } + } + + if (newLen > numAvailableBytes) + { + newLen = numAvailableBytes; + for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ; + _matchDistances[numDistancePairs] = newLen; + numDistancePairs += 2; + } + if (newLen >= startLen) + { + normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0(); + while (lenEnd < cur + newLen) + _optimum[++lenEnd].Price = kIfinityPrice; + + UInt32 offs = 0; + while (startLen > _matchDistances[offs]) + offs += 2; + + for (UInt32 lenTest = startLen; ; lenTest++) + { + UInt32 curBack = _matchDistances[offs + 1]; + UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); + Optimal optimum = _optimum[cur + lenTest]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur; + optimum.BackPrev = curBack + Base.kNumRepDistances; + optimum.Prev1IsChar = false; + } + + if (lenTest == _matchDistances[offs]) + { + if (lenTest < numAvailableBytesFull) + { + UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); + UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t); + if (lenTest2 >= 2) + { + Base.State state2 = state; + state2.UpdateMatch(); + UInt32 posStateNext = (position + lenTest) & _posStateMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() + + _literalEncoder.GetSubCoder(position + lenTest, + _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)). + GetPrice(true, + _matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1), + _matchFinder.GetIndexByte((Int32)lenTest - 1)); + state2.UpdateChar(); + posStateNext = (position + lenTest + 1) & _posStateMask; + UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1(); + UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1(); + + UInt32 offset = lenTest + 1 + lenTest2; + while (lenEnd < cur + offset) + _optimum[++lenEnd].Price = kIfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); + optimum = _optimum[cur + offset]; + if (curAndLenPrice < optimum.Price) + { + optimum.Price = curAndLenPrice; + optimum.PosPrev = cur + lenTest + 1; + optimum.BackPrev = 0; + optimum.Prev1IsChar = true; + optimum.Prev2 = true; + optimum.PosPrev2 = cur; + optimum.BackPrev2 = curBack + Base.kNumRepDistances; + } + } + } + offs += 2; + if (offs == numDistancePairs) + break; + } + } + } + } + } + + bool ChangePair(UInt32 smallDist, UInt32 bigDist) + { + const int kDif = 7; + return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif)); + } + + void WriteEndMarker(UInt32 posState) + { + if (!_writeEndMark) + return; + + _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1); + _isRep[_state.Index].Encode(_rangeEncoder, 0); + _state.UpdateMatch(); + UInt32 len = Base.kMatchMinLen; + _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1; + UInt32 lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + int footerBits = 30; + UInt32 posReduced = (((UInt32)1) << footerBits) - 1; + _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); + _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); + } + + void Flush(UInt32 nowPos) + { + ReleaseMFStream(); + WriteEndMarker(nowPos & _posStateMask); + _rangeEncoder.FlushData(); + _rangeEncoder.FlushStream(); + } + + public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished) + { + inSize = 0; + outSize = 0; + finished = true; + + if (_inStream != null) + { + _matchFinder.SetStream(_inStream); + _matchFinder.Init(); + _needReleaseMFStream = true; + _inStream = null; + if (_trainSize > 0) + _matchFinder.Skip(_trainSize); + } + + if (_finished) + return; + _finished = true; + + + Int64 progressPosValuePrev = nowPos64; + if (nowPos64 == 0) + { + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + UInt32 len, numDistancePairs; // it's not used + ReadMatchDistances(out len, out numDistancePairs); + UInt32 posState = (UInt32)(nowPos64) & _posStateMask; + _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0); + _state.UpdateChar(); + Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); + _literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte); + _previousByte = curByte; + _additionalOffset--; + nowPos64++; + } + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + while (true) + { + UInt32 pos; + UInt32 len = GetOptimum((UInt32)nowPos64, out pos); + + UInt32 posState = ((UInt32)nowPos64) & _posStateMask; + UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState; + if (len == 1 && pos == 0xFFFFFFFF) + { + _isMatch[complexState].Encode(_rangeEncoder, 0); + Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset)); + LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte); + if (!_state.IsCharState()) + { + Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset)); + subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); + } + else + subCoder.Encode(_rangeEncoder, curByte); + _previousByte = curByte; + _state.UpdateChar(); + } + else + { + _isMatch[complexState].Encode(_rangeEncoder, 1); + if (pos < Base.kNumRepDistances) + { + _isRep[_state.Index].Encode(_rangeEncoder, 1); + if (pos == 0) + { + _isRepG0[_state.Index].Encode(_rangeEncoder, 0); + if (len == 1) + _isRep0Long[complexState].Encode(_rangeEncoder, 0); + else + _isRep0Long[complexState].Encode(_rangeEncoder, 1); + } + else + { + _isRepG0[_state.Index].Encode(_rangeEncoder, 1); + if (pos == 1) + _isRepG1[_state.Index].Encode(_rangeEncoder, 0); + else + { + _isRepG1[_state.Index].Encode(_rangeEncoder, 1); + _isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2); + } + } + if (len == 1) + _state.UpdateShortRep(); + else + { + _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + _state.UpdateRep(); + } + UInt32 distance = _repDistances[pos]; + if (pos != 0) + { + for (UInt32 i = pos; i >= 1; i--) + _repDistances[i] = _repDistances[i - 1]; + _repDistances[0] = distance; + } + } + else + { + _isRep[_state.Index].Encode(_rangeEncoder, 0); + _state.UpdateMatch(); + _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState); + pos -= Base.kNumRepDistances; + UInt32 posSlot = GetPosSlot(pos); + UInt32 lenToPosState = Base.GetLenToPosState(len); + _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); + + if (posSlot >= Base.kStartPosModelIndex) + { + int footerBits = (int)((posSlot >> 1) - 1); + UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - baseVal; + + if (posSlot < Base.kEndPosModelIndex) + RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders, + baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced); + else + { + _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits); + _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask); + _alignPriceCount++; + } + } + UInt32 distance = pos; + for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--) + _repDistances[i] = _repDistances[i - 1]; + _repDistances[0] = distance; + _matchPriceCount++; + } + _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset)); + } + _additionalOffset -= len; + nowPos64 += len; + if (_additionalOffset == 0) + { + // if (!_fastMode) + if (_matchPriceCount >= (1 << 7)) + FillDistancesPrices(); + if (_alignPriceCount >= Base.kAlignTableSize) + FillAlignPrices(); + inSize = nowPos64; + outSize = _rangeEncoder.GetProcessedSizeAdd(); + if (_matchFinder.GetNumAvailableBytes() == 0) + { + Flush((UInt32)nowPos64); + return; + } + + if (nowPos64 - progressPosValuePrev >= (1 << 12)) + { + _finished = false; + finished = false; + return; + } + } + } + } + + void ReleaseMFStream() + { + if (_matchFinder != null && _needReleaseMFStream) + { + _matchFinder.ReleaseStream(); + _needReleaseMFStream = false; + } + } + + void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); } + void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); } + + void ReleaseStreams() + { + ReleaseMFStream(); + ReleaseOutStream(); + } + + void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize) + { + _inStream = inStream; + _finished = false; + Create(); + SetOutStream(outStream); + Init(); + + // if (!_fastMode) + { + FillDistancesPrices(); + FillAlignPrices(); + } + + _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen); + _lenEncoder.UpdateTables((UInt32)1 << _posStateBits); + _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen); + _repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits); + + nowPos64 = 0; + } + + + public void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress) + { + _needReleaseMFStream = false; + try + { + SetStreams(inStream, outStream, inSize, outSize); + while (true) + { + Int64 processedInSize; + Int64 processedOutSize; + bool finished; + CodeOneBlock(out processedInSize, out processedOutSize, out finished); + if (finished) + return; + if (progress != null) + { + progress.SetProgress(processedInSize, processedOutSize); + } + } + } + finally + { + ReleaseStreams(); + } + } + + const int kPropSize = 5; + Byte[] properties = new Byte[kPropSize]; + + public void WriteCoderProperties(System.IO.Stream outStream) + { + properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits); + for (int i = 0; i < 4; i++) + properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF); + outStream.Write(properties, 0, kPropSize); + } + + UInt32[] tempPrices = new UInt32[Base.kNumFullDistances]; + UInt32 _matchPriceCount; + + void FillDistancesPrices() + { + for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot(i); + int footerBits = (int)((posSlot >> 1) - 1); + UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders, + baseVal - posSlot - 1, footerBits, i - baseVal); + } + + for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState]; + + UInt32 st = (lenToPosState << Base.kNumPosSlotBits); + for (posSlot = 0; posSlot < _distTableSize; posSlot++) + _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot); + for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++) + _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits); + + UInt32 st2 = lenToPosState * Base.kNumFullDistances; + UInt32 i; + for (i = 0; i < Base.kStartPosModelIndex; i++) + _distancesPrices[st2 + i] = _posSlotPrices[st + i]; + for (; i < Base.kNumFullDistances; i++) + _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i]; + } + _matchPriceCount = 0; + } + + void FillAlignPrices() + { + for (UInt32 i = 0; i < Base.kAlignTableSize; i++) + _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i); + _alignPriceCount = 0; + } + + + static string[] kMatchFinderIDs = + { + "BT2", + "BT4", + }; + + static int FindMatchFinder(string s) + { + for (int m = 0; m < kMatchFinderIDs.Length; m++) + if (s == kMatchFinderIDs[m]) + return m; + return -1; + } + + public void SetCoderProperties(CoderPropID[] propIDs, object[] properties) + { + for (UInt32 i = 0; i < properties.Length; i++) + { + object prop = properties[i]; + switch (propIDs[i]) + { + case CoderPropID.NumFastBytes: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 numFastBytes = (Int32)prop; + if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen) + throw new InvalidParamException(); + _numFastBytes = (UInt32)numFastBytes; + break; + } + case CoderPropID.Algorithm: + { + /* + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 maximize = (Int32)prop; + _fastMode = (maximize == 0); + _maxMode = (maximize >= 2); + */ + break; + } + case CoderPropID.MatchFinder: + { + if (!(prop is String)) + throw new InvalidParamException(); + EMatchFinderType matchFinderIndexPrev = _matchFinderType; + int m = FindMatchFinder(((string)prop).ToUpper()); + if (m < 0) + throw new InvalidParamException(); + _matchFinderType = (EMatchFinderType)m; + if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType) + { + _dictionarySizePrev = 0xFFFFFFFF; + _matchFinder = null; + } + break; + } + case CoderPropID.DictionarySize: + { + const int kDicLogSizeMaxCompress = 30; + if (!(prop is Int32)) + throw new InvalidParamException(); ; + Int32 dictionarySize = (Int32)prop; + if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) || + dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress)) + throw new InvalidParamException(); + _dictionarySize = (UInt32)dictionarySize; + int dicLogSize; + for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++) + if (dictionarySize <= ((UInt32)(1) << dicLogSize)) + break; + _distTableSize = (UInt32)dicLogSize * 2; + break; + } + case CoderPropID.PosStateBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax) + throw new InvalidParamException(); + _posStateBits = (int)v; + _posStateMask = (((UInt32)1) << (int)_posStateBits) - 1; + break; + } + case CoderPropID.LitPosBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax) + throw new InvalidParamException(); + _numLiteralPosStateBits = (int)v; + break; + } + case CoderPropID.LitContextBits: + { + if (!(prop is Int32)) + throw new InvalidParamException(); + Int32 v = (Int32)prop; + if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax) + throw new InvalidParamException(); ; + _numLiteralContextBits = (int)v; + break; + } + case CoderPropID.EndMarker: + { + if (!(prop is Boolean)) + throw new InvalidParamException(); + SetWriteEndMarkerMode((Boolean)prop); + break; + } + default: + throw new InvalidParamException(); + } + } + } + + uint _trainSize = 0; + public void SetTrainSize(uint trainSize) + { + _trainSize = trainSize; + } + + } +} diff --git a/Unity Studio/7zip/Compress/RangeCoder/RangeCoder.cs b/Unity Studio/7zip/Compress/RangeCoder/RangeCoder.cs new file mode 100644 index 0000000..949c6bb --- /dev/null +++ b/Unity Studio/7zip/Compress/RangeCoder/RangeCoder.cs @@ -0,0 +1,234 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + class Encoder + { + public const uint kTopValue = (1 << 24); + + System.IO.Stream Stream; + + public UInt64 Low; + public uint Range; + uint _cacheSize; + byte _cache; + + long StartPosition; + + public void SetStream(System.IO.Stream stream) + { + Stream = stream; + } + + public void ReleaseStream() + { + Stream = null; + } + + public void Init() + { + StartPosition = Stream.Position; + + Low = 0; + Range = 0xFFFFFFFF; + _cacheSize = 1; + _cache = 0; + } + + public void FlushData() + { + for (int i = 0; i < 5; i++) + ShiftLow(); + } + + public void FlushStream() + { + Stream.Flush(); + } + + public void CloseStream() + { + Stream.Close(); + } + + public void Encode(uint start, uint size, uint total) + { + Low += start * (Range /= total); + Range *= size; + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + public void ShiftLow() + { + if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1) + { + byte temp = _cache; + do + { + Stream.WriteByte((byte)(temp + (Low >> 32))); + temp = 0xFF; + } + while (--_cacheSize != 0); + _cache = (byte)(((uint)Low) >> 24); + } + _cacheSize++; + Low = ((uint)Low) << 8; + } + + public void EncodeDirectBits(uint v, int numTotalBits) + { + for (int i = numTotalBits - 1; i >= 0; i--) + { + Range >>= 1; + if (((v >> i) & 1) == 1) + Low += Range; + if (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + } + + public void EncodeBit(uint size0, int numTotalBits, uint symbol) + { + uint newBound = (Range >> numTotalBits) * size0; + if (symbol == 0) + Range = newBound; + else + { + Low += newBound; + Range -= newBound; + } + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + public long GetProcessedSizeAdd() + { + return _cacheSize + + Stream.Position - StartPosition + 4; + // (long)Stream.GetProcessedSize(); + } + } + + class Decoder + { + public const uint kTopValue = (1 << 24); + public uint Range; + public uint Code; + // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16); + public System.IO.Stream Stream; + + public void Init(System.IO.Stream stream) + { + // Stream.Init(stream); + Stream = stream; + + Code = 0; + Range = 0xFFFFFFFF; + for (int i = 0; i < 5; i++) + Code = (Code << 8) | (byte)Stream.ReadByte(); + } + + public void ReleaseStream() + { + // Stream.ReleaseStream(); + Stream = null; + } + + public void CloseStream() + { + Stream.Close(); + } + + public void Normalize() + { + while (Range < kTopValue) + { + Code = (Code << 8) | (byte)Stream.ReadByte(); + Range <<= 8; + } + } + + public void Normalize2() + { + if (Range < kTopValue) + { + Code = (Code << 8) | (byte)Stream.ReadByte(); + Range <<= 8; + } + } + + public uint GetThreshold(uint total) + { + return Code / (Range /= total); + } + + public void Decode(uint start, uint size, uint total) + { + Code -= start * Range; + Range *= size; + Normalize(); + } + + public uint DecodeDirectBits(int numTotalBits) + { + uint range = Range; + uint code = Code; + uint result = 0; + for (int i = numTotalBits; i > 0; i--) + { + range >>= 1; + /* + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + */ + uint t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < kTopValue) + { + code = (code << 8) | (byte)Stream.ReadByte(); + range <<= 8; + } + } + Range = range; + Code = code; + return result; + } + + public uint DecodeBit(uint size0, int numTotalBits) + { + uint newBound = (Range >> numTotalBits) * size0; + uint symbol; + if (Code < newBound) + { + symbol = 0; + Range = newBound; + } + else + { + symbol = 1; + Code -= newBound; + Range -= newBound; + } + Normalize(); + return symbol; + } + + // ulong GetProcessedSize() {return Stream.GetProcessedSize(); } + } +} diff --git a/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBit.cs b/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBit.cs new file mode 100644 index 0000000..4f0346d --- /dev/null +++ b/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBit.cs @@ -0,0 +1,117 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + struct BitEncoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + const int kNumMoveBits = 5; + const int kNumMoveReducingBits = 2; + public const int kNumBitPriceShiftBits = 6; + + uint Prob; + + public void Init() { Prob = kBitModelTotal >> 1; } + + public void UpdateModel(uint symbol) + { + if (symbol == 0) + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + else + Prob -= (Prob) >> kNumMoveBits; + } + + public void Encode(Encoder encoder, uint symbol) + { + // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol); + // UpdateModel(symbol); + uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob; + if (symbol == 0) + { + encoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + } + else + { + encoder.Low += newBound; + encoder.Range -= newBound; + Prob -= (Prob) >> kNumMoveBits; + } + if (encoder.Range < Encoder.kTopValue) + { + encoder.Range <<= 8; + encoder.ShiftLow(); + } + } + + private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits]; + + static BitEncoder() + { + const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits); + for (int i = kNumBits - 1; i >= 0; i--) + { + UInt32 start = (UInt32)1 << (kNumBits - i - 1); + UInt32 end = (UInt32)1 << (kNumBits - i); + for (UInt32 j = start; j < end; j++) + ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) + + (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1)); + } + } + + public uint GetPrice(uint symbol) + { + return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; + } + public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; } + public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; } + } + + struct BitDecoder + { + public const int kNumBitModelTotalBits = 11; + public const uint kBitModelTotal = (1 << kNumBitModelTotalBits); + const int kNumMoveBits = 5; + + uint Prob; + + public void UpdateModel(int numMoveBits, uint symbol) + { + if (symbol == 0) + Prob += (kBitModelTotal - Prob) >> numMoveBits; + else + Prob -= (Prob) >> numMoveBits; + } + + public void Init() { Prob = kBitModelTotal >> 1; } + + public uint Decode(RangeCoder.Decoder rangeDecoder) + { + uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob; + if (rangeDecoder.Code < newBound) + { + rangeDecoder.Range = newBound; + Prob += (kBitModelTotal - Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 0; + } + else + { + rangeDecoder.Range -= newBound; + rangeDecoder.Code -= newBound; + Prob -= (Prob) >> kNumMoveBits; + if (rangeDecoder.Range < Decoder.kTopValue) + { + rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte(); + rangeDecoder.Range <<= 8; + } + return 1; + } + } + } +} diff --git a/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs new file mode 100644 index 0000000..4b4506f --- /dev/null +++ b/Unity Studio/7zip/Compress/RangeCoder/RangeCoderBitTree.cs @@ -0,0 +1,157 @@ +using System; + +namespace SevenZip.Compression.RangeCoder +{ + struct BitTreeEncoder + { + BitEncoder[] Models; + int NumBitLevels; + + public BitTreeEncoder(int numBitLevels) + { + NumBitLevels = numBitLevels; + Models = new BitEncoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + + public void Encode(Encoder rangeEncoder, UInt32 symbol) + { + UInt32 m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; ) + { + bitIndex--; + UInt32 bit = (symbol >> bitIndex) & 1; + Models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + } + } + + public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol) + { + UInt32 m = 1; + for (UInt32 i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; + } + } + + public UInt32 GetPrice(UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; ) + { + bitIndex--; + UInt32 bit = (symbol >> bitIndex) & 1; + price += Models[m].GetPrice(bit); + m = (m << 1) + bit; + } + return price; + } + + public UInt32 ReverseGetPrice(UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int i = NumBitLevels; i > 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[m].GetPrice(bit); + m = (m << 1) | bit; + } + return price; + } + + public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex, + int NumBitLevels, UInt32 symbol) + { + UInt32 price = 0; + UInt32 m = 1; + for (int i = NumBitLevels; i > 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[startIndex + m].GetPrice(bit); + m = (m << 1) | bit; + } + return price; + } + + public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex, + Encoder rangeEncoder, int NumBitLevels, UInt32 symbol) + { + UInt32 m = 1; + for (int i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[startIndex + m].Encode(rangeEncoder, bit); + m = (m << 1) | bit; + symbol >>= 1; + } + } + } + + struct BitTreeDecoder + { + BitDecoder[] Models; + int NumBitLevels; + + public BitTreeDecoder(int numBitLevels) + { + NumBitLevels = numBitLevels; + Models = new BitDecoder[1 << numBitLevels]; + } + + public void Init() + { + for (uint i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + + public uint Decode(RangeCoder.Decoder rangeDecoder) + { + uint m = 1; + for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--) + m = (m << 1) + Models[m].Decode(rangeDecoder); + return m - ((uint)1 << NumBitLevels); + } + + public uint ReverseDecode(RangeCoder.Decoder rangeDecoder) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + uint bit = Models[m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + + public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex, + RangeCoder.Decoder rangeDecoder, int NumBitLevels) + { + uint m = 1; + uint symbol = 0; + for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + uint bit = Models[startIndex + m].Decode(rangeDecoder); + m <<= 1; + m += bit; + symbol |= (bit << bitIndex); + } + return symbol; + } + } +} diff --git a/Unity Studio/7zip/ICoder.cs b/Unity Studio/7zip/ICoder.cs new file mode 100644 index 0000000..c8b95c8 --- /dev/null +++ b/Unity Studio/7zip/ICoder.cs @@ -0,0 +1,157 @@ +// ICoder.h + +using System; + +namespace SevenZip +{ + /// + /// The exception that is thrown when an error in input stream occurs during decoding. + /// + class DataErrorException : ApplicationException + { + public DataErrorException(): base("Data Error") { } + } + + /// + /// The exception that is thrown when the value of an argument is outside the allowable range. + /// + class InvalidParamException : ApplicationException + { + public InvalidParamException(): base("Invalid Parameter") { } + } + + public interface ICodeProgress + { + /// + /// Callback progress. + /// + /// + /// input size. -1 if unknown. + /// + /// + /// output size. -1 if unknown. + /// + void SetProgress(Int64 inSize, Int64 outSize); + }; + + public interface ICoder + { + /// + /// Codes streams. + /// + /// + /// input Stream. + /// + /// + /// output Stream. + /// + /// + /// input Size. -1 if unknown. + /// + /// + /// output Size. -1 if unknown. + /// + /// + /// callback progress reference. + /// + /// + /// if input stream is not valid + /// + void Code(System.IO.Stream inStream, System.IO.Stream outStream, + Int64 inSize, Int64 outSize, ICodeProgress progress); + }; + + /* + public interface ICoder2 + { + void Code(ISequentialInStream []inStreams, + const UInt64 []inSizes, + ISequentialOutStream []outStreams, + UInt64 []outSizes, + ICodeProgress progress); + }; + */ + + /// + /// Provides the fields that represent properties idenitifiers for compressing. + /// + public enum CoderPropID + { + /// + /// Specifies default property. + /// + DefaultProp = 0, + /// + /// Specifies size of dictionary. + /// + DictionarySize, + /// + /// Specifies size of memory for PPM*. + /// + UsedMemorySize, + /// + /// Specifies order for PPM methods. + /// + Order, + /// + /// Specifies Block Size. + /// + BlockSize, + /// + /// Specifies number of postion state bits for LZMA (0 <= x <= 4). + /// + PosStateBits, + /// + /// Specifies number of literal context bits for LZMA (0 <= x <= 8). + /// + LitContextBits, + /// + /// Specifies number of literal position bits for LZMA (0 <= x <= 4). + /// + LitPosBits, + /// + /// Specifies number of fast bytes for LZ*. + /// + NumFastBytes, + /// + /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B". + /// + MatchFinder, + /// + /// Specifies the number of match finder cyckes. + /// + MatchFinderCycles, + /// + /// Specifies number of passes. + /// + NumPasses, + /// + /// Specifies number of algorithm. + /// + Algorithm, + /// + /// Specifies the number of threads. + /// + NumThreads, + /// + /// Specifies mode with end marker. + /// + EndMarker + }; + + + public interface ISetCoderProperties + { + void SetCoderProperties(CoderPropID[] propIDs, object[] properties); + }; + + public interface IWriteCoderProperties + { + void WriteCoderProperties(System.IO.Stream outStream); + } + + public interface ISetDecoderProperties + { + void SetDecoderProperties(byte[] properties); + } +} diff --git a/Unity Studio/7zip/SevenZipHelper.cs b/Unity Studio/7zip/SevenZipHelper.cs new file mode 100644 index 0000000..f70fe42 --- /dev/null +++ b/Unity Studio/7zip/SevenZipHelper.cs @@ -0,0 +1,126 @@ +using System; +using System.IO; + + +namespace SevenZip.Compression.LZMA +{ + public static class SevenZipHelper + { + + static int dictionary = 1 << 23; + + // static Int32 posStateBits = 2; + // static Int32 litContextBits = 3; // for normal files + // UInt32 litContextBits = 0; // for 32-bit data + // static Int32 litPosBits = 0; + // UInt32 litPosBits = 2; // for 32-bit data + // static Int32 algorithm = 2; + // static Int32 numFastBytes = 128; + + static bool eos = false; + + + + + + static CoderPropID[] propIDs = + { + CoderPropID.DictionarySize, + CoderPropID.PosStateBits, + CoderPropID.LitContextBits, + CoderPropID.LitPosBits, + CoderPropID.Algorithm, + CoderPropID.NumFastBytes, + CoderPropID.MatchFinder, + CoderPropID.EndMarker + }; + + // these are the default properties, keeping it simple for now: + static object[] properties = + { + (Int32)(dictionary), + (Int32)(2), + (Int32)(3), + (Int32)(0), + (Int32)(2), + (Int32)(128), + "bt4", + eos + }; + + + public static byte[] Compress(byte[] inputBytes) + { + + MemoryStream inStream = new MemoryStream(inputBytes); + MemoryStream outStream = new MemoryStream(); + SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder(); + encoder.SetCoderProperties(propIDs, properties); + encoder.WriteCoderProperties(outStream); + long fileSize = inStream.Length; + for (int i = 0; i < 8; i++) + outStream.WriteByte((Byte)(fileSize >> (8 * i))); + encoder.Code(inStream, outStream, -1, -1, null); + return outStream.ToArray(); + } + + public static byte[] Decompress(byte[] inputBytes) + { + MemoryStream newInStream = new MemoryStream(inputBytes); + + SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder(); + + newInStream.Seek(0, 0); + MemoryStream newOutStream = new MemoryStream(); + + byte[] properties2 = new byte[5]; + if (newInStream.Read(properties2, 0, 5) != 5) + throw (new Exception("input .lzma is too short")); + long outSize = 0; + for (int i = 0; i < 8; i++) + { + int v = newInStream.ReadByte(); + if (v < 0) + throw (new Exception("Can't Read 1")); + outSize |= ((long)(byte)v) << (8 * i); + } + decoder.SetDecoderProperties(properties2); + + long compressedSize = newInStream.Length - newInStream.Position; + decoder.Code(newInStream, newOutStream, compressedSize, outSize, null); + + byte[] b = newOutStream.ToArray(); + + return b; + } + + + public static MemoryStream StreamDecompress(MemoryStream newInStream) + { + SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder(); + + newInStream.Seek(0, 0); + MemoryStream newOutStream = new MemoryStream(); + + byte[] properties2 = new byte[5]; + if (newInStream.Read(properties2, 0, 5) != 5) + throw (new Exception("input .lzma is too short")); + long outSize = 0; + for (int i = 0; i < 8; i++) + { + int v = newInStream.ReadByte(); + if (v < 0) + throw (new Exception("Can't Read 1")); + outSize |= ((long)(byte)v) << (8 * i); + } + decoder.SetDecoderProperties(properties2); + + long compressedSize = newInStream.Length - newInStream.Position; + decoder.Code(newInStream, newOutStream, compressedSize, outSize, null); + + newOutStream.Position = 0; + return newOutStream; + } + + } +} diff --git a/Unity Studio/AboutBox.Designer.cs b/Unity Studio/AboutBox.Designer.cs new file mode 100644 index 0000000..66a2df4 --- /dev/null +++ b/Unity Studio/AboutBox.Designer.cs @@ -0,0 +1,188 @@ +namespace Unity_Studio +{ + partial class AboutBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox)); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.labelProductName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.labelCopyright = new System.Windows.Forms.Label(); + this.labelCompanyName = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.okButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel + // + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 51.12107F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 48.87893F)); + this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); + this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); + this.tableLayoutPanel.Controls.Add(this.labelVersion, 1, 1); + this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 2); + this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 1, 3); + this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 1, 4); + this.tableLayoutPanel.Controls.Add(this.okButton, 1, 5); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 6; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.Size = new System.Drawing.Size(446, 264); + this.tableLayoutPanel.TabIndex = 0; + // + // logoPictureBox + // + this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Location = new System.Drawing.Point(3, 3); + this.logoPictureBox.Name = "logoPictureBox"; + this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 6); + this.logoPictureBox.Size = new System.Drawing.Size(221, 258); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.TabIndex = 12; + this.logoPictureBox.TabStop = false; + // + // labelProductName + // + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.Location = new System.Drawing.Point(233, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelProductName.Name = "labelProductName"; + this.labelProductName.Size = new System.Drawing.Size(210, 17); + this.labelProductName.TabIndex = 19; + this.labelProductName.Text = "Product Name"; + this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelVersion + // + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.Location = new System.Drawing.Point(233, 26); + this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(210, 17); + this.labelVersion.TabIndex = 0; + this.labelVersion.Text = "Version"; + this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCopyright + // + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.Location = new System.Drawing.Point(233, 52); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.Size = new System.Drawing.Size(210, 17); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.Text = "Copyright"; + this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCompanyName + // + this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCompanyName.Location = new System.Drawing.Point(233, 78); + this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCompanyName.Name = "labelCompanyName"; + this.labelCompanyName.Size = new System.Drawing.Size(210, 17); + this.labelCompanyName.TabIndex = 22; + this.labelCompanyName.Text = "Company Name"; + this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // textBoxDescription + // + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.Location = new System.Drawing.Point(233, 107); + this.textBoxDescription.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxDescription.Size = new System.Drawing.Size(210, 126); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.Location = new System.Drawing.Point(368, 239); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 22); + this.okButton.TabIndex = 24; + this.okButton.Text = "&OK"; + this.okButton.Click += new System.EventHandler(this.okButton_Click); + // + // AboutBox + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(464, 282); + this.Controls.Add(this.tableLayoutPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Unity Studio"; + this.TopMost = true; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.Label labelProductName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.Label labelCopyright; + private System.Windows.Forms.Label labelCompanyName; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Button okButton; + } +} diff --git a/Unity Studio/AboutBox.cs b/Unity Studio/AboutBox.cs new file mode 100644 index 0000000..4161b78 --- /dev/null +++ b/Unity Studio/AboutBox.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace Unity_Studio +{ + partial class AboutBox : Form + { + public AboutBox() + { + InitializeComponent(); + this.Text = String.Format("About {0}", AssemblyTitle); + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelCompanyName.Text = AssemblyCompany; + this.textBoxDescription.Text = AssemblyDescription; + } + + #region Assembly Attribute Accessors + + public string AssemblyTitle + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != "") + { + return titleAttribute.Title; + } + } + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + } + } + + public string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyDescriptionAttribute)attributes[0]).Description; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public string AssemblyCompany + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + + private void okButton_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/Unity Studio/AboutBox.resx b/Unity Studio/AboutBox.resx new file mode 100644 index 0000000..76cc9af --- /dev/null +++ b/Unity Studio/AboutBox.resx @@ -0,0 +1,603 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + + + \ No newline at end of file diff --git a/Unity Studio/AboutBox1.Designer.cs b/Unity Studio/AboutBox1.Designer.cs new file mode 100644 index 0000000..a8a11b8 --- /dev/null +++ b/Unity Studio/AboutBox1.Designer.cs @@ -0,0 +1,186 @@ +namespace Unity_Studio +{ + partial class AboutBox1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox1)); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.labelProductName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.labelCopyright = new System.Windows.Forms.Label(); + this.labelCompanyName = new System.Windows.Forms.Label(); + this.textBoxDescription = new System.Windows.Forms.TextBox(); + this.okButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel + // + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 33F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 67F)); + this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); + this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); + this.tableLayoutPanel.Controls.Add(this.labelVersion, 1, 1); + this.tableLayoutPanel.Controls.Add(this.labelCopyright, 1, 2); + this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 1, 3); + this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 1, 4); + this.tableLayoutPanel.Controls.Add(this.okButton, 1, 5); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 6; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 10F)); + this.tableLayoutPanel.Size = new System.Drawing.Size(417, 265); + this.tableLayoutPanel.TabIndex = 0; + // + // logoPictureBox + // + this.logoPictureBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Location = new System.Drawing.Point(3, 3); + this.logoPictureBox.Name = "logoPictureBox"; + this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 6); + this.logoPictureBox.Size = new System.Drawing.Size(131, 259); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.TabIndex = 12; + this.logoPictureBox.TabStop = false; + // + // labelProductName + // + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.Location = new System.Drawing.Point(143, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelProductName.Name = "labelProductName"; + this.labelProductName.Size = new System.Drawing.Size(271, 17); + this.labelProductName.TabIndex = 19; + this.labelProductName.Text = "Product Name"; + this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelVersion + // + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.Location = new System.Drawing.Point(143, 26); + this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelVersion.MaximumSize = new System.Drawing.Size(0, 17); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(271, 17); + this.labelVersion.TabIndex = 0; + this.labelVersion.Text = "Version"; + this.labelVersion.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCopyright + // + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.Location = new System.Drawing.Point(143, 52); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.Size = new System.Drawing.Size(271, 17); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.Text = "Copyright"; + this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // labelCompanyName + // + this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCompanyName.Location = new System.Drawing.Point(143, 78); + this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17); + this.labelCompanyName.Name = "labelCompanyName"; + this.labelCompanyName.Size = new System.Drawing.Size(271, 17); + this.labelCompanyName.TabIndex = 22; + this.labelCompanyName.Text = "Company Name"; + this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // textBoxDescription + // + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.Location = new System.Drawing.Point(143, 107); + this.textBoxDescription.Margin = new System.Windows.Forms.Padding(6, 3, 3, 3); + this.textBoxDescription.Multiline = true; + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textBoxDescription.Size = new System.Drawing.Size(271, 126); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // okButton + // + this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.Location = new System.Drawing.Point(339, 239); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 24; + this.okButton.Text = "&OK"; + // + // AboutBox1 + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(435, 283); + this.Controls.Add(this.tableLayoutPanel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox1"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "AboutBox1"; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.Label labelProductName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.Label labelCopyright; + private System.Windows.Forms.Label labelCompanyName; + private System.Windows.Forms.TextBox textBoxDescription; + private System.Windows.Forms.Button okButton; + } +} diff --git a/Unity Studio/AboutBox1.cs b/Unity Studio/AboutBox1.cs new file mode 100644 index 0000000..e5b1cac --- /dev/null +++ b/Unity Studio/AboutBox1.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Windows.Forms; + +namespace Unity_Studio +{ + partial class AboutBox1 : Form + { + public AboutBox1() + { + InitializeComponent(); + this.Text = String.Format("About {0}", AssemblyTitle); + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelCompanyName.Text = AssemblyCompany; + this.textBoxDescription.Text = AssemblyDescription; + } + + #region Assembly Attribute Accessors + + public string AssemblyTitle + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); + if (attributes.Length > 0) + { + AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; + if (titleAttribute.Title != "") + { + return titleAttribute.Title; + } + } + return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); + } + } + + public string AssemblyVersion + { + get + { + return Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyDescriptionAttribute)attributes[0]).Description; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; + } + } + + public string AssemblyCompany + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyCompanyAttribute)attributes[0]).Company; + } + } + #endregion + } +} diff --git a/Unity Studio/AboutBox1.resx b/Unity Studio/AboutBox1.resx new file mode 100644 index 0000000..09e0c92 --- /dev/null +++ b/Unity Studio/AboutBox1.resx @@ -0,0 +1,607 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAHgAAAEGCAIAAAAhWcaAAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAcQNJREFUeF7tfQdc + lFfa/ez/K/tlExUVmN7ovQ1D74Kg2BWs2CvYEVEEG0VALHTpAip2xd57jzHGmF5MsokxdbPV/XY13//c + 9xleX2YAMTGJZnfy/PiNiATOnDn3POXe+xtZpew3v/mNCP/9v9/85j9+g4+i/xDhyf/7z//HnvzXb0T/ + yf7InuOvfiNij/8TiR6KRN+L/u/h/7EnDwTPv2fP2Sf/T/T9599///r3D28/nDFsRp8+fezt7f8f98D/ + zuiBb8l+hl/3A0DLK+WKKoWyWqmsUapqVeqNanW9WrNJo23SardptTu1VnusrA9YWx+2tj5qbXPCxuYU + Fydt8Nz6GPd5/G2ztdUuK6vtVlZbray2WFk1WllttLKqs9LkalSjVXJ3eW5u7htvvPHnP//5r3/96/37 + 9//3f//3H//4xz//+c8HDx48fPjwe+7xf7/ehwgoy6sMQKtqVAzoWrWmTqOp12gbtNpGrdVmDrhtVlY7 + raz3Wlvvs7Y+aG19xJpBzEcL1ta7ra12tMJaW6vV1mjV2WrlcKXMSVZSUvLJJ5/8C8LNgCY6M5RrWlCu + 02g3alnUa60aOHpusmKIN7UgvodDHEQ+xIGOANZ4AfDJvdZ4SYS8ZlhXa7VVWvVStXKQUmYl27x58x// + +Md/KbhFQFlRbQAaXFbXMTo/QrneyooPHnEQHPpAHOcRB8oIQE9YQ0bwBS0aYsC6Uqut0KrmqxSRiqSk + pBMnTvBw//3vf/91i4lIUalQVilV1RydazjR2GgA+hHERnAbIQ5d3sWpSjOHMgVhjb/CmwDvho1WBqwr + tNoNWm2JVjVFJfeRr1q16t133xXCDeE20u5fh26LFGUKRQXDmqFcq0Fo67QsNmrbBtqU4CQp4PgOK2i0 + AXGADugh2bQ8GmFdrtWWaTWZGuUwpcxW1tTU9Ic//AFw/+Uvf/nb3/4Gdv/61kmRYo1CuV6pKlWpylXq + SrWmWqOpYVgzzyAMIakfS3BICiEOYeGXR7we9QJel2m1pRy156oUYYrFixffuHEDcP/pT39qz5Y819QW + KXIVijyFMk+pWqNSF6o1pRpNuUYLMa1ibgH+rFOIQ0xMFRz2A5ICoKEhvBVpaI11iVZbrNXkaZQjmSdp + bGz85ptvvvvuO4JbKNzPuwUUKbIVyhylapVKladSr1YjNGs12vWMa0xMgTgMA2xDbec4bgQ3RAPSAROC + ANb88lhnxb4t9Bq8xv+oSKsp1KjmqRThiiVLlty+ffvbb7/llcR0kXweqS1SZCqUWUpVjgpYq3PV6jy1 + Jl+jKeACiBdyb3AB4p3iuBBukm/ATSFIZ1phXajVrNeoc9TKOKXMTrZ79+6vv/66TSV5TqktUq5QqjJV + qiwVcgr8nppVGuRyDGsebkK8iGMfONh5gpvCDUYT1rwVEfAapMb/SLNGo0pUyf3lq1ev/uyzz6Ak5Emw + SD7X1OaAXqlSZ6pZZKk1ORoWBHceB/fqFoKv0QALI0l5DMGNtJvYTcFjXdOiIRDr9Qas1UvUiliFVCa9 + dOnSV199ZUrt5y5xFwFlHmhNlsYQ2QK4TQm+joMbBG9R8CeDm/Id0hDe9pFe81hz2oUiicxRtm3bti++ + +OJ5pzYD+hGdeaDpCcHdHsGhJ8VPoidG7AbKIDVhTbYPLxuwxsIIXuPdQ1hDRvzk69evv3fvnpDapl77 + GV8hRYqpClU6w/oRnY3gxh87hru1fD+e3aicUPEEKFOYYr3uEdbqRWpFFDPab7311pdffskbEr4E+FzI + iCggIEBqJ5UHyxXDFKqZqo7gFuqJkXzz7O6MmAipTaVBfDTFGgsjmZ8CDRYP5WClVCk9f/48qA1DAq9t + tEI+425E1NDQUFRUlJKSMmLECD8/P7mnXBmrVE1WaZa26LURwTtgN2k30mvAjSUO1tso32kvpQTKFJTO + 8BoiwNog2fayffv2ff7558+djIi2b9++c+fOXdwD7rWgoGD69OlRUVFyN7myjxKlH82KthA3hbuFfcyZ + kPXujBEkC0hKgsATI702wnoy6yEggYTzwwpJMkIp+zNeihLt37//wIEDBw8ePHToEJ7gAco0NzeD5jNn + zmSIe8lRRFbNMlEVXklMrfcaY9/dKWoT4o/FeiYr+5WVlX366aeQEXIjqEaZSvYztTyKUBQ+efLkKe6B + J8ePHz927NiRI0cId4AOjk+cOFGmkSlCFaqxJpLSgXCTkoDaXNnkMUk8L9yENZVVSUOQNLaYEIMVmaeS + B8rXrFmDZk3Hkv3sYC26zD2uXLmCj8gOLly4cO7cuTNnzgB3vAY86DCzqEIMGDCAEXyYUr1A4FKMXKAw + q/wB1CYxwccOsVYvVOOFz87O/vjjj4WSLUwgn6nlUfTaa6/dunULH2/evPnqq6++8sor169fv3r1KnAH + 6FjlATqYDsSPHj0Kmq9bt27s2LEyZ5myvxIVzlYJTnuOW0ht0/qUUQGWqE3BY13Kqk6teL1ao05TKyIU + K1as+Oijj+7evQvnxyeQvMt+drAWocHxXsvj7bfffvPNN9GrBvTAHQXil19+GaCD6UD87NmzoDm0BYhX + V1djzZTZy5hFmcPBDV53RrV5Q9JBvbs9rJHI8EsungDrdDW6YkuXLr1z5w6/PPIlVn55fBZa7KLftzyg + d3gb4if+8MMPgfw777zDgw6mg+bXrl0DzXnEwXGs/rNmzWJw91Oq56kfYd0etcmQtFSmOlohQXOCG0+I + 1/hX4LUQaxRh8jXqDJbOZGRk4Cen5ZG3IsLs8RfHWgSThDcdbCme4KeE3oEaAJ9A/+CDDwA6Mf3111/n + ESeOQ1Wg45s2bUKnVeYiUw5Rqhe3lKWMsOZrgbyMtGn+2uzjcNxnyymwLtFqkDTyvOaxjlQsW7YMFMFP + zlsRah08I7wWQdeQZcEh4SOewy0BdEDPgw6mQwSJ5oQ4hIUQxxJ68eJFLJ6QlNra2smTJ8u95aoxnJII + jbZRWYrSSOQ1cCOPlWyCnpvFeYQ1b645oBmvoSERiszMTDBDiDVs3zOCtQgvO/9AUguBMwKdmE40FyIO + KccSCh2HpBDBT58+XVxcHB8fj0aJaoaqI6x5N9KmZLfHa+rLcE10VrkmXvNYY20MVeTl5QFr3vaRxX4W + sBbRD4EHyup4DtsPhwTo8fPxoEP1UF4gmhPipCpYSIWSAoKTnqxcuZIJ9yAlysqstE0ZjUmBm7VvqNb6 + WJdNpOZnFvBuQJGPN9c81ilqeYC8sLDw/ffff9awFqH0RQ+MweHRJuhgOtGcEOc5TjoOSUFdDY0+GBXS + E/hCpPUzZsxAo4SVTdrHGotbq+Wx49a7EGtKZHixJvOer4HjlOvlVVVVHWBNnu9nzmVEtBzTAz8BHm2C + TjQXIg4pB8FhYIng+MWg4KQnPNww3TJrmXKgEhraHq+fAOuWl4EpO/QdkyG8CWkhNcN6hgqFmq1btxph + LVwbf36sRUYvrBB0nulCmgNxXlWweBLB4VVgraDg0BMjuFFFgQVUBHKq3Y6GPDHWEGtK0GH4eBPCY52n + UU1UocN7+PBhHmsqifyCWBsDLcTdlOY84pByIcHxa5CCG8FNYgL3jYIJmlKqESqDWJs2JGH7hBa7PQ0R + kpo3fPzC2CIg6Hbi/4X6NXTsGcG6I6B50NtEnBZPnuCk4KQnQrih3fCCyDBRLUHuruijYF6bB1rY/O0M + 1oIXwDDMBxOCTiMtjAJS43+hHKCcO3culmve8+EnpLyRGup8a+Zn0OtOAW2KOOm4EcHJpeCX4dlN2o2l + EskOqihwgampqTAGqiSO2tSmEWLNr41GPkRo+EyxhgnhF0Ye61yNeoVa0UuRlZVlijVfe/rZsH4yoAlx + IcF5rwKOkJ4Q3CQm0G5aKskI0jqJ8qbMTaYap2JAt4c19NeoQcNjLVQVEmujhZFePHxnYL1AjeI1TAhe + bORceKthRaHaE2FNWw5+hgT9hwAtJLjQqJAZ5+GGmABu/GJwJjCC+D2xTkJJkOOgf8bcSJzyEdBCXqMk + Qv5aOIfWDqlZxkiVED6LEZCabeyYppI5yNDfwP+dak9U54OD4vsyP4MJ+VFAGxGc1xOCm8wJORPKdGBL + YLqJ2ugqjB8/HrVWvMENAiKYjTLkMlyObpiyNEoXOyPWHKkZ1lgYpVJoF2GNFx5rCXhAfRkqhvzUWD8F + oNuDm18qeeGGkiBhA7VRGgS1kdfMnj1b0VvBEkgjsaYcHeLL1Z4Y1qZ5ecdiTd+QMtJVGizC6enpWCog + Yni98ZPg5Rcavp9arJ8a0DzcJCb8Ugm4SbhJSYyoDf+HgQ3URtSpJlij9kSdMH56uAOsTZ01CUgLqfH9 + 5b7yyspKvMB4V0HKhEW+n8GEPGWghXCbKgkYBCXB25anNt7LYBm6JIoghSpZ1cZwJbCG/rZH6pYaiKEM + wjtrcnutSa2aqsLuApTRkb7y5poMn9HC+FO4vZ8EaKEz4eEmJcESBGqTasMDkCHBb45diMz2zeew5scq + ARYMHxZGXqz5bkBbJsTgrKnkRGUQntRcvUU5VIk0Fb4e64TQhPwMC+NPBbSRcJOS8Iskr9pkSGiFRPbI + ilDAGkALRlgNE8PV3DiOsPPSHtbk9ig1JwFpUWr1crUiRAF/idWYNyH8wkiFzJ9IrH9aoNtUEl61hTKC + 5A1Wl2ENXkNDhKQmseYFRNhRNMVa2B/gBYSUmiM1pibh9jC4gvYF1mSjhZEX66de3vs5gBYqCU9tkhFK + bSAjlNeAZfn5+YpgBQYbW/VhKWMkZ82T2khGhGUQ6g/w6aKA1GhHYFwCnWWkTrQwUuXaSKyfutv7mYBu + k9qU2pCMIK+B0QbWYBmmNZgPQWWVLzfD7VGXAAICQPnZD+re8u0uozoqantUb+JXRY7U6mVqrL1r165F + 6kTZOVaLnzqL+VmBJmrzJW8IolBG8KtSUoPlERMEimgFGybmsebdHjkQfn6sTax5AUG9SbgqUgsih0sX + bWQYyIK/FGYx5Kx/CgH5uYFuT0Yoh8S6xC+PycnJKL8JSW0oW1dyqyI/HUljTSa8NjgQvjnAr4oc0ExA + +ivnz5+PsiJlMbyzFrq9pyggvwDQRjJCboR3fuSy8WuDa9OmTcOZCK1I3ZIuGkhNA6hCsTZKFyHrqIEI + V8UWUrMUxkteU1OD1JycNdYJKjn9FG7vFwPaSEaEzo9cNrBGqxe1J7RLDFgDL6yKcCC0KgJffti3Lawf + FazJVpuQGntkRo8ejeYAnDU8D5Wc8Er/FALySwJtKtlUisLvyWMNHyZzl7GpM37rI+3koFWRDrfged2m + gMBWC1dFWL0W9cBmdNhq5EoQELi9n1RAfmGgO4M15vzkQXKDCeFJTbYaukGbM4yw5gWEXxWFuSJ5aih1 + tobl5RqWl8PtGQkIPxDyVFKYXx5ofnkUJutGvMYIErYdMlIDaH53KU9qfseRcGE0stVYFXmrJyR1tgb2 + BoUtoYBgQeZre8LmwI+pgTwTQJtaEdg+IdZQT0yJQFJp47Rh9wZPauHurvYcCHUGeKsnJPUsFcZ9MIhi + 5EAohXlaBetnBeiOsYYPwdAwjj9QzVYxoGlJ5KrVTKlpyyICMtIxqakAQolii3pgUhDTsHPmzMEcIRwI + 1ZtoVUT9i59QoI7XDyb1MwS0Kdb82kj+ur6+nmXnyGLQL8eSyCflEGja/Ny+WBvmQIxITZOYWRrMHGO0 + Hic9YRic6k1UA0F5gGz1j+/CPFtAt4c1mAWswTLMQaPUyYBGRs63BSAXRtueeQERrooogJS3DDeZknqg + MjExEU2fjlfFH0zqZw5o07URvEYGgTwCOTrKQMxZJ6kMQHOlaqYeEA06T4s/psIE61akJk8tUA91MiM1 + Rusx7sPbatNV8Qfnis8i0EZYU95IOToyNwzVwe3h/W7Y+M8viXQqCLCmcxNMV0Wa+gWpTZWa27SKjB+k + RpZEqyJf2KNcka9W/zBSP6NAm+aNhDWcAJJGtFlV8SoGdMvOUcOSKDx7RYi10OpRUk6JIu/zOKCZUjvI + tmzZgkEfKuyZ5oo/uF/+7AItxJrqIVRTxQIFbwBE8GZnQHM7B1iZCchyJ5UZzl5p04EQqYWeGvaDy1xo + exn2PmGKDHsYMF0vzBWFBZAfZj+eaaCNsKaaKrDGwoh0EXuEHm09p9IHAY3zm/jz9tpTaiqfUkeRlJoD + GscO4KDJPXv2mFo9vgDyw0j9rAPNY02tGeHCiNoeysqM0ZBpjCSg0AHvwZ12yLDmD8oywtqU1AKggTXG + 9dLS0mDbyerxBZAfSernAGgjrHmxxqwTmrlgJe2nM3gPOlaSP2yvPaXGP6HqB+/zWtQDWxRwCDP2sMLq + GeUvP4bUzwfQhDUVQ3ixRjkC1FMlqOjEISbTSAuhHnR+Jx0iSYejtklqlPRQOTFZEkFqvH5oXT5dUj9P + QFMPjBpgqIQgi4HnlXvIkSsaJsdIpun4ZToclU7rbFOpN7ROXlpkmin1CNXIkSOfLqmfG6DbE2t0ctGF + eQQ0J9OG81GBNU/q1qVqw7Av+TwT9UAPHskLdk4SqU3txw/w1M8T0EKsKYuBaGK9QrFJvVJtmEQgoOmw + ZQQEpD1SY34MyQtfO229JCr7Mp8HUsN+8J6aTxSF1Y9OlpmeM6B5sRYKCPRUGa80AM3l4uwIWqC8nxOQ + DkgNcRcuiUL1mMYmfXG8AHlqPlGkpiL1BJ7I5z2XQPPTqnB7SBfx1sY7HV6YOTxKW7Ae0hH5wLo9UpPP + w5JIWSIVTlu8B1sSfdlpkth9TYkiNRWNSnqdT16eP6CNBIRSGCg12gKGdi0BjQOs6ZB23PJApDapfjCl + xpLIlz5aA40y4bhx49DlouoH6lnUKUdti+rU1HzpZJnpuQTaVEBQ24T90K7lrn4g40FA0y0PROo2fR5a + t3yWSOl4y6lo2ISLdiI6L9jjDntDozaoU/PzY9R86SSpn2OgeQGhFIZ56ikqQ2GaHB7drgGs93Gkxmtg + SmosiSh98OohAJpliYHsxAScBQNSU52ab74YJS+PXRKfV6BNSY2TQzCJypZE3koD6KPcHSZ4AlKjfMod + QSac1aONRoatzlShFsg0aoSjRo3C5BhOEjDNyJ9oSXy+gTZaFXFgiCpFZQz0cY7XUGpUP0yTF1oSeUPd + 2uSxwqlGhqMBTX2esMvVGfV4joE2XRXR9EOblc5gZ9IBdT7GrkKyBtYHudth2lsSST0oc2mtHkjHoR5Y + EuHz+CWRpk+fSD2eb6CBNZ+XY2nC749GF7yaodxBQOOqqVM2TEPgqWlJbFM9KHOhqqnglFB4D+ysxv59 + 4ZJIE5HoQnS+8/LcA01zwHyxCexD+c1wZwakGUDjWq8z3LVeB7gl0bTLRerBZy5GMj2TZS7YD4olkVq3 + 1HkxyhIfqx7PPdDCVRGkBu8wZG69jbt9hwf6HMOaKTWWxDbVA96DMpc21cNTjoNHkCWi9MFniW0a6g68 + x68EaCGpUXjD9OIjoE/b2JznAqSGz2tPPZC5UNXURKZxGC6OacXhipQlokcuNNS8enScufwagDYiNY6v + RZGaJd+4MA3ScdrG9ryt/Xl7RupDLephtLMc6lHJHRbZlkzjfIB+/fqhz8Aban6aiUb0qMbUsXqwo34e + a7af/S8QKjXe3ShTMOOBVAVAn7GxO2/ndMEJcDNP3Z56GJk8gZvGyLpMy7rjP0Y9fiVAE6mprwh+IcuA + S2OifJwBDTq7XnQF1mB3R+rBm7zW6yEVmHJyckg9aMLmSdVDBGV59gnbmZ+QSE3lU6xd2CdAJtrmnA0g + 9rjk4X7RnZGa1ENo8gSncrYr0/2U6AWTeph6D34+rwP1YED/OtSDPDX5PJQmMA7JLm6FieaA9rzk6X3Z + 2/mCs0E92qx7VAlkunXaoprAOrbYfiBUDxTzTDOX9sBk5979aoCmBi5NJfTt2xclUGgF/AZ0Ayj7XfED + 3GxJRDrenskT5uKCtEWdopaqpDgWijIXTK2js4MtkZS5UCuAr5q2+f4TUUW1M+/NZ/9rhEsiinlAh1ZC + t4tuvld8g64GAWvoNUvHjUwerx5CmW59iwSumcAOaqgHqldQD9NWAFVN21MIUQd/9+wja/oT8qQG+5A9 + QzeALATa/6p/2MthoddCATrUgw00mcg0OzUIbprSFpP1EIM18+bNw1n81AowrZp2bPIY0L8y9aAlEe9r + tAJsDjOB9rrkBTr3ut4r8nokqM28xx5rVp42OaeJuWkUPdpKW1RxKtygApnmq6ZooWHi1DRFbFOKRU/U + j3kuOM4viUOGDLEtt4VA6y/rweU+1/v0e6UfnjDvgRSxTZmGm6at+ib5IcbPwsLCMJbHmzz0XIxkmu/Y + mgIleqJ+zHMBNK8emO61WWRDugE6D7gxYMirQ6KvRwN6ZvIg08KGCy/TtB6ijNfaeOBcRKyHuB6XN3k0 + MCbs2HYg0+z86I6Xy+cCXOEPyRtqgKIdoYXfgG4AX6A8/LXhg24MgnowmW7PTXewHrqx69F+mEyLOlkT + eb7gJvWAMVD5qwAr5KLvK33jbsYl3EoA1vgjZJoNjD12PWxtPODNYWaEMk3zHiTTwj6AqUyL+JoIfrJf + maHGG1kql/ru9o14OQK6MfrW6Em3J417fRzEGp6P9QG4m9CM+wBYD1HGI+PRGmi0b9At27t3Ly/TnXfT + Ijpn71e2JPIyjeaIvkQPZIfdHDbh9oTENxOnvzl96KtDmclDHwDrocm5hWgCMONBhWlBaYkNP45WDR48 + GDeKkZumaTHTokebqYmImoy/viWR1GP58uVeaV6g86hbo6a9OW3+2/MRY18fy2T6cDvrIZoAMB7k8IyA + nq4KCQnB7W1ouPBumm+4CJE0TVtEP2zu5tmXbCrm4RBUt3FuoPP418fPfmv24ncXp72XBlKHvxyOehPr + i3dgPEwcHu6NcnV13bFjB2Sab9di2AOHBfHnT7SXtoh+2NzNcwE0EjG0rh16O4DOU96YkvJOyor3V2R+ + kJn8djIMNbJzlh+2CTS1tUwcHho3aP7iLJX20hZ+PTTNAUWoPwmPAun8MNkzjjWZPBR9tG7acTfHzXxz + Jric+2FuwZ2CjPcy4ECwHrZtPHA3Bjk8U6BRmHZjt84ZrYfY54KjxvhBU1rwjJyFqM1hsl9HmYlkGteO + JhxPAIvB5fUfrS/9uDT3Tu7E2xNZ2gLjYeTwKG3hKx6tcxbadYGDtbAe4u4CmqqhJgBfxiO7bLoeivjD + yH7MTphnk90k04MGDUrYlpD+Xjq4XPn7ytrPaks+Lpn15izk5SwRN3J4BDSGxPjSkpGVjlBgQB3roTA/ + 5Cd66eQJ2g9gRFYR706Ei+avQ0DI5OEswZFlI3M+zCn7pGzT3U3b722v+6wu7d00pC0sEW/T4cFKtwM0 + WWmMmArzQ+GkB2/hjIGmRZM6BeSpf8AGjWeW0QAa7/S47Lh1H60Dvrvu7Trw5YEd93YAdyTlaMG0a6Xb + y1nilMOHDyfjQd0WzIl1xniI+BP2nu7xFM8I9KBVSUnJwAUDK35fsfXzrYe/Onzym5MHvzxY+FHh4FcH + M4eH0lIHOYtJcohBBoweYOyRNx40UkNtLd5WmBafRXREp/DUt18TqQE0Skt9J/et/6x+35f7Tn97+vJ3 + l/Gx5tMaZOSs4tEm0LXcIG9bWTjmzXr16gWgYTz4tlZnCtPsztmf4niKZ4TRkGnU6SPiIyAXx78+DpQp + wO7Jtyej/8JyFpOD1jE0zYZp2gQ6SYUr69G+ERamaSdzxw5PhD7YT3po0y+LOIBGIzWwTyDk4uIfLvJA + g90wHuhysWJpW0CzmUdk4SbSoZ6r9vLywpkhvMOjIbE2G7VCKy1Sqdzw+gg3Pf+aVkX8qrAE3kHeJBp8 + QKlT30nF9AFLDk2vDkDzsD2gF6pdXFwIaGGj9rGlJZGr63SUuPCyGB3aROXTZ62qB+Ae+zBqAiCVcPVy + FaKM52D38veXY6SGTae3CTT6LFRXau2jcXWznZ0dgG7TSguHpo1yFlFQUKODQxxuVjI6uPonOgtViALe + OlhGMPuDsTZMJuLSWNwWglcdKQYWHH9/f3d3d3t7e41Go1QqZdwDT/BHfBJ/hS+IiIgYOHAg/glO7oeN + Q/sDF+Ci3AMrhd8ZKyEe+L/YOdpd+sMlYQBrpOMY82BZeFuXYbDNFm0BrVmq0Wq1WGDbrOHxzo3vafG/ + L4De5OdXaGPTCyk87cUVnvr2tI6NxPeBB4IlwvWZOEw4Li4OMLk5OfYODUoYMmD+5HE5C+ZsyFq6rajg + aF355R2Ntw/tunP64L3LJ//4yvn7r1/9x5vXH779CgJP8Ed8En+FL7jd3HS5ofxoce62zEUbkqdnTx41 + L67fmMjg3t4ebnbWSL7xP8LEbY+ePfI25TVcaDjxyYmL31xk8e3FNR+u0V/UM0bzJ4kJdgK0C/QKjUql + AtDt5SxGxdJWQANrnW65Wu2FoiK1DExPvufvlOrk4oZWJN4i4BcOUIPDt7HSRoUETRsVvypl7ua1ueea + agHTP958+ft3bvzYuH3p+1dOPbx08OHpnQ+PbX64v+bhzpKHm1f/vXr5B7mzz6aMbZwwYG6A0/hgt1AX + rUohjhgUMW7BuKUblqY0p+hP6bXbufMnEEZXcGHzYZuMztTI5XIAbVosBUFpG0CbySEYvZmLTR4e8xQK + Wwh8myffd+aEPbyYGJcCZ6dMmWKt1faLjFgwZUJl9vIzm2s/u3DsxwLawUvy1svf3zz3/bVjD883Pzy+ + 9eHB2oe7GNYPalc+qEh7UJx8d1H8/VXj72eO/nDBgKMTwksG6mcFO0Y4y83Ev+0S2aXnqJ7ShVJVsYqu + dGYb6Gqt2C5PsneZXAiUGgoGrTNNDoVbEPmqtJDRTUFBWwhuF5fJuL8K8078NSWPPfkeSxPc4YYNGzBs + 6exgP3JAP3B2X2Xxh6cO/oTImoL+9vXvb138/vqJhxcPMGofrn+4p/zh1rUP6nMeVC29u2zc/TXTOKxH + 3V867G9LBv4tNfZP8yOujnOtitXM9RNH2He1sPzvLmFdzMeayzJkOA0LPlqdp1ZnqzUrW7AmxFGS5oCm + 5JCfeQQ72yz/PwI6OHhrUNAjrB0dR2FFavPke+E1JVgq8f/Azhz8X/tHRiyfk7i3fP1HZw7/rOAawf3m + te9fO9+C9Q6GdXPFwx1FDzfl381Nul82//66xPt5k+5nj7m/LP5v6YP/lNL73hzfuzM8705xvTvJ6XK8 + bWmUYqrOXG/14n+a/Uf3vt3FE8XKJezONBYrWTDQVzLpgCTCE1MWThtb2gOat9IiAC3Aeou/f5W9/WAc + 88uffE8rKRVRQXB8d7TcHexsxw0bVLpiybXdm39JcAlrQAw6v3oWKH9/5cjDC/sNen2g9mHzhgfbCz9f + l3K/Jv3+hpT7hbPvF0xl1F458i/pA+8lh9yd5XN3Oof1RMdPJjjcGe/w/lj7plj1Qj/LSNuu3Xv+d7eQ + bpajLZWLlLgshyG+VI3FEAc+Amg+C8emWqNyh2lDC0BvE2DNqO3nV2JnF4v7q1CUotMMgTXakVjW7Gxt + xg8bUpm97PWDux68xZzAT44yFkzG05MGBM/ueXh6x8MTWx8e28Li6KaHRxsfHmlg/EUc2vjwYN1Dhm/V + w70bHu4qfbij+J9Na+6tT7m/cfn9qsX3y5PvF81mMpI74S8rR3yRFnUXWM/2vztDd3eKG3jNsB7n8G6C + /dtj7N8cZbc7VrPYTxxl07V79/82CzcTjxfDR8Nf4jharIfIWfi5Ayp3dFBXEqGra4J1k4/PWhubKJzJ + jj4CblMXi8WDo6NWL06G8frra5f/fht+6+V/tliup4D1q2fZOgbUgE5TwYO6TLaIlSQ/WDvrwerpD3In + P8ie8CBz7IOVCQ9WjGaxfBT3ZMyDzIQHWeMe5ExgX5M39UFBIvsn6+c8KJrH/nnpwgfli/5RmnovawqD + uHT+/eK59wtn3V834/7qKX/JSfhiWb/PFwPrMIZ1kv7uNI+7k5w/neAIXr+XYP/WKLvbI+1ujbB9dbjt + 5hjVHG8Lf+1L//nSf1haWq5atQq7dOHwKDmkdI8vd9AhE0YFPFFY2P42sXZzy7K01Fur1bPGjd66Pv/T + c0e/uHzy25fP/OnVC3+7deV/fwTWzIqBdI25D0pTHuROebBsxD8XDfzn3N7/nBXxv4mhf5ke8sdpwd9M + DfpqatC9KUH3JgfenRT42aTATycF/n4iCzzBHxGfTw7E3345JejrqUF/mBaMf/XXGSF/Twz5Z1LoP2dH + sG+4IBbf+f7CQV8kRd5fFnd/xYj7WWPu5yTczxmL+EvWyHvLYj9Pi/48NfJucujdOQF3Z/owrKe4fDbR + 8aOxDh+MMWD92gjbG8NtX463vRZnWxQmG2PT01NhiWIp3uJ8+Z8f8MC7n59LF7ZoRRERxzisdxOvAwO3 + eHvXubiUuziXujhlaJSBq1PnvXVkN1wEsP7yyqk/XD/755sXeaxJQDrWEMbW7YWMX1njOEwjAQdwAUbA + 6+OJAXfGB7w/zv/dsf5vj/V/c6z/Gwn+txP8X0/wuzXG77UxfjfbCnwef4uvQeCL8a8Q+OfvjfP/YLz/ + nQkB+Lb45nglPh/v+0Gc03fT/f6a6P+3pKC/zQn/W3LU3xb2/VNqn88Xht5dEMYYPT/k7twgxmtgzSTb + 7e4Ep0/GMazfHW1PvAbWAPrKEJsrsbbHBriuDLDpaycLDw9PSUnBukXlf3J4lLPwDS1aDwH0SQ7rA4GB + O3S6OgeHYne3Ch/vmiC/BoTeM8taHZKfMvfto3vunD702XmG9XfXzz0Ga6B/bPODmmUPciYyZGeG/3l6 + CMEKCIApAQqAhFC+Otrvxwf/qtDLgNfs5nCvKwMc3hzr/e54/QcT9B9P9Lk72ffLKX5fT9PfneIE/jIW + Q6MhHRR4znjNsP79WMc7CQ7AGnptwHqozbX+dreGe96M97gR71ka7pDgprKRWi5YsADlaagH5vDoKHWs + h8JzlwD06dDQoz4+u11cNuo8N/rp64P9N7VEY7B/o94zx1Ybnj1v5jtH93505tDdC8e+unqasEY2TBpC + vH5wZjeT1+wJeM/+IzEUb2e864XI4jfnGfrjMe3kd7gy1P1Mf/vro7wQN0brbo7RvZ6ge2Os9xtjPV4Z + Y3trjN2bY+zfG2sPXYZiYD28O9mFoTzZ7e5El7vjnT4bx7B+fzSTkddH2r06zPbVQQ5vDPd8nWHt+epw + r1fiPRuinWforD3UMpSM0BpHmQX5Id2aw9/FIPLzO+TpsdNXvyckcH9Y0N7QwB3B/puNsPbV5dtZRWck + TXn3WDOw/vzicSHWf99T8fd1s/938eB/zAwDuJBOgIu38FucCPDgdhKXp/5lFwe5nhngeG2kF8XLo1gA + 9CujXE8Ptz4XZ30x3ubKcJvrI21vjrJ7A1qRYP/hOAfoxqfjHIEygnj9wWj7tyEjcXa3Bzu9M9LrzRFe + r4/wwtvlRjyw9ro+XLc91m2ur63eSgHtxvLIV+Xo5i2Rn8+BsOBjvcKOR4QeDQ85FB7cHBq4MyRgS2u4 + N/npC+1tBiRPTHi1eSth/WVjwbdZk7+b1+eP04IYuOMBrh8Dd+wvD67w1To/wPncIGceaP7JhREux+Ot + jg21OjHU6uRQqzPDrM9zoF8bYXt9hO2tkbZvjLKDaABfoIz4cAzD+p14+3fjXO6M9npvlO7tUbrbI3S3 + Rni9Olz3ynDdy8O9rw333tnfY66fvY+1EudpwfNBrOFAQG1Rr7BTXJzsFXYiIvRYeMjh8OB9YUG7QwKa + jLAO8K10shs+pW/EmdlxH86I+ni8/7vjfN9I8Hl9tM/N0b43mcL63mDhh3jqxPzB3/BsP8cLQ1xMgT43 + 3PnYMKtjQ1piqNVxDvHTQ63PDrO+MNTmSpwNnAa8HRQDugHQWcTZ3xnu+kmC7s4Y3fujvYH1W6N0r4/U + 3RzhfWOEN8N6hP7KCP22fh4zfe3ctYri4mIkIpARHmjC+iSwjgg9Eh4MGQHW2zisOSXxawjWVQd7bHBR + DZN16VnTy/F8nO5CnPfFeO9Lw70vj9BfG+lzbaTv9VG+r7B4hrA+1df+4jA3U6DPDndqBTSP+BCr40Os + Tg62OjXY+uxg6wuwGcNs4DeAONbD20Ps7gx3+zRB9/sE748T9B+O8X5vjPfbo73fGKW/NUp/Y6T+5RH6 + qyP0l4frL43Qb+zjPlFnZ6uSw3QLgeapDRk5Eh5ykJPsnSG+DcFeVcHuZUFupYFupQGupS6aCXIzzQp/ + qyODvU4O052J051ncON/AKx9TLEmjvPBvRIs8JUvj2RxdaTvlRE+l0f4XBzO4jwiXo84F68/G6c/Iwj8 + EYHP0xfgK/H1l7h/i++AVxrfDd+25Wdgb6/j0TaX4z2ujvRCCOE+M9yhbaAHWx0dxOLYIKvjgxjip4WI + D7B5O97tzmjdR2O8P0nQf5zgfSdB/0GC/t0xPm+N5t7co3yuj9RfYz+Snn6XwkjXoW7WAPo0Jx30USgj + R8P994Z5bwn13BjkXhXgVh7gWubvWkrhbjNXbe6Z5K48MNDz+BDd6WG6c/Fgt/7KcIY1Ufv6KL9XRvsJ + McXnAQf97wHW6Tj9iTjvY8O8Dw/VHRis28/FvsFewmge5GUURl9A/wr//NAQ3dGh7LudjPPGa4OXgb1s + 8boDUVYXh3teGuF5eYTnFS4I9JPx9keHCqSjhdFHCeiBhgDcPOJnBluf62uFMXashO+M8oJ03Bnj/VGC + /qOxPh+O9Xl/rO/bCb63x/i+NtoHvzVwwMt/gSMNfk0CunWEnuoVcKiXT3OE984w3fYQz81BHhsD3asD + 3Db4uZb7uZZxUertsMJG0iveTlId6XR0iO4UqB3vfSFefwlwM51iFLs8whd0I1hPxemFmAIvQnBvS+wZ + 6LWbi12dCPpK/BME/x3oG9IrQejv7efWFGF1ZKj7sWHuJ+Pcz8R7nBvucXEEw/14nM2RIdojg7VHh1hR + kF4bAS1EHAQ/Ea29OsTtRpzHa/Geb4wE3N7vj/H+MMHnzljfO+N8Pxjn926C31sJvrfG+N5gWPsS1vj1 + WwMNiP0P9/LZF6FvDvcGnfeEee8K0e0I9moK8mwI9Kjzd6v0bw23o2qErKt8hb81ZOTEUC/AfWoowhsf + jw9lVD04xGvfIF0z98sTrAQooblzgOeOAZ7bBbGtvyfFVpPg/wpPhP8E3wGBb0Xfk14AQn9rtFNDhNWu + ga6IPQPdmge7HRzifnSo+4k49+YhVvsGaQ4M0h4arD08WID4YKsjAkbzQLMn/a2OR1tfHup+daj7y3Es + YXlthNcbI73fGe39XoLPh+N8Pxzn9+E4ZKdwX36vj2HuAFIGrEG1Fo02hhgoI5pDdXtDdbtDvHaEeG0P + 8twU6FEf4F4jgJsR3M16jtpcN9FZ3hDjuneAx66BHrA47NfGc/bL4wnCaycHKwFkwLGf59anGNzLw78A + BH19L7uNkbbbBrhuH8hiB4c4YsdA54b+qi2xqu391Lv6q5sHavYN1BwcxCE+SHtkIMKKohXQ/axOxNhe + GuIOrK8M87g2zON6vOdNOLyR3m+O0r+bAPVgQH843h/Z7zssjWD1A6gosOaAJqHQ7+VYzCIUoWNAU/Bw + c9RuBLUfwe0GrMu9nXJtZP0tXuqxUK9t6OPaGOu2ua/75lj3LbHum/t5NPXzYB9jPZv6sXia4Hbw3bg3 + RGWIVV1v+839XZoQA1wRWznQN/W3r+6rrIlR1sYo6/ooN/VVbY1liO8doNk3QHNwgPbQAO0RCiHisVan + +tgxoBnWHleGelyN83w53uvGCN1rI/W3R+nfGuP77li/98f5od7yPuwvV2lAMgysRb18m3sxiKESLAhi + PhjKLRGi2xOi2xXMqN0U6NEQ4F7n51bj51bl61rp41qBcNYmKXp6xNlJ80MdqqJda2LcNsa4NfRxb+zr + vqmvx+ZYjy2xBrh/Hqzxohb6yOtiHBtiXRr7uWzq5wLEt3Cg18XabIhRVvRWVkYrq6JbI95XvStWvaef + Zl8/zcH+2sNCuPtYnY51aAX0MM+rcV4vI2EZ4X2TOTyfN8ZgSfR7lwmIgdfAGoUXUbj3rjDv3YhQoKyj + aIV1C9D7Qr0RzYA7WLczyGtbgOcWf48GP8DtXuvrVu0LxN2qdE4F1rLBFi9JprmpKnu7Vke71sW41ce4 + NzK4GdaIn43ajTGuJQEqoCwMQryyr7Y0WlEWpSjvrdzQ24B4NRCPVtT0Vm6MVqIAvb2PGoX/5n6aA/0N + BD8crT3T3+niEHdOPTygHleHeV6L87oWz9LCV0bqXx2ph+WA8Xgzwe/tsX5gNOCGhgBrUahue6j3Tggx + F62wDtHtRTxiNFD23hesQ+wN8tod6Lkj0HObv8dmP/dGX7eNvm6A2xCuNgvVlkGRavNUH2tQuzYa1HZv + k9o/qZLURTqWh2iNgKY/lkari3srSiIV6BMieMQreyuqohTVXNRGKRujVU0xql191XtiGcEPRGnODnC+ + MNgNQF8a6nF5mOcVDuiX43XXh3tfH6G/Mcrn1VEsT4bruD3Gj4OblSoRomCvLSHwcLodobpdPNacSjCU + DeHdDHCDdfgIlPcHGaI50Gt3gOeOAAb3Fj/3TX7uDb5u9RzoG31caxzUU2TdXQbbSDID7Wqi3UypDSXZ + HOtZHOWWFeacEuAwTW8/ysNmgItVLweNv63K00rlpFbYKOVquUyBHrBUisAT/BGfxF/hC/Bl+GL8E/xD + /HN8E3yrkii3LZx2V4XZVobbmAJdH+tcHK0silQU9WJRHPkI8XJwPFJREamojFRUI6IUNVHK+mjllhjV + jhj1nnD1qQEu5wa5XRhiwPpKHJMOMJqAfmWkz42RPjAbwPq10b5UpwWdUQISYWWDnQj22gZrAaxD4DEY + yoZg5NXtCfJiwT1vDtLtA9DB3gcQHOIM7kCvnRzcTRzBgXgjhbdzka1ipKSbdoSDLC/EAdReHea80N9h + ks5ugIs20FbloFI4OztjaikmJgZTRRMnTsRw16JFi9A/w7HvGBHBIANua6qrq8NwDx5o1uEyicrKSoyX + Yw42KysLnWJsKsEkCcZ0cLxPYGAghhAdVYogO3WoovsYN+XCQNuCXg5CuGv62hf1VvBAE9wIEJxFL3lZ + L3l5L8WGXgzuqha463opt4ZrD/dzOTHA9cwgt/OD3S8SqQE0V1HigYaDfnUUwxqWgy+Li+CLA9xr4SWC + PbdioQvR7eSw3h1swHc3oRzIRRDDGsFjfTDYG0GI7w302tVCcCAOBd/McPfY4uaQp5IO6fI7qaKnmaWF + OTaf4iSNqVOnoteOOTRs2wN2GzduBIiAEp18PFAcwAPjE+iB0gNzhaYPtKLxMP18eXl5cnKyhcQCc0k+ + 4T4WEnN3rSTGSTlRp80ItlsfZdUm0AzuCEVxhBxYl0TIyyJawx2maAiz2tnHaV+s85H+ricHuZ1lWHte + jvO6Gq8D1gD6+kgfRmoOaPAahTBgTc0gEXI8+LMA92p45CDPLaB2kNeOIK9dUGEKjrAGoNvB+lCwN4IQ + J4Lv8vXY7u2+1dOtyc21yd19u5fXThcXbAsZZWFhN3ToUOwcrqioqKqqAsRgKyBGA59HFsABPkyoYBoI + D/RAMVGIB7rO9MAQeJsP/gvwxajB+/fyz67PRmTVZc3JmTN69ujecb09AjwU8hf1Ni8Nde0+39eysIXO + Bl5HKIrC5YhiLgB3aQvcFSGKhnCbbTGOO2Kcd/d1PtDP9dhAt9ODPc4zrHVXh7PSHQN6FAOaYc0BTVgj + CGgEsupKf/daf49NAZ5bsdAFee0EXlwQ1o/gbuE1ZIQ05FCI/jAi2Puwv+6Q3nO/p3uzp2ezTrdfrz/g + 53cwIOCQvz+LgIDDXl4bbG0nisUumALFwSUgMlhM/AW+ABewEpSYmkAvDt1PPDDsgH4zHujK0wN9fqMH + /1f0lTihNG5q3Oqtq1c3rc7fkp+3OQ9zjrmNuasaVmlSNWZDzV4MePF/bP7HRvFCpH3Xad7m+WEyjtEM + ZRZhLAhrA7sDFQ297JqiHZFtbu/jtLOvy95+LocHup0c7HF2qNeleO8rwJqRGksiAxoVY2FpV+TrUuzr + WuLrUuqDcC33davxd28M8NgCzYUOtId1C7UZ1kHeB/y8Dvh4HfLyPKzTnfD1PR0QcCY4+GxQ0GlEYODJ + wMDjiIAA9hERFHTCx2eTg8MchSIgMjISJ0JBPQAxcRb4EqxowWEOCPNQeGASF9O9aOzjgV4RHjhR0ehB + n6evwRf7+vqmrEkp3FO4fvf6dbvWrdu5bu2OtQXbC+bWz5XlysSpYvFcsXi2uOeInl0jur7g/IJK9j8R + dl2neZkXhD4C+hHcQNxP3hDpsKm34+Zop60xwNoZWO+OdT0wwP3YYM8zQ71QMb4ynJWLoR6M11xpHs9h + BFETF/m4FOudi31cSvSGKOMc8UbIaztYP6K2v9devcceT/e9XgDa5yiH74Xg4EshIZe5uBQcfDE4+Hxw + 8LngYPwVC0IfT0JCzgQGHnZ3z7KyGmxhocJFHHTYGXgKZAlWQInD9TFzhS3dOJgLQ4HYqYouET2w+4Z/ + 8J/EF+DLsH56+XuVHypHlB0sKz1QiijZX1LcXDy0dqg0VypNk0oWSCTzuZgrYYiP6tk1tOsLdi/YSl/o + Z2+W7GNJKBsiRF4eqK6PcmiIIqydt8Y4b+vrsjPWdXc/t+b+HkcGe6K8g3IxKtGokV4f5QNDcn6gy9He + 1qdiHS8MchfpnYsQ3s7FCD1AZ3CX6l0qYIrhH2AkADdMhZDaAV67fTx2e7nvdnPdBX3w8zsSGHgiMPAU + ByLQPA+IQ0KuhGLLJIurXDDcEaGhF1riYmgo4lJY2BVf33onp3kqVQgRnC6pAl6EJgau0MzHEDAeGJ/A + hhGMBmJgxeiBT+KBv8XXwLcMmzSs7kxd3em62lO1NSdrqk9WV5+orjxWGVATIM+XY5JRtlgmXSSVpkql + KVJJMgf3DLHlRMsesT1e0r3Upft/+ahfGufWIz9EBqwLA+Ubgq3qIh02Rjo29HZsjHbaEuO8tY/L9ljX + nf3c9vR3R5Hn4GDPE0N1UJITA5yP9rE/GmN7pr/zxSEwf74IAF3ozQJYs2jBGnCX+bgi36sXUtvfc5e3 + xy4Pt12QYOivvz9YfAxBmsCpBOAGWxnWwDcMZ82FvRIefoP7iLiOwCfDcYyDICIiXunV60Z4+BW9foOj + 4wyl0h9GDasZ5BuoAT403zDchsEJjLliPzAeGOLGA+19/kGfwV4SPLBnIL04velq05YrW7Zc3rL58ubG + i40YRK86W2VfZ69Yo5CvlMuXyuUZclk6Q1y2SCZNlkoSJeLJYsx9iceKLUZYmIWaveDwgq3shcGO3dO9 + xJWhNrW9HDZGOdZHMaAbo50Z1n1dd8S67ezvDiVpirLfFG7dFKZtjnY41t/9/FDvS3E+V+J9rsb7MKBt + FcO8nddzYQr3I2r7uDfp3La6uW7T6Zp9fbG+AWIKBjRhDfHlgikD5AJYh4VdBbIREa9GRLwWEXGrVy8+ + XouMvBkZiY+PIirqVlTU6717v9mr13U/v1onp8kaTTBOQEtKSoJrxuQ1htswGosH5lRwNhceGJjHFhWj + BwRdF6ADvrtf273r5q6dN3fufHXnjhs7tl3ftvDkQnWDWrlWqVilUGQpFJkKxQqFfDlH8FSZdKZUmiiV + TJZIJkrEEwyI9+jb4yWXl2Qv/vcwB1mmvw2yTWDd0JsBDWpv7GVXG25TFaypCdY0hNtu7e20K9Zz3wCv + o4N0p4Z4nxumvxjnc5nDWtT9f16wksZ4OqxqC24m3F7OZe7Olc5OtZ6e23x9m/39mYsICDjCBQM6MJBn + NEh9Ijj4ZHDwKU6Fz0EcoAyEda9er0dGvhEV9VZU1NsUvXtTvMUFnrwTHf1uTAzivZiYDyIjryECAzd5 + ei61sxuhVHrGxsZCWOALId/oeGKiEGNBeGDOHoNY9BEP3FGWMCvhwDsH9r+zf9/b+1i8tW/vG3v33t47 + 6OggVb1KWaRUrlYq85XKPKVylVKZo1SsVMjT5LJ5MtlMmXS6VDpVKp3CIT5JIpkgsYyyRFaFoSRrcc9B + ttIMb9WGYG1ZgKrET7khSFMTZtsQ6dTUx2NbH4/tsZ47Yz139/Pc28/r0EDvE4O9zw7VX4jzAbVFWUF2 + fa0sVRYBrjapLVgb2O3pVOTqWORgX+TqWqnT1ev1W319d/r5AWuIBsM6MPAohzLRmWf0yZCQU1ycDgk5 + GxZ2Pjz8UkTENYgD+AvCEqDR0e8DTUSfPh9ycYeLj7j4uE+fT3r3vt279xsxMW/FxLzTp8970dE3Q0K2 + +/hku7pOsLYOlkhkMHDQYqSOWD8hLJgPwgOTK0gR8xrzjn549Oido/h45IMjiEPvHTr47kHvQ97qjWpV + qUpVqFKtU6nWqhjiq5WKHIV8iVy+QC6fK5fPkgNuWaJMNl0mmSKxmGDRzbMbdmIh4XzxxRe7d+8p7fJi + fyvLlb5Wdb2c6qNcGqNdG6PdtsS4M6z7eu4wYO21p7/uwADv44O9zwDrYXpRYbjzmjDH4fYyqZmjo2Yq + Ye3ltN7VYZ2D/ToXlzJPzypM43GxUa/f7Ou7zc9vj7///oCAg4GBwPpYUBCCoRwcTHQ2AB0aihmo02Fh + hPXFiIgr0ISoqFeBYHT02zEx73PIftK37+/79v20b9+7sbF3+/VDfN6v3z0Eod+378f9+n3cv//HAwf+ + fvDg38fFfTpixKejRn02dOjF2NimiIhVfn7T3dxira3d9Xo9Bg8HDBjghSzr9u6D7x089MGhIx8eYXAj + PjqadytPc1ADoNXlanWJWlWkUhYqFesUstUyaZbUcpGlxTyLnjN7dp/Wvdvkbi+Nf+nFhBd/N/p3L45+ + 6X/kv/Pw8O/TZ/jIkYnTp6ePHTs3LKyfg1Q8xkVTGAoNcd0U47Ypxn1LH/etfT2B9XbA3c9rd3+G9b4B + uqODvCEjotJeLoURDOupbirLLlIb+TBXh7WO9mtdXIo9PDbodOBylU5Xg2iBu8HHZ6uf305//2YO68NB + QUeDg49zAYgpThHKBHR4OOJcePiFiIhLkZFXo6Je6d37tejoNyERQLNv3084iO/17/9l//5fDxjw9cCB + Xw8ahI+fDRp0d8iQz4cO/Twu7t7w4fdGjvxizJgvxo37YsKELyZP/nLGjC9nzfpq/vyvUlO/Sku7t2DB + zVmzjvj4jBiXPHnfOweb3zmw9619e95s3nV7987Xd+64tSPqYNRL1S+9uPrFF3NefDGTxUsrX+qyskuX + ZV26LurWdW7XrrPMzBJ7dE/s2WOmhXmSpUWSRDxTZjFc2r27eVJSRmLisqSk5bNmZc6dmz1/fu7kyQsj + Ivrr1fIkL9v6aAb05j7A2gNYb4313B7rBax3cXA399cdHugtquztUhbJsF4b5jTaRfXb//xPS8tejo4r + vbwqEC1AM6y9vWv1+jq9Hryu9/Fp9PPb5u+/OzBwf1DQ4eDgoyEhx0NCToSGngwNBcqnwsIA8RkKDuiz + ERHnIiLOR0Rc7NXrclTUNcAdHf1aTMybkIXY2DuxsZ9yWDOIhwz5Ji7um/j4L4YP/2LUKID7ZULCl+PH + fzVp0tdTpnw9Y8bXSUlfz579TXLyN4sWfZOR8c2KFd+uWvWHgoI/5Od/IldZlx2qOfHp+RO/P3fi03Mn + Pzt38u65U1x4ndartmmV1VplhVZZzkJRqlGUaOTr1PJstWypSpamlC1USlOU0gVK6XwFQjJPYREpCQqK + Abhz5uTMm5ezYMHqhQsLFi1au2RJ8bJlZSjYhIT0jbZTLwtw3NzHA8GwjvVC8Fhvi/Fs6uUlQm0eWOeG + Og1z1drIxBC4/v37S6V6e/s5Xl6VFCC1tzfCgLWPz0Yfn3pfX2C9JSBgZ2Bgc3DwwZCQI8AaQIeFEcqn + w8MBsRBlAH2uV6/zXFyMjLzcwu6bMTFv9Onzbt++d/r1+7R//y8GDvwGWMfHfzV69FcJCd9MmPDN5Mnf + Tp36bVLSt3Pnfpec/F1q6ndpad8tW/bHrKw/5uX9ae3aP5WU/Lmy8i9z5mwZMCbu1N0Lpz6/cPrehTP3 + Lp794uJZfLx3ceVbOepjVqrNLUAD6w0c1iUaxTqNPEstX66Spatki1WyRSpZqopHvKeHOC5u6oIFeSkp + q1NT1y5eXJieXrJsWXlmZlVOzsa8vMaCgi0TJiTbymQJ7jblka5b+no0QUBivTZFe9ZHeG4M86wL9agP + dRehTDzfzz7YRgnviZIjrgzAFiDszerZU21lNdzDYz1HagPWen2NXl/r41MHrDmgEZv8/bHdCOPVGLI+ + HBqKCeAT4eGnwsMZ0BERIDIFQ5kHOjLyAhcM7qioK717v9y7942YmNf79Hm7b98PYmM/6d//cwjIsGHf + jBz57dixf5g8+Q/Tpn03e/Yfk5P/uGjRH9PT/7hixZ9WrfrTmjV/Li7+S0XFX2pr/7ply99iYqZl1uSd + /eLS2S8vnfvq8nkuzuH5l5cGXBui3melarRS1Vqpqrio1CIYqdcQ0Gr5kpZIMyAunarsKRODzosWrU9L + K8rIAIvLV6yozsmpy8/ftGbN1vXrdxYV7Sktbc7Orhk2bFKItTrZ27E23KM6hEVViHt1sFttCMJVNNrD + 2kYhw04sXECwdu1aeKO8vDxsHcCCHh0drVCEOjkt9Pau5BhdpddXA2sfn1pf3zqkc35+Df7+AHpzQMAW + jFcHB+8NCTkQiimn8OPh4Ri7Ph0RQViDyBRE50fRgji0G4hf7d37enT0q4R4bOwH/fr9HgQfNAjs/jYh + gcGdlPTdvHkMa9A5O5sBXVr6l6qqvzY0/DU7+2xgVMSh908wlL80oExY7/v8oPM5d/VOK1U9B3Q1Fwxr + K2WpVpGvUWSpFSvU8gwu0rngQJcMUISGxi5ZUgQWL11atnx5ZXZ2bW5uQ0FBU2HhzpKSZlieysojWVmH + Z8w4MGTIAU/PTPOXJIOstPm+zpVBrlXBhqgB0Dh8GiX20tJSJAXYkI1aOxDHA5UHfH7ChAmWljY2NqO9 + vAr1egBd5eMDoGt8fWv9/Db6+dX7+zOsOaAR2Gu0IySkOTT0YFjY0fDwExERp3r1OtOr11ku2oUb0Lfm + OEO8heNvgeP9+oHj9yApcXGM4FOmfDdz5ncLFjBqA+61a/9cVvaXwYPT5+Sknrl36UxrRgPoWbfnqY9Z + q5qsVHVWqhouOKyZWBdpFasAtEaxQqNYSvEIcUu9bPToWRyLKzIzQeSN+fmNa9ZsKyjYnZ6+b/r0g3Fx + h2NioJmHoZ/+/jvw/gZQKtVwvUQ+39WuMsilKtilMph9FKFbgQeyABhSPFAyx6OMewB9PNDsgGdSqUJd + XFJ8fKp9fYEyCz+/OmAdEFAfENAQEACssSUUG0OBNfbTEdwHwsOPcjsKTOE2prYJzaEql6AqLTSHjt8W + 0Pwe0RygT53KJGXKlFccPfT1F3ee/OzSqbuXTn1+6TSP+JeXAy+FqputVJtMgMaSuE6ryOWAXq5RLBPE + Uo1shspCLsW6l55ekZxcPWNG7ZgxdYMHN8bEbAsN3QUXEBCwJyAAT2DA4As2A2UoKvemr7C1naXoJh5l + qwXKFCIUuvCgNgdq8PQRZWL+I30SO+UlEitb23idLh/5McLfv44LhnVgYENgYGNg4GbwugXrbSEhO0JD + 92LTRlgYExMO8dMt1O4IaB50Ac0fgd7C9Df79mV2pV+/zyAvrq7ZCfNmHv7o0pGPLh39+NLRTy4d+/2l + 459eOvHppZVvrJYfsZFuspJWa2WVWlkFCzk+lmtkRRrpKo00SyNdrpFmqCXpLMRL1JZpaovFarMouZ3d + wJCQ4oCAUhRhdDoKJqEQT2CKJYpk09/fEPgMFBV/i7e+i8tKqTSmt0qVo3dkQBOg1EZC9Z36RsIGB3oc + KBbjgYYIenoqlY+z83Q/vyp//9qAAKDMB4Mbh1JgWzlH7S20fTE4eDt2IoWF7QsPP4zNMq3hbkO1TXW8 + TdxbNB2r6CuhoYfVNi4lBxoOfnj+4IcXDrG4aIg7F0NPDejRpO1RoelRrOlRqOlRpOlZyKLHGk33HI1Z + htosTW2WojZboO6WrBKE8gVbsZXVNDe3bDe3HC7yPDxWe3mt9/Yu9fau4MQTQAPibQEB2wMCdnAfEU2g + tq8vsg2YtA1q9WhvsSzFzU4EiNGjQ3cODQ7qbqCvgdI7dTGo+o6PeOCPqBdjwUQvytq6t4dHakBAHRcb + AwOBMgWjNoe1QUla4CaCN4Pg4eFHIiJ+CMHbW0sdHOYPT5x88IOzBz84Z4gPzx3kovB2rXy/Q/dalVmJ + ymy9ymydymwti25rlN1ylV2XKbqmKbouVHSdTyHn46U46W9/a+7ktMTZOd3FZamr6wp39xwPj3xPz3Xe + 3uV6faWv70Z//ybgC+kICtoTFLQXXoB7Ar+7HX/FsRtpR5WtbaKVmVjEQ4zuEZpGQBPVL7QqUHHHA0Vh + VNxRTafSOz6DKhr+Fvtq5XIre/shOt1KgjswEHC3hziEu0mA+C4O8YOcgrMF80klRYg4fk+VtXNhcy0H + tHHEnI4z26o026AwK1SYrVeYrVOYrWXRbbW8W5a8a5qsa6qs6wJZ1/nG8TtfsUzW18lpcQvQmW5uqzw9 + C3S6IkgwpxubAgO3cb52H9IILpM4wHnc/cHBe+DBOGoj26jGO8DRcb4ImkAsBmfR10BTA4Ci3I6N5Ci0 + 46wlqrLjI0rD+CPK8KjH4wUA5RcuXKhUOmOfvl6f28JuHnQjgpOe8HBDUsBxJikCxJ9YxIG4nd2cUbOm + tolyzVvb1QeczTYqzUo5oFtQNluj6JYr77aMA3phGyh3mSL9rdTc2nqak1Oas3OGi8tyV9csd3fQGbpR + BpLC1+KosMBAbDreFxICiJFAHOHiMAc02A1eY7M3pLxcp1vn5ZUnQo8OgoDuEXgK2gJi4AtYsV0f9XUU + 0VFZRyEYDzzBZ/B54A7QCXEoODy4SuXu5DRGr88LCIBwUzwR4jsFqsLrOHxh2+6bZzRoZePiWXa4sU2g + B59N6L5dZVapMCsyoXO2vOsSjs4pbQD9Ym+JuXmQk9MiSAd0w8VlBejMCXQhZBdrHdZAQd5wGF4WEHNx + ICQEAgLVRipX7eeHL4agF+p0a0QgJrQCmgB9QMcIrSBACXxx5CDK6lT2xQP7FPEcJXaU2wlxVCZBcBAf + /xCraGJiokrl4eg4xtt7lQDuxyMuVBWsnKGhewQ0N5Jy48XT2nrqpEVz2kR549s7tQddzeqVZmVt0Xl5 + u3SGjPyPnYVaPapFN5a5upJurNHpijl1RuoAMdwJC0sulsN3D+0+RgGd87vQFphgiAwcC4AuEEEu0KAj + IgM7QIwWBiAGuCii49wIqvPSA1sVUWgH4oAbHOfhBrshJpjN4OB2cXCAC1zRGm4DzVtLeXsrJxOW1qBj + /RQynaU/eBd7BYfUX9zVLp13tEPnHHnXdFnXRW3T+aXBUjMzL6KzszPoDN3IdnfP45ZBoMb8BvIGZGdc + ggaZRgWCFn/QHJ9vxLsZlszPDy9JuY9PCYDW69eJoMiACVKAjhyoCgQJYsCKQ3qx1RYndWCzHB54gk2K + 2OgM9PEF4DixG308iAleJ7xa+G5YXTGjhVOD7O0HeHgsbAtuIeimUm5kV8gjQtAhL3DlpOkMd6Vy2PzV + S9tEufLNJqbObdI5T95tRQudk9vQjRc8LeXygRyd01xcYDkA9EpYDk/PfJ1urbc3FsNSIAgcIQ6cu6Uc + gn4R/BHCUu3vj7+tQLRgXSTCex+KDLDAUCgDGkLAERADVuyOw2ZE7GmmB3Yl4o+EOODGAeD4YvwTdPDw + PsDrBNmB+EC4ofXwMChR4Q5Aa+twHK3n67uufcSZvAgcC35uY6a3XkUZ7o6OyVHDBu175+SBD87wcfCD + M1ycjTk9rPt2ZbeKttS5YzqPlPy2W08YMvgE/C8cHVOcnFKdnRe7uqa7uy/z8MjR6VaDoRAEDmusijX+ + /jWCXw3PWXBY428Z3L6+G3x9y0QgIxQAckEHoIDIoC3t98Secdpeiwee0IOHG1+GvhGJCaQGmk5KgjcH + CTcUCQssqlToOUG+cbqep2dah3C3Ky8t3txgz/F7yjW2OZvWH/jgtGmsfq1Uvs/OrE7erUzWbb2s21pD + dC2Qdc2VdV0h65Im7ZIq7ZIs7TKfQtJlniF+52cuFofa2U23s0u0t5+JKR/A7ey80NV1iZvbcg+PLPgH + b+81Pj7AuoTDugLkBawcvrwR4LE2UBtYs4O6oQDQAUBGR/qAyHSGI38yGN0mjwdd6oq/whfgKDt8MbiP + 14ZXErwt8ObAdAAZQQg3wY0kHnqCyVsrqxBn5wne3tmdQLxN98JyIo1mxNj50w98cKrNCD4ebbZF1q1C + 2q1I2m2dtNtaabc1LLqulnbNknZZIumySNJlwSNweZRfGiv+rUV3fHNb26nA2t4eWM92dJzr7LzA1XWx + m9tSd3f0Q1ZhZdPr13NAb+CAJpSFQOMnN6a2CCiDktABkgvauEwQA1n+PhE6qJJOzSeswXdSEug4ryS0 + TvLCbQQ3TCQqghhKQrJjYxPp4jLVxKLwpGj3ibNzil9kRMPlnQfeP2UaC64tNd+rMquVdSuRdlsvRFnS + dZWk63JJl8XiLgvFXeaLu8wzjhcCe1pY+NvYTLK1nUxYOzgkcUCnuLgwoMFonQ6MXtuiHgDalM7Cn9xA + bZ0uWwSU6cw1Xi5MUebPFCOshdRuU0lIuI3gpvQSCRHcJHJ9tBdw1zEQt7aOAMdxwmFnOI7f0EKqzqhY + 1SbK+KTrYV+zTdJu5dJuha3pnCfpminpkibukirusqANlF8ab/lbiZlKNdTGZqKNDYCeBkY7OMzCCJWL + C6QDGr3C05M0GnQuhuxydEbNx0g3HgGNXwq/GlYp/JoiXpSN5IIo3OYVmEZwg9q8kuAF412gEG6ICWk3 + lko4E+TxsJWooiAvBeI4XBSqotH4Qcfd3ef5+KxpD3S8r0fPndIeysPPT+i+S2ZWzYmGkM75HJ2XdUjn + oJ7m5n7W1kB5oq3tFE46QOc50A0Xl0UcnTO9vHIh0BydSTd4Oj/SDfzw+BXwi+DXwS+F6XocUYNaP7sr + SyjKQrno4HRMI6zpkmgoCb4VucA24aalEs6EjCCyJMg3CI7sH2UsdBtwjihGBhQKG0i5o+NID4/5Pj4F + POggV3Cf6PZEY/2tCtV+B7MGabey1nQukHbNlXRd2YJym3Qea0TnqRydZ3J0TsFK6O6+nKNzPhyxXs/T + 2QA0fkj8qPiB8WPjh+/duzfKnJgB52vOqNyJsKYJD0rp/O3VvGoLlaQDuPkcB5knDCV8N1ZL0hMiOBSc + CoRw4mhd4mhIuEO5XKXR+MKS29kNV9vYZTesaY/OgcejzLZKu1WarIGgc7akS4a4yyJxl5Q2RANi/YI/ + 1DlAQGfoBug828kpmaNzBkfnVd7ehmXQ2zvf3X2hs/Mke/v++PHwQ2I8E+9LOFq0SoSVZyRxVBw13NBp + tPR18qRXfFmbcJNwG7EbppuWShhB8t1UMyGCkz+BggsRR6kLlXE01ebMmePk5JS4IrH5nebmd/fve/fg + vvcO73/v6P73ju1//8SB909OvJTUfY/crEbarZQTDZgNg9OQMDrza2ByG0C/OMrit+ZmGk18izpjGZxB + dKZl0MVlnqPjNEfHBBubQVptuFLpLpOpgoKCsEEEd4+gA4VKPV/TJ2QJXNoRQsV9drnvD0ZZuEi2t07y + cMN0w9uQEYTv5ldLnuC8ggsRh6qA48jsR88aferzU4gTn5049vtjRz46cujOoQMfHNj33r7Cm0WafVZd + Npp1KTXrsq5HlzU9u64x71pggeiSa9El07LLEssuqZZdUixbOw38kcX/6MzMzfVqNdp1fVWqKKUSa1eg + TKaXSt0lEjtLSyV6pjqdDpzFLAYmLqEJoK1wUwi/74bfbkPg8rsXwBh2Lzgdz9bm0td5aneS3ZTBU5pD + JSoiONw3FBy5JSQFiPMch6pg61X00OhtL28788WZM/dYnL53+lF8fjrqYpS0WWpZb2m+wbxnSc8ehT3M + 1pmZrTXrmt+1S3aXlzJeejH1xd8t+N3v5v7ud7Nbx5zfvTDwhf966b9w/re1tTXeNJ6enjh1GvOMWCpg + iiBfmAbAQYt4V6FzjT4q7bvhd4RQNV+46Ybft0D7Qmi0Hsu+iET5x6PcMbt5Z0K+m9IcwA09QWmFEEey + Y4o49M470LtkX8nZL84iGNZ8cKBPvTlVcVwh3y6XbZTJqmWySpmsQibbIJOWSaXFUmmBVJIlkayQSJZK + JOksxOniR5Em7qnviZ132CIGTGfMmIHVGDKFHV3AF2dQwRFh+AKrNE7sQQsbnVVADP6SJhBnhchSc4oH + l3aE0L4F0dNFuQO4yZnACPIFE75ERYjzksIjjp/Sxt4mszrz3Ffnzn3J4uyXZ1lwoCPWvrvW6bSTYrdC + 3iiX18rlVfJHQJdKpeukkhwJA3q5AWXCmg+LIRbQBOgspAkQo7COsWC4MezLw0H2QBn1A6AMoQCR8ZIT + xLTdBnV8PIiz1PYDbYEsHvymENoOQpsWGNBPpA9P9MVGSyWfVdJqCcNDJSoQHArOSwohDu0GBMn5yee/ + Ps/iq/MMbgoO9MOfHw68GKg8oFQ0KRR1CkWNAkDLK+XyCrmsXCYrkrEx0WypFM3oZVJphnFIZkl6OveE + 7GILKVgMiHFIILYZYK8YGnWwPfyOUhAZSxz1VAlcIIvFg9/FRJuXQFtq+MFKEbh8iwpphOiJgPthX8zD + bZRV8gSnBZMkhUd8yZIl09OmX/jmAouvWRgQ50BHDH55sPqYWrVDpWxQKmuVimqFokqhqFTIN8jlpXL5 + WrksRybDAdfLZbKlMulSqSFaEMd4OW2ZgVDggbYc/o+40AFLAkSZJzKGA+hEf0AMfEFbUgMsHli0+S1M + wr02sFIwVPxeEGz4wHv05wC6PT0Rlk1IUnjEwSZM7WO62XD3wTcXDYi3gJ50O8nqjJV6t1q1WaWqU6lq + VcpqpbJKqaxUKsoVikKFPE8uz5Fjr4psmYzF0lYhGS8xV5lDLkBhyDH8LxQZRg2zcNjMi3UPs0TQCnSO + 0KujnjXhC84SYbFi0xYm1HOwhgNZ0JZ22WClIXBpCwhWILxHf1agCfE2Cc4XqoA4fsm4yXF7X9976dtL + CNwwYQi6cOKbiznv57icc9Hs06ib1NiTQkCrqlkAaGWJUrlGqchVKLINW1Tky+TCwNYgsa8YxVuoBPAF + iwExzgPEq4sLRmAtMFEEraDD5QExNBfkBb6kBgSrcPMS31lFtZnfWQNw4axgZ7ECQRV/AaDbJDifXuI3 + HDhmIMzco2tTOLh50Os/rfe97Ks9qNVs12gauQn+WrW6hoWqUqUqV6nWq9jmlBylMlOJvUAslrcKyUAJ + 5jcBLpY74AsWA2LSClgLpMuQY7oKixrWuAQK+AJcLBsgLLEVrpRgJc4iFyNksaoDWQIXzgp2Fms+VPGX + BNoUcahhvxH9Nl3YdPkPlxFGt9Tgj7hYrNe1XlbHrbQ7tZotOJpco9mo0dSyUFer1RVqdbFatVqlylUp + s5XKFW2EfIpcbCuGYkCIYSogFOTe8DaCQabjt2HRqJUKiCG4IC/wRTES4PJSQFuVaIcSYEUuxiOLlQbg + YtWhLiDWfKjiMwE0IQ4excbHNpxrIJSNgkAfdGOQ9Slrqz1W2iattlGrrddqN2q1dVqGdaVGXapWrVGp + 8lWqVSpVlkq10jhwOYI0UIorNoEvHhAK1NUw1AmtICLzt/ZCKIjFaBsBX9JZkgIeU9qbRLAKkcVKQ+BS + /48aVc8K0EixwOWG8w1Gl1oJ4R5za4z1WWurfVbaba1QZrfiVWs05RpcQqherVbnsms91JmtQpXJQJcP + lOOqeowm40EQQytAZBhk/i5ImgmgsQtIBA0EkBTwsFLPmm9bt4ks3wXEmo/HMwE0ftVBCYOYYgguaDN6 + PvWNqbhg2nq/NbsYDzfy0n3e3HVAWtxNj3uPizS4KJZdnpJjjDKBrpyklFpLYZChxQQxEZncG13WC0WG + naDrleAZwGLwl6QW4JIOEFuFhCXOGiHLV5Ao9/7lgcavHT8lHttaO0B5zltzHC84Wh/kUMZ1vHTHNI9y + pZZdBNTOdbx0KZB6gVrmI8PwMSDGMDidaoOFl64X41GGY4NLo0usoL901TfwpZI91ZOFmFLnmjhLbVW6 + CY0vbDy6h+WH5SBP5V/hF8CKNHbO2OY3mjtAGTfUszu8ceMxLhAzRblKq8XF9Dh0ha62yja+GI+AlkfL + sTEHEFPJgmZo6aJNpCEwcMiV+Qs0aSAAQkG3HRPEPKAdw9pepv2LMRrLCzKFxIzEYx8d6wDlRe8uMkYZ + okFcxr1W1Vp2K/1aJhptXkxPKCvjlVKplI5nosIQncNCt2wCZSR4dEcvz2WgTK1quhNBWEmmPOBJa0S/ + DNBY0B1cHFLXpHYAMf4KKLtddLM+LOCyKcq4hZdEw+RWekJZNUUlc5DBLPMVZEKZv5BQqMvCa++e7r2Z + vwDQcKn+4f659bkdo2xQDKCMux2bOF1uWQANXC7nruDtWJrnqeV6OeoY/BFZUAxCGYk1qkKoBMEs89cb + w8DxV07T4ia8S+XHCObPCjTegFiL+o/qX3mksmOUsfo9UozWKOPuQaYYG7TawsctgBlqRYQCtWYeZVr9 + 6IY8lN9Qu4BfRrECNQrhhd104URnbhbsPPQ/H9DIrFDnnZQyae+tvR2jPO2NacxjCFc/3swBZc7Msct3 + icsm18Lydw8q+7Fb6fl9UKjD0fV4VIcjaTa6QZruqnm6okEvxs8ENOoGOn9dRkkGsruOUU64lYBbpJmT + 4z3GD0JZFa+SKqXIrYXSDJtBtx+jPI/EBEWiNi8UfLqi8TMBDclDsot8ZMOhDR1DfOKbE4NfHYxL0Q1Z + CTm59lBu857Slns0VWNVMjvDAgigycwJpRnVZKR/dMcuakPI/R57RWbnVaLNr/xpGY23J9zFnMw5OJSk + Y5Qb7zZGXo+0OW1jvU+QlbR4DKbLQsXo0DKrpqnkrnKUQIULoJE0wzUb3RqNksVPJBoGRm8oXfFTRG52 + 8tDBvcP7h+Y0ZJ387HjHsex2uvspV9k+sXSzWFJnKam0lFRYSsotJWUsxCUW4kIL8VoL8SoLy5XmlsvN + LZeaWy4xt0xrI8wn9uju1DUyMiBh9MCxYwaOGzt4wrghkycOmzIpfsa0EbOSxsydPT5l/qRFC6dlLElc + sXR2Tub8/FULCvJT169JK1qfXlKYUVq0tKx4WXnJ8qcLy0/CaJQO3HRu87LnPZbIoDkMBi5Ctz5ibb3b + 2mqrSR2DshJ+9euQy2qYOX85+iY8l/kFEBkgSTNcM6SZbpunSVq6Q+xpXczdnsKIhK9bRdlKisryzJbI + qtqAyEZUVyByqitzaipXIWqrcg1RnVfHIn9jTX56WlJ0dPDAhP7rd609dfeEcXx+4pQgDn66v//lWOVx + uWynVNYokdVJZFUSWaVEViGRbWAhLRNLi8XSdWJpnliSJZasFEuWiyUZYkm6WEqR8SgksyzNfXr2iek1 + d87UeXOnzZ83IyU5KXXhrCVpc5dmLMhcsSg3J31NwcriotyK8jV1NUWbN23YvrV6z676/c1bDh/cfuzo + rhPH95w+2Xzm9IFzZw5cOHfowrnDF88fuXjhyKULRy9dPHb50vEriMsnrl4+ee3KqWtXT7189fTL185c + f/nsKy+fe+X6uRuvnH/1lQuv3rh488bF11699NrNy7duXrn12pXXb119/da1p8Zo1G3RrYgcGJlVm4VG + aseKjL8t/bgUJ9+1Icp8tYjPsPmspH0np16kVoQrMFrImzksgHyeTbkJFkDMsvKuGQUNFD+NpPlppSem + vH4KjF6dt3jUiP6u3s4zVyRuv7G1DSLz1G6h85QbkxxO2smaJbImiXSjRFrTQmSey6ViaZFYulYsybWU + ZFkauJzOuEwhZLRknqV5YM+IiOC5s6fMnQ06T0+en7hwQVLaojnpS5JXLFuYk52Wn7e8cH1WWUl+deW6 + ho2lTZsrdu2o27u74eD+piOHth/n6Xxq/9kzB86fPfhsMRqVARQ5PXw8Zi6fufXa1seyGF+w9fOtA24M + sDlvw5wycmsTUWYGA1xG5RM1OaoW0UXogivQhc/Vi9WKXoqEhAQUjHjLTGYOSwWfAZLNoKuhhQUNvmzU + yXnlH2zyfiCjczKTRw7vZ+9iO37+2MpjGzpisUCpZ91Mcj3tLN8vlW2VSOvF0hqxtFIirZBIOUVmUS6R + loilhWLparEkm+PyCkvJMkueyEaMlsxlXA4PC5g9a/Kc2VOhzkyaFyQuSoU0z1uWkZKVuTgvd+m6NStL + inIrNxTUQpoby7cxad64b++mQwe2Hj28A3Q+eXzPqVPNZ07tgzqfO3vwmWA0SjDoH/sE+cxeOXvLpS2d + YTG+BjYZRLY9b4vE2uAuNrfOR/iyJwwGVfE7rHyyWn4K02VMJROXhYkJVTNoUoBKoEKb8VPnJm0nLJ10 + HUXrMhKnjw4P8/Pv5Ts7a2bjpfpTd4+3hIm7aO03JrwyjinyPk6RDUQWSyvE0g1iKSiMgMGAKMNgrBVL + c2EwIMqWkuWWkqXgMsUjdTY8T7Q01/eIjAyZPXMy0Xn+3OkLkmcsTJkJaV4Gm7EydVV2+prVKwrXZ28o + y6+pWt9YX9K0uXLndibNB/ZtPnJo29HD208cY3SG2Th9qvns6f2/JKPhOtGWt7W3RcMpf1P+yd+f7CSL + 8WWrPlzFrMXZ1oosTKxRwheK8roWUW6/V8JKzDNV8MuY/xR6DJpAJC6jZkQNQPzwKIFSnk1b/IQ2g6qg + nd/k8IMFmhWV2mP0soyZSK78fT38wn2mp08pP1J68u5xYXTM6JL3iqIvRqmOKWS7JbItsBZiaTUUuYXI + jMssJLxTNhZlnsvGjBaPs+jp0j02NnJm0iTQmbMZUxfMn56aMnPxotkZ6fNXLIfNWLI6f+n6tbAZeVWV + a+s3FsM179hWvXvnxv3Nmzmnse3YkZ2g86kTe06d2At1PnN638/KaJQNYSQgfAERAdMWTSveW3z23tnO + UxhfuevertG3RrPOyDFr6+aWwgX1rQWtawOR0fEra6ksI+vLa7dRYmiXjGV1DMwkGnEZHsOIy1TOB5dR + aCbLTNtVhd2pn4fLj2od2ZnzUAeI7Rvm5mrvG+o9bl5C3uZV+99pNhQoWhOZJ7Upo7d93DTq2gjIMfMV + 2yTSRrG0ViytEhCZYzEjcqmlpMRSsl4sKWjtLh6JchuMthxg3kNlFh/Xf2bSxFkzJ0Ga586Zkjxv+sKU + RMblJfNWLk/Jzlycn7d03drM0uJVlVwGuKmhbFtT1c4ddc17IM1IArfCOB87suPk8d2I0yf3smzwZ2A0 + NsJ5+HrETYpLK0zbeGbjY+vFbbJ77xd7J92epLussznJFTlRSoZBFvqKlnzvUVO1vKV4/zinzAxGhhpV + fNSX0foT1jEo9yO/TAOfNCpnxGXTTuvPyWUDo1GUaH5rT0fVtQ4ZXfF++ZArgxxO2Mn2S2TbxYzFda1Z + 3CLHBiIXg8iWkgJLsdAmZxjxt9UfxTMszf17BAbop0waxXF54pxZk+cxLk9buCBxcSq4PHfFMuJyxlpY + 5uKcivKC2ur1jSwDrIQ0t7hmRmc4jeNHeXWG3/i5GP1E+iv84oI7BZiEY509aDGKyB2yuJUiUxeqE0Sm + Hja6q3zfjzbqoPWHphS1Syj3w9gnHTzSJpf5ytxT3Bn1pA5E9NhisZHZ2PHRtmmvTPE56y0/KpXuFku3 + iKX1ltJaS6bFZI0pWuSYERlyDCKvs5SsBpEtxJkW4hWWYuR7HRIZ9tkCoqwxGzQwOmnG+KTE8QYuz52S + PH86ShmLU2cxLi9Nyc5q4XJRzoay1bXVqGaUbNm8YXtT1a6dTJoP7t986ACchoHOYDTUmfMbzySj8+7k + DX11qMclD5tTzBezBG8bNzoER8FbY4EWG+QYnREqXNAABqxFh7ULwwQXsr5oBaZeeFGmm5747TqoL2Ns + ATU5dLJpyIg/eER4JMazwGWDRj+W0flv5Q7DxcGnXGRHJIzCTWJJvSX6INIqS2mFpXQDF+WI1iwmX1Fo + KVljKcmzZCxeCSJbiJdZiDMsxEssERKEIfFr9cRytHlPt+4RYQHTpiYkzRhn4PLsSfPAZYPHmJWRPo/p + ctai/NwMrpSRXVEOLq+tryvewgrNVbt21DbvbtjfvAl0PnyQjDMzG/DOXDb4bDD6zLdnVt9ZDTvsf8Wf + VdqOClTYlMKtWfxIjuErULXAVBw/F9DOMBFfjWPuYrBSZivDoDjvlIWijMEXMhjUxkZ9mT9zi06DotzP + dJrrSSe4nlSCH/v1rTS69L3i6TemRpwPtT9hKzvcwt8GS0mtpaS6pZW3gevmMQpzUdbyBIwu4+S4iJPj + fF6OLcTLLcRLwWJhtMFoy/HmPb17BAR4j00YNmN6QuL0sTOZLk+YM3vy/DlTFyQj90tasnj20vR5K1cs + XJW9eHUecr8VJUWrKjasrmG6DC7DMleCy3t31+/b23CA0RlOo+noYVbWOH4UhTrmN34ZRpd9Ujb3rbnw + D75XfNkA8nFrpr97uYwOXrhN/oLC7bEYtbeSljoyZXooJbcz4dmKyEOVmJDDcUBEZOE2YMr6+IMQ6axJ + MhiYMKJZcTpzy/R4l6e+L/ixzG23Zyg7LJbuEUthgdGBJvJWCcjbwl9isSG45jTjMp6UWhi0eC2nxQZT + 0cLidCMi8398xGjLBPOeuu5+vl6jRw6ePm0MuAxdnpk0fs6siVziNy1lwYzFqTOXpM1ZvjQ5c+XCVTlp + BfnLCtdxud+G/NoqA5e3bqnYuZ1Z5uY9aANuOrBv0+EDTVweuJXU+RdmdBvMpYqEaXDDsnywPgg5ChQr + YI1JizvNYiooI9+T2cjopj1TItO5qej4wSnTHjQ6CBGz4uhhYyKfihg0yGx65tZPuin4SaktkoCzbdLW + hMI0ZcGVKSwkRRaSdRaSAjZrwRwFAkJMjqJdFgvYnWZpMbhnD0ez4CCfcQnDGJGnjeFEedxsiPIsZjAW + zJ+WujAxbREzGCuXL8jOhMFIX1uwvGh9ZlkJ2iXMLzfWF29phC6jAQguo9BMBQ20TrYgjjA6Q50NfuOX + ZnSb5DVVYeqAEIVhJ3gh5h1F+209o3Yfkj1FiALnNGAzpZG14O/p5ImM8gV/bip/ECJEuTMnmz0p6X7S + rxe1El9iMTG3JdigULGFuIibFVptIc4xF2dyAVNMdqIzFOYsh+Vk854h3buLu8VEh06dMmra1NHgciJE + OXHcrMTxs2dOnDdncvL8qakpMxalzkyHKC9LzlqxMJeJcgZnMJD45VZXFtTVol1CHqNiJ6sy13BchjQz + OpNxZt75GWW0qQTTZEUFy+vYMDKvwjQs2wk78chXzOPk2F6GPX7Yd8bLsfA8dlgLOiycTrIWHgAsPDe1 + Y1F+pnRZ+BYRteJvqaWBvDTrlm9hucrcMtOcTbytMBcvNxcvMxdnmIvTzcVp5q19cXvuwsIy0dy8d4/u + Vt0CA71HjhwwdTKIPGr61NEzpo9J4pwyRHnunEnJ86YsTJ6+aGFSetrs5UvhlBesyl6Un7dkbcEyTpRz + KpjBQOJXuKmhuGlz+fat8BhI/2ogzc170DdBEth4YF8jV9Zg3vnZYzSJL09eWAjoL/Xu+NIE2eHH5XVG + WoxJOOUApcxZhjNzsLuPWCy8nJo/ZATJHgbjcEIDv72dTrLmiUzlC6NzU5/KaVA/qS63YrR4nYUY5iHP + wjKHYy5HXjaxSUObGeaW6YahTcZiYbTK9Fox2mJiz57h3buru/n7ecUN6ztl0oipk0dOmzJqBog8LSFx + BucuZk2YByLPn7pwwfRFqSDyrGUZczOXp+Rkpebnpq0pWFq4bmVpcVZFWW5V5eqNNej7FW5uQBubcXnH + tiroMknzvj1IAuvBZU6dmUA/o4w2MJfMAy++IO/j0rk2R4dUk1WYG5JZyXAAKXrnbbIYdWT0RIR3N/AX + C9D2a9rhzh9NKyQybakUdq+fWVE2eq+IGG155raQt83R4w4YbTnb3HxAj+7u3RwcrCPC/MeMHDR50nCe + yFDkRCjyjLGzZ46bM3vivLmTFoDIKTPSQOQls5dlcIqctTAvJ23t6qXr1y0vKcoqL82pgihXr9lYC7Nc + tKWxdOuW8u1N4DJKGQabwei8t37/XqgzzMazz+gfxFyezhivV/ZlQoxrnnDsE09hOrCMv+GFDtQiFtOt + AuiJ0GkjGCOioxroHAHyyGQt+NoFT2S0SJ6d8sUT6buoTfI+ltEWU3v27NO9u2u3bt26BAV6DxvaZ9L4 + +MkT4idPHDFl8ohpU0bCWsyYNjpxxphZSePmzBo/b/ak+XOnLFwwbdHCGUsWJ2UsYdYia0XyqmxekZcX + F2aWl6J8kVdTVVBXs7YRotxY0rSJuIypjMpd25k079lFrhk1DczPPUeMbmdKs00JhpHAbidFoEKmYefI + 4igiYWpHFKZ7oCDE8MX8PUX8PTp0szpqb5hTFsoxqha0yZ0/R0B4JPvzS2Se9Z1itMXEHoy/7t3MLLt6 + eTpHRwWPGTVw4vi4iRPiJk2IY3I8eThYPGMaY3FSYsKspLGzZ42fO3vi/LmTU5KnpKZMX7KIM8gZc1cu + n5+dmZKbvWh13pJ1azIK1yHfA5FzKjesqq5YXVe9pmHj+s0NRVs2FYPL25qIyxXg8q4dVXsYnVFrRvyK + GK1OVavGqZR9lHJPOXp3dA4ynckJ/SUJ5o+SpTMjicL8yXB0chnm7FE+RiuEtBiFNzIVqL1h3z3JMfkK + tEXoKIE297k/kSA+g1/citEWST3Nh3fvGWEG8TUTd3VysgkM0PXvFzF+7JAJ44ZOHD904oRhkybGTWmh + 8PSpjMUQ4pkzwGJOi+dMTJ43KSV56qKF09NSEzl3PHvl8nlZK5Hppa7OXbxmdfq6NUuL168oLc6sKAOR + c2sqV9fVrKmv40SZ4/LWzdDlsu1N5eDyTtB5R9Vu5jSqn29Gwzao4pj5ZcxVSR97DjJ/LCfPX8rroMLo + SROF6XA4OryMvw0KrRA6+cmIxXQJCX9DhtGBDc8gN3/YjySytVZ7ejiFhuj79wtPGDVwPLcxz0Be8HcC + +BsPCZ46efj0qSOmc14iCRROTIApxp69eXMmcBRmjmJxKuco0mcuXzoHLM5mLF64OndRQX4aJ8fLS4tW + lpdkbSjDHi9Yi3yOyOsaN8IpF25phFkuAZe3NTEub99aDi7v3A6nAeP8q2A06md0ayR/wjR/fSR/Wq/w + HGQ69pRO5qTDDenkSFJhnsK8EMMXo1JBh2uRNeav0hG6Y35O+XnJ9J6U16KJE4ZOmjAMe0snM/GNnzqJ + kXfaFJCX09/p4O9ojr9j58waN2/O+OR5ExfMIy8xLS11evriRFAYQrxi2dyslfNzshbk5izMz11csDpt + XUFG0bplJUWQ45UbSjF3AV+RV1sFRS6or2WivKl+/SaIcmNR02ZwmdGZuLxjK5zGhl8bo5GzQW07fw4y + HXuKiU3iL2psdP4emni8CmO+gg405C/covO1yFHwV+n86lncqno3Y9rIxOmIUTNxunsSErmEObPGzp09 + bh7pL6tLTF64APydmrZo+pLFM9KXJC1Ln7Vi6ZxM5iXm5WQlrwKFV6UW5IHCS9avzShav7S4cHlpCViM + 2hvkGNts2b7auurVIHJD3dqGjevA5c2NnC4zj1GydUvpNhYGdf51Mhpu94nOQUaNGEUJHPJE50eSBJOR + 4I/gEx4VKRTiX6uj6Ixei+bPhW2YsGD+xJTkSakLJi9aOGXxwhbypiUuTZ+1fOmsFctmZy6fmw3+ZoK/ + KXmrmJdYw1Q4bf2a9MJ18MXLSgpXlBGLyxmLq9l+cShy3sYaVJMLGurWwF1sqmdc3tSwnuNyURPSP1Ln + fwVGP+k5yMKjeukISTo/kr+TT6jC/8oUNq5HL12SuCwjaXnGzBVLZ61chiwO4suRF+KbvSA3OyU/d+Hq + vNQ1+YvWrl7MqfAS7DksXr+0tGh5WTF88coNZVmV5YgcdvZBRW4NTj2AItfk19fCXTAuI4jLmxsQqMmR + Ov+LMfpJz0EW6q/QRfAdvH8pL9EZdTbMR+OomLyc5LxVC3AQy+rchQV58A+pHHmhv0yCib/FhcvKikHh + FeXsxBqc6YEDPcBi7hwPw/EdhlM7DFyuM3C5cSOKGLDM//KMplt7O38OstGxp8IDTzv/8v4LfqVoHaNt + WuHaJYiidenF6zOKuXOFuGAsxulCTIhL6ViarMoNWZwWG86hYUfRCE6gYR6jFn65oP7fjDY6geZJz0H+ + xUfnn9N3g6ikcCmCKMyRlwU2iLecr0SHKzFf0Zkzlf7N6HbPVGrveOlfaxXtl3pDiHgKC1j8w08J+zej + f/JTwn4ppjwv/98feKZSe+fe/ZvR/2b0L0z9fzP65zrd4Bd+of9l/vf/ZvS/Gf3rIvu/Gf1vRv+6GP3/ + AZ+4Ui+mkTlKAAAAAElFTkSuQmCC + + + \ No newline at end of file diff --git a/Unity Studio/AssetPreloadData.cs b/Unity Studio/AssetPreloadData.cs new file mode 100644 index 0000000..2e0978c --- /dev/null +++ b/Unity Studio/AssetPreloadData.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Unity_Studio +{ + public class AssetPreloadData : ListViewItem + { + public long m_PathID; + public int Offset; + public int Size; + public int Type1; + public ushort Type2; + + //public string m_Name = ""; + public string TypeString; + public int exportSize; + public string InfoText; + + public AssetsFile sourceFile; + public int specificIndex = -1; //index in specific asset list + public string uniqueID; + } +} diff --git a/Unity Studio/AssetsFile.cs b/Unity Studio/AssetsFile.cs new file mode 100644 index 0000000..a594a11 --- /dev/null +++ b/Unity Studio/AssetsFile.cs @@ -0,0 +1,319 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Diagnostics; //remove this later + +namespace Unity_Studio +{ + public class AssetsFile + { + public EndianStream a_Stream; + public string filePath; + public int fileGen; + public string m_Version = "2.5.0f5"; + public int[] version = new int[4] { 0, 0, 0, 0 }; + public string[] buildType; + public int platform = 100663296; + //public EndianType endianType = EndianType.BigEndian; + //public List preloadTable = new List(); + public Dictionary preloadTable = new Dictionary(); + public List GameObjectList = new List(); + public List TransformList = new List(); + //public List RectTransformList = new List(); + //public List MeshFilterList = new List(); + //public List SkinnedMeshList = new List(); + public List exportableAssets = new List(); + public List sharedAssetsList = new List() {new UnityShared()}; + private ClassIDReference UnityClassID = new ClassIDReference(); + + private bool baseDefinitions = false; + + public class UnityShared + { + public int Index = -1; //actual index in main list + public string aName = ""; + public string fileName = ""; + } + + public AssetsFile(string fileName, EndianStream fileStream) + { + //if (memFile != null) { Stream = new EndianStream(memFile, endianType); } + //else { Stream = new EndianStream(File.OpenRead(fileName), endianType); } + a_Stream = fileStream; + + filePath = fileName; + int tableSize = a_Stream.ReadInt32(); + int dataEnd = a_Stream.ReadInt32(); + fileGen = a_Stream.ReadInt32(); + int dataOffset = a_Stream.ReadInt32(); + sharedAssetsList[0].fileName = Path.GetFileName(fileName); //reference itself because sharedFileIDs start from 1 + + switch (fileGen) + { + case 6: + { + a_Stream.Position = (dataEnd - tableSize); + a_Stream.Position += 1; + break; + } + case 7://beta + { + a_Stream.Position = (dataEnd - tableSize); + a_Stream.Position += 1; + m_Version = a_Stream.ReadStringToNull(); + break; + } + case 8: + { + a_Stream.Position = (dataEnd - tableSize); + a_Stream.Position += 1; + m_Version = a_Stream.ReadStringToNull(); + platform = a_Stream.ReadInt32(); + break; + } + case 9: + { + a_Stream.Position += 4;//azero + m_Version = a_Stream.ReadStringToNull(); + platform = a_Stream.ReadInt32(); + break; + } + case 14: + case 15://not fully tested!s + { + a_Stream.Position += 4;//azero + m_Version = a_Stream.ReadStringToNull(); + platform = a_Stream.ReadInt32(); + baseDefinitions = a_Stream.ReadBoolean(); + break; + } + default: + { + //MessageBox.Show("Unsupported Unity version!", "Unity Studio Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + } + + if (platform > 255 || platform < 0) + { + byte[] b32 = BitConverter.GetBytes(platform); + Array.Reverse(b32); + platform = BitConverter.ToInt32(b32, 0); + //endianType = EndianType.LittleEndian; + a_Stream.endian = EndianType.LittleEndian; + } + + /*Platform list: + -2: unitypackage + 4: OSX + 5: PC + 6: Web + 7: Web_streamed + 9: iOS + 10: PS3(big) + 11: Xbox360(big) + 13: Android + 16: Google_NaCl + 21: WP8 + 25: Linux + */ + + int baseCount = a_Stream.ReadInt32(); + for (int i = 0; i < baseCount; i++) + { + if (fileGen < 14) + { + int baseType = a_Stream.ReadInt32(); + readBase(); + } + else { readBase5(); } + } + + if (fileGen >= 7 && fileGen < 14) {a_Stream.Position += 4;}//azero + + int assetCount = a_Stream.ReadInt32(); + if (fileGen >= 14) { a_Stream.AlignStream(4); } + + string assetIDfmt = "D" + assetCount.ToString().Length.ToString(); //format for unique ID + + for (int i = 0; i < assetCount; i++) + { + AssetPreloadData asset = new AssetPreloadData(); + if (fileGen < 14) { asset.m_PathID = a_Stream.ReadInt32(); } + else { asset.m_PathID = a_Stream.ReadInt64(); } + asset.Offset = a_Stream.ReadInt32(); + asset.Offset += dataOffset; + asset.Size = a_Stream.ReadInt32(); + asset.Type1 = a_Stream.ReadInt32(); + asset.Type2 = a_Stream.ReadUInt16(); + a_Stream.Position += 2; + if (fileGen >= 15) { int azero = a_Stream.ReadInt32(); } + + asset.TypeString = asset.Type2.ToString(); + if (UnityClassID.Names[asset.Type2] != null) + { + asset.TypeString = UnityClassID.Names[asset.Type2]; + } + + asset.uniqueID = i.ToString(assetIDfmt); + + asset.exportSize = asset.Size; + asset.sourceFile = this; + + preloadTable.Add(asset.m_PathID, asset); + + //this should be among the first nodes in mainData and it contains the version - useful for unity 2.x files + if (asset.Type2 == 141 && fileGen == 6) + { + long nextAsset = a_Stream.Position; + + BuildSettings BSettings = new BuildSettings(asset); + m_Version = BSettings.m_Version; + + a_Stream.Position = nextAsset; + } + } + + buildType = m_Version.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); + string[] strver = (m_Version.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)); + version = Array.ConvertAll(strver, int.Parse); + + if (fileGen >= 14) + { + int someCount = a_Stream.ReadInt32(); + a_Stream.Position += someCount * 12; + } + + int sharedFileCount = a_Stream.ReadInt32(); + for (int i = 0; i < sharedFileCount; i++) + { + UnityShared shared = new UnityShared(); + shared.aName = a_Stream.ReadStringToNull(); + a_Stream.Position += 20; + string sharedFileName = a_Stream.ReadStringToNull(); //relative path + shared.fileName = sharedFileName.Replace("/", "\\"); + sharedAssetsList.Add(shared); + } + } + + private void readBase() + { + string baseFormat = a_Stream.ReadStringToNull(); + string baseName = a_Stream.ReadStringToNull(); + a_Stream.Position += 20; + int childrenCount = a_Stream.ReadInt32(); + //Debug.WriteLine(baseFormat + " " + baseName + " " + childrenCount); + for (int i = 0; i < childrenCount; i++) { readBase(); } + } + + private void readBase5() + { + int baseType = a_Stream.ReadInt32(); + if (baseType < 0) { a_Stream.Position += 16; } + a_Stream.Position += 16; + + if (baseDefinitions) + { + #region cmmon string array + string[] baseStrings = new string[1007]; + baseStrings[0] = "AABB"; + baseStrings[5] = "AnimationClip"; + baseStrings[19] = "AnimationCurve"; + baseStrings[49] = "Array"; + baseStrings[55] = "Base"; + baseStrings[60] = "BitField"; + baseStrings[76] = "bool"; + baseStrings[81] = "char"; + baseStrings[86] = "ColorRGBA"; + baseStrings[106] = "data"; + baseStrings[138] = "FastPropertyName"; + baseStrings[155] = "first"; + baseStrings[161] = "float"; + baseStrings[167] = "Font"; + baseStrings[172] = "GameObject"; + baseStrings[183] = "Generic Mono"; + baseStrings[208] = "GUID"; + baseStrings[222] = "int"; + baseStrings[241] = "map"; + baseStrings[245] = "Matrix4x4f"; + baseStrings[262] = "NavMeshSettings"; + baseStrings[263] = "MonoBehaviour"; + baseStrings[277] = "MonoScript"; + baseStrings[299] = "m_Curve"; + baseStrings[349] = "m_Enabled"; + baseStrings[374] = "m_GameObject"; + baseStrings[427] = "m_Name"; + baseStrings[490] = "m_Script"; + baseStrings[519] = "m_Type"; + baseStrings[526] = "m_Version"; + baseStrings[543] = "pair"; + baseStrings[548] = "PPtr"; + baseStrings[564] = "PPtr"; + baseStrings[581] = "PPtr"; + baseStrings[616] = "PPtr"; + baseStrings[633] = "PPtr"; + baseStrings[688] = "PPtr"; + baseStrings[702] = "PPtr"; + baseStrings[718] = "PPtr"; + baseStrings[741] = "Quaternionf"; + baseStrings[753] = "Rectf"; + baseStrings[778] = "second"; + baseStrings[795] = "size"; + baseStrings[800] = "SInt16"; + baseStrings[814] = "int64"; + baseStrings[840] = "string"; + baseStrings[874] = "Texture2D"; + baseStrings[884] = "Transform"; + baseStrings[894] = "TypelessData"; + baseStrings[907] = "UInt16"; + baseStrings[928] = "UInt8"; + baseStrings[934] = "unsigned int"; + baseStrings[981] = "vector"; + baseStrings[988] = "Vector2f"; + baseStrings[997] = "Vector3f"; + baseStrings[1006] = "Vector4f"; + #endregion + + int varCount = a_Stream.ReadInt32(); + int stringSize = a_Stream.ReadInt32(); + + a_Stream.Position += varCount * 24; + string varStrings = Encoding.UTF8.GetString(a_Stream.ReadBytes(stringSize)); + + //can skip this + a_Stream.Position -= varCount * 24 + stringSize; + for (int i = 0; i < varCount; i++) + { + ushort num0 = a_Stream.ReadUInt16(); + byte level = a_Stream.ReadByte(); + bool isArray = a_Stream.ReadBoolean(); + + ushort varTypeIndex = a_Stream.ReadUInt16(); + ushort test = a_Stream.ReadUInt16(); + string varTypeStr; + if (test == 0) //varType is an offset in the string block + { varTypeStr = varStrings.Substring(varTypeIndex, varStrings.IndexOf('\0', varTypeIndex) - varTypeIndex); }//substringToNull + else //varType is an index in an internal strig array + { varTypeStr = baseStrings[varTypeIndex] != null ? baseStrings[varTypeIndex] : varTypeIndex.ToString(); } + + ushort varNameIndex = a_Stream.ReadUInt16(); + test = a_Stream.ReadUInt16(); + string varNameStr; + if (test == 0) { varNameStr = varStrings.Substring(varNameIndex, varStrings.IndexOf('\0', varNameIndex) - varNameIndex); } + else { varNameStr = baseStrings[varNameIndex] != null ? baseStrings[varNameIndex] : varNameIndex.ToString(); } + + int size = a_Stream.ReadInt32(); + int index = a_Stream.ReadInt32(); + int num1 = a_Stream.ReadInt32(); + + for (int t = 0; t < level; t++) { Debug.Write("\t"); } + Debug.WriteLine(varTypeStr + " " + varNameStr + " " + size); + } + a_Stream.Position += stringSize; + } + } + + } +} diff --git a/Unity Studio/AudioClip.cs b/Unity Studio/AudioClip.cs new file mode 100644 index 0000000..67854fb --- /dev/null +++ b/Unity Studio/AudioClip.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class AudioClip + { + public string m_Name; + public int m_Format = 0; + public int m_Type; + public bool m_3D; + public bool m_UseHardware; + + //Unity 5 + public int m_LoadType; + public int m_Channels; + public int m_Frequency; + public int m_BitsPerSample; + public float m_Length; + public bool m_IsTrackerFormat; + public int m_SubsoundIndex; + public bool m_PreloadAudioData; + public bool m_LoadInBackground; + public bool m_Legacy3D; + public int m_CompressionFormat; + + public string m_Source; + public long m_Offset; + public long m_Size; + public byte[] m_AudioData; + + public string extension; + + public AudioClip(AssetPreloadData preloadData, bool readSwitch) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + + if (sourceFile.version[0] < 5) + { + + m_Format = a_Stream.ReadInt32(); //channels? + m_Type = a_Stream.ReadInt32(); + m_3D = a_Stream.ReadBoolean(); + m_UseHardware = a_Stream.ReadBoolean(); + a_Stream.Position += 2; //4 byte alignment + + if (sourceFile.version[0] >= 4 || (sourceFile.version[0] == 3 && sourceFile.version[1] >= 2)) //3.2.0 to 5 + { + int m_Stream = a_Stream.ReadInt32(); + m_Size = a_Stream.ReadInt32(); + + if (m_Stream > 1) + { + m_Offset = a_Stream.ReadInt32(); + m_Source = sourceFile.filePath + ".resS"; + } + } + else { m_Size = a_Stream.ReadInt32(); } + } + else + { + m_LoadType = a_Stream.ReadInt32(); + m_Type = m_LoadType; + m_Channels = a_Stream.ReadInt32(); + m_Frequency = a_Stream.ReadInt32(); + m_BitsPerSample = a_Stream.ReadInt32(); + m_Length = a_Stream.ReadSingle(); + m_IsTrackerFormat = a_Stream.ReadBoolean(); + a_Stream.Position += 3; + m_SubsoundIndex = a_Stream.ReadInt32(); + m_PreloadAudioData = a_Stream.ReadBoolean(); + m_LoadInBackground = a_Stream.ReadBoolean(); + m_Legacy3D = a_Stream.ReadBoolean(); + a_Stream.Position += 1; + m_3D = m_Legacy3D; + + m_Source = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + //m_Source = Path.GetFileName(m_Source); + m_Source = Path.Combine(Path.GetDirectoryName(sourceFile.filePath), m_Source.Replace("archive:/","")); + m_Offset = a_Stream.ReadInt64(); + m_Size = a_Stream.ReadInt64(); + m_CompressionFormat = a_Stream.ReadInt32(); + } + + #region Info Text & extension + preloadData.InfoText = "Format: " + m_Format + "\nType: "; + + switch (m_Type) + { + case 1: + extension = ".fsb"; + preloadData.InfoText += "FSB"; + break; + case 13: + extension = ".mp3"; + preloadData.InfoText += "MP3"; + break; + case 14: + extension = ".ogg"; + preloadData.InfoText += "Ogg Vorbis"; + break; + case 20: + extension = ".wav"; + preloadData.InfoText += "WAV"; + break; + case 22: //xbox encoding + extension = ".wav"; + preloadData.InfoText += "Xbox360 WAV"; + break; + default: + preloadData.InfoText += "Unknown type " + m_Type; + break; + } + + preloadData.InfoText += "\n3D: " + m_3D.ToString(); + #endregion + + if (readSwitch) + { + m_AudioData = new byte[m_Size]; + + if (m_Source == null) + { + a_Stream.Read(m_AudioData, 0, (int)m_Size); + } + else if (File.Exists(m_Source)) + { + using (BinaryReader reader = new BinaryReader(File.OpenRead(m_Source))) + { + reader.BaseStream.Position = m_Offset; + reader.Read(m_AudioData, 0, (int)m_Size); + reader.Close(); + } + } + } + } + } +} diff --git a/Unity Studio/BuildSettings.cs b/Unity Studio/BuildSettings.cs new file mode 100644 index 0000000..ffd7d5a --- /dev/null +++ b/Unity Studio/BuildSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class BuildSettings + { + public string m_Version; + + public BuildSettings(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + int levels = a_Stream.ReadInt32(); + for (int l = 0; l < levels; l++) { string level = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); } + + if (sourceFile.version[0] == 5) + { + int preloadedPlugins = a_Stream.ReadInt32(); + for (int l = 0; l < preloadedPlugins; l++) { string preloadedPlugin = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); } + } + + a_Stream.Position += 4; //bool flags + if (sourceFile.fileGen >= 8) { a_Stream.Position += 4; } //bool flags + if (sourceFile.fileGen >= 9) { a_Stream.Position += 4; } //bool flags + if (sourceFile.version[0] == 5 || + (sourceFile.version[0] == 4 && (sourceFile.version[1] >= 3 || + (sourceFile.version[1] == 2 && sourceFile.buildType[0] != "a")))) + { a_Stream.Position += 4; } //bool flags + + m_Version = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + } + } +} diff --git a/Unity Studio/BundleFile.cs b/Unity Studio/BundleFile.cs new file mode 100644 index 0000000..a91fdd2 --- /dev/null +++ b/Unity Studio/BundleFile.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using SevenZip; +using Lz4; + +namespace Unity_Studio +{ + public class BundleFile : IDisposable + { + private EndianStream Stream; + public byte ver1; + public string ver2; + public string ver3; + public List MemoryAssetsFileList = new List(); + + public class MemoryAssetsFile + { + public string fileName; + public MemoryStream memStream; + } + + public BundleFile(string fileName) + { + if (Path.GetExtension(fileName) == ".lz4") + { + byte[] filebuffer; + + using (BinaryReader lz4Stream = new BinaryReader(File.OpenRead(fileName))) + { + int version = lz4Stream.ReadInt32(); + int uncompressedSize = lz4Stream.ReadInt32(); + int compressedSize = lz4Stream.ReadInt32(); + int something = lz4Stream.ReadInt32(); //1 + + byte[] lz4buffer = new byte[compressedSize]; + lz4Stream.Read(lz4buffer, 0, compressedSize); + + using (var inputStream = new MemoryStream(lz4buffer)) + { + var decoder = new Lz4DecoderStream(inputStream); + + filebuffer = new byte[uncompressedSize]; //is this ok? + for (;;) + { + int nRead = decoder.Read(filebuffer, 0, uncompressedSize); + if (nRead == 0) + break; + } + } + } + + Stream = new EndianStream(new MemoryStream(filebuffer), EndianType.BigEndian); + } + else { Stream = new EndianStream(File.OpenRead(fileName), EndianType.BigEndian); } + + long magicHeader = Stream.ReadInt64(); + + if (magicHeader == -361700864190383366 || magicHeader == 6155973689634940258 || magicHeader == 6155973689634611575) + { + int dummy = Stream.ReadInt32(); + ver1 = Stream.ReadByte(); + ver2 = Stream.ReadStringToNull(); + ver3 = Stream.ReadStringToNull(); + int lzmaSize = 0; + int fileSize = Stream.ReadInt32(); + short dummy2 = Stream.ReadInt16(); + int offset = Stream.ReadInt16(); + int dummy3 = Stream.ReadInt32(); + int lzmaChunks = Stream.ReadInt32(); + + for (int i = 0; i < lzmaChunks; i++) + { + lzmaSize = Stream.ReadInt32(); + fileSize = Stream.ReadInt32(); + } + + Stream.Position = offset; + switch (magicHeader) + { + case -361700864190383366: //.bytes + case 6155973689634940258: //UnityWeb + { + byte[] lzmaBuffer = new byte[lzmaSize]; + Stream.Read(lzmaBuffer, 0, lzmaSize); + Stream.Close(); + Stream.Dispose(); + + Stream = new EndianStream(SevenZip.Compression.LZMA.SevenZipHelper.StreamDecompress(new MemoryStream(lzmaBuffer)), EndianType.BigEndian); + offset = 0; + break; + } + case 6155973689634611575: //UnityRaw + { + + break; + } + } + + int fileCount = Stream.ReadInt32(); + for (int i = 0; i < fileCount; i++) + { + MemoryAssetsFile memFile = new MemoryAssetsFile(); + memFile.fileName = Stream.ReadStringToNull(); + int fileOffset = Stream.ReadInt32(); + fileOffset += offset; + fileSize = Stream.ReadInt32(); + long nextFile = Stream.Position; + Stream.Position = fileOffset; + + byte[] buffer = new byte[fileSize]; + Stream.Read(buffer, 0, fileSize); + memFile.memStream = new MemoryStream(buffer); + MemoryAssetsFileList.Add(memFile); + Stream.Position = nextFile; + } + } + + Stream.Close(); + } + + ~BundleFile() + { + Dispose(); + } + + public void Dispose() + { + Stream.Dispose(); + GC.SuppressFinalize(this); + } + } +} diff --git a/Unity Studio/ClassIDReference.cs b/Unity Studio/ClassIDReference.cs new file mode 100644 index 0000000..9dba6ec --- /dev/null +++ b/Unity Studio/ClassIDReference.cs @@ -0,0 +1,252 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class ClassIDReference + { + public string[] Names = new string[1121]; + + public ClassIDReference() + { + Names[1] = "GameObject"; + Names[2] = "Component"; + Names[3] = "LevelGameManager"; + Names[4] = "Transform"; + Names[5] = "TimeManager"; + Names[6] = "GlobalGameManager"; + Names[8] = "Behaviour"; + Names[9] = "GameManager"; + Names[11] = "AudioManager"; + Names[12] = "ParticleAnimator"; + Names[13] = "InputManager"; + Names[15] = "EllipsoidParticleEmitter"; + Names[17] = "Pipeline"; + Names[18] = "EditorExtension"; + Names[19] = "Physics2DSettings"; + Names[20] = "Camera"; + Names[21] = "Material"; + Names[23] = "MeshRenderer"; + Names[25] = "Renderer"; + Names[26] = "ParticleRenderer"; + Names[27] = "Texture"; + Names[28] = "Texture2D"; + Names[29] = "SceneSettings"; + Names[30] = "GraphicsSettings"; + Names[33] = "MeshFilter"; + Names[41] = "OcclusionPortal"; + Names[43] = "Mesh"; + Names[45] = "Skybox"; + Names[47] = "QualitySettings"; + Names[48] = "Shader"; + Names[49] = "TextAsset"; + Names[50] = "Rigidbody2D"; + Names[51] = "Physics2DManager"; + Names[53] = "Collider2D"; + Names[54] = "Rigidbody"; + Names[55] = "PhysicsManager"; + Names[56] = "Collider"; + Names[57] = "Joint"; + Names[58] = "CircleCollider2D"; + Names[59] = "HingeJoint"; + Names[60] = "PolygonCollider2D"; + Names[61] = "BoxCollider2D"; + Names[62] = "PhysicsMaterial2D"; + Names[64] = "MeshCollider"; + Names[65] = "BoxCollider"; + Names[66] = "SpriteCollider2D"; + Names[68] = "EdgeCollider2D"; + Names[72] = "ComputeShader"; + Names[74] = "AnimationClip"; + Names[75] = "ConstantForce"; + Names[76] = "WorldParticleCollider"; + Names[78] = "TagManager"; + Names[81] = "AudioListener"; + Names[82] = "AudioSource"; + Names[83] = "AudioClip"; + Names[84] = "RenderTexture"; + Names[87] = "MeshParticleEmitter"; + Names[88] = "ParticleEmitter"; + Names[89] = "Cubemap"; + Names[90] = "Avatar"; + Names[91] = "AnimatorController"; + Names[92] = "GUILayer"; + Names[93] = "RuntimeAnimatorController"; + Names[94] = "ScriptMapper"; + Names[95] = "Animator"; + Names[96] = "TrailRenderer"; + Names[98] = "DelayedCallManager"; + Names[102] = "TextMesh"; + Names[104] = "RenderSettings"; + Names[108] = "Light"; + Names[109] = "CGProgram"; + Names[110] = "BaseAnimationTrack"; + Names[111] = "Animation"; + Names[114] = "MonoBehaviour"; + Names[115] = "MonoScript"; + Names[116] = "MonoManager"; + Names[117] = "Texture3D"; + Names[118] = "NewAnimationTrack"; + Names[119] = "Projector"; + Names[120] = "LineRenderer"; + Names[121] = "Flare"; + Names[122] = "Halo"; + Names[123] = "LensFlare"; + Names[124] = "FlareLayer"; + Names[125] = "HaloLayer"; + Names[126] = "NavMeshAreas"; + Names[127] = "HaloManager"; + Names[128] = "Font"; + Names[129] = "PlayerSettings"; + Names[130] = "NamedObject"; + Names[131] = "GUITexture"; + Names[132] = "GUIText"; + Names[133] = "GUIElement"; + Names[134] = "PhysicMaterial"; + Names[135] = "SphereCollider"; + Names[136] = "CapsuleCollider"; + Names[137] = "SkinnedMeshRenderer"; + Names[138] = "FixedJoint"; + Names[140] = "RaycastCollider"; + Names[141] = "BuildSettings"; + Names[142] = "AssetBundle"; + Names[143] = "CharacterController"; + Names[144] = "CharacterJoint"; + Names[145] = "SpringJoint"; + Names[146] = "WheelCollider"; + Names[147] = "ResourceManager"; + Names[148] = "NetworkView"; + Names[149] = "NetworkManager"; + Names[150] = "PreloadData"; + Names[152] = "MovieTexture"; + Names[153] = "ConfigurableJoint"; + Names[154] = "TerrainCollider"; + Names[155] = "MasterServerInterface"; + Names[156] = "TerrainData"; + Names[157] = "LightmapSettings"; + Names[158] = "WebCamTexture"; + Names[159] = "EditorSettings"; + Names[160] = "InteractiveCloth"; + Names[161] = "ClothRenderer"; + Names[162] = "EditorUserSettings"; + Names[163] = "SkinnedCloth"; + Names[164] = "AudioReverbFilter"; + Names[165] = "AudioHighPassFilter"; + Names[166] = "AudioChorusFilter"; + Names[167] = "AudioReverbZone"; + Names[168] = "AudioEchoFilter"; + Names[169] = "AudioLowPassFilter"; + Names[170] = "AudioDistortionFilter"; + Names[171] = "SparseTexture"; + Names[180] = "AudioBehaviour"; + Names[181] = "AudioFilter"; + Names[182] = "WindZone"; + Names[183] = "Cloth"; + Names[184] = "SubstanceArchive"; + Names[185] = "ProceduralMaterial"; + Names[186] = "ProceduralTexture"; + Names[191] = "OffMeshLink"; + Names[192] = "OcclusionArea"; + Names[193] = "Tree"; + Names[194] = "NavMeshObsolete"; + Names[195] = "NavMeshAgent"; + Names[196] = "NavMeshSettings"; + Names[197] = "LightProbesLegacy"; + Names[198] = "ParticleSystem"; + Names[199] = "ParticleSystemRenderer"; + Names[200] = "ShaderVariantCollection"; + Names[205] = "LODGroup"; + Names[206] = "BlendTree"; + Names[207] = "Motion"; + Names[208] = "NavMeshObstacle"; + Names[210] = "TerrainInstance"; + Names[212] = "SpriteRenderer"; + Names[213] = "Sprite"; + Names[214] = "CachedSpriteAtlas"; + Names[215] = "ReflectionProbe"; + Names[216] = "ReflectionProbes"; + Names[220] = "LightProbeGroup"; + Names[221] = "AnimatorOverrideController"; + Names[222] = "CanvasRenderer"; + Names[223] = "Canvas"; + Names[224] = "RectTransform"; + Names[225] = "CanvasGroup"; + Names[226] = "BillboardAsset"; + Names[227] = "BillboardRenderer"; + Names[228] = "SpeedTreeWindAsset"; + Names[229] = "AnchoredJoint2D"; + Names[230] = "Joint2D"; + Names[231] = "SpringJoint2D"; + Names[232] = "DistanceJoint2D"; + Names[233] = "HingeJoint2D"; + Names[234] = "SliderJoint2D"; + Names[235] = "WheelJoint2D"; + Names[238] = "NavMeshData"; + Names[240] = "AudioMixer"; + Names[241] = "AudioMixerController"; + Names[243] = "AudioMixerGroupController"; + Names[244] = "AudioMixerEffectController"; + Names[245] = "AudioMixerSnapshotController"; + Names[246] = "PhysicsUpdateBehaviour2D"; + Names[247] = "ConstantForce2D"; + Names[248] = "Effector2D"; + Names[249] = "AreaEffector2D"; + Names[250] = "PointEffector2D"; + Names[251] = "PlatformEffector2D"; + Names[252] = "SurfaceEffector2D"; + Names[258] = "LightProbes"; + Names[271] = "SampleClip"; + Names[272] = "AudioMixerSnapshot"; + Names[273] = "AudioMixerGroup"; + Names[290] = "AssetBundleManifest"; + Names[1001] = "Prefab"; + Names[1002] = "EditorExtensionImpl"; + Names[1003] = "AssetImporter"; + Names[1004] = "AssetDatabase"; + Names[1005] = "Mesh3DSImporter"; + Names[1006] = "TextureImporter"; + Names[1007] = "ShaderImporter"; + Names[1008] = "ComputeShaderImporter"; + Names[1011] = "AvatarMask"; + Names[1020] = "AudioImporter"; + Names[1026] = "HierarchyState"; + Names[1027] = "GUIDSerializer"; + Names[1028] = "AssetMetaData"; + Names[1029] = "DefaultAsset"; + Names[1030] = "DefaultImporter"; + Names[1031] = "TextScriptImporter"; + Names[1032] = "SceneAsset"; + Names[1034] = "NativeFormatImporter"; + Names[1035] = "MonoImporter"; + Names[1037] = "AssetServerCache"; + Names[1038] = "LibraryAssetImporter"; + Names[1040] = "ModelImporter"; + Names[1041] = "FBXImporter"; + Names[1042] = "TrueTypeFontImporter"; + Names[1044] = "MovieImporter"; + Names[1045] = "EditorBuildSettings"; + Names[1046] = "DDSImporter"; + Names[1048] = "InspectorExpandedState"; + Names[1049] = "AnnotationManager"; + Names[1050] = "PluginImporter"; + Names[1051] = "EditorUserBuildSettings"; + Names[1052] = "PVRImporter"; + Names[1053] = "ASTCImporter"; + Names[1054] = "KTXImporter"; + Names[1101] = "AnimatorStateTransition"; + Names[1102] = "AnimatorState"; + Names[1105] = "HumanTemplate"; + Names[1107] = "AnimatorStateMachine"; + Names[1108] = "PreviewAssetType"; + Names[1109] = "AnimatorTransition"; + Names[1110] = "SpeedTreeImporter"; + Names[1111] = "AnimatorTransitionBase"; + Names[1112] = "SubstanceImporter"; + Names[1113] = "LightmapParameters"; + Names[1120] = "LightmapSnapshot"; + } + + } +} diff --git a/Unity Studio/EndianStream.cs b/Unity Studio/EndianStream.cs new file mode 100644 index 0000000..4279784 --- /dev/null +++ b/Unity Studio/EndianStream.cs @@ -0,0 +1,198 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace Unity_Studio +{ + public enum EndianType + { + BigEndian, + LittleEndian + } + + public class EndianStream : BinaryReader + { + public EndianType endian; + private byte[] a16 = new byte[2]; + private byte[] a32 = new byte[4]; + private byte[] a64 = new byte[8]; + + public EndianStream(Stream stream, EndianType endian) : base(stream) { } + + ~EndianStream() + { + Dispose(); + } + + public long Position { get { return base.BaseStream.Position; } set { base.BaseStream.Position = value; } } + + public new void Dispose() + { + base.Dispose(); + } + + public override bool ReadBoolean() + { + return base.ReadBoolean(); + } + + public override byte ReadByte() + { + try + { + return base.ReadByte(); + } + catch + { + return 0; + } + } + + public override char ReadChar() + { + return base.ReadChar(); + } + + public override Int16 ReadInt16() + { + if (endian == EndianType.BigEndian) + { + a16 = base.ReadBytes(2); + Array.Reverse(a16); + return BitConverter.ToInt16(a16, 0); + } + else return base.ReadInt16(); + } + + public override int ReadInt32() + { + if (endian == EndianType.BigEndian) + { + a32 = base.ReadBytes(4); + Array.Reverse(a32); + return BitConverter.ToInt32(a32, 0); + } + else return base.ReadInt32(); + } + + public override Int64 ReadInt64() + { + if (endian == EndianType.BigEndian) + { + a64 = base.ReadBytes(8); + Array.Reverse(a64); + return BitConverter.ToInt64(a64, 0); + } + else return base.ReadInt64(); + } + + public override UInt16 ReadUInt16() + { + if (endian == EndianType.BigEndian) + { + a16 = base.ReadBytes(2); + Array.Reverse(a16); + return BitConverter.ToUInt16(a16, 0); + } + else return base.ReadUInt16(); + } + + public override UInt32 ReadUInt32() + { + if (endian == EndianType.BigEndian) + { + a32 = base.ReadBytes(4); + Array.Reverse(a32); + return BitConverter.ToUInt32(a32, 0); + } + else return base.ReadUInt32(); + } + + public override UInt64 ReadUInt64() + { + if (endian == EndianType.BigEndian) + { + a64 = base.ReadBytes(8); + Array.Reverse(a64); + return BitConverter.ToUInt64(a64, 0); + } + else return base.ReadUInt64(); + } + + public override Single ReadSingle() + { + if (endian == EndianType.BigEndian) + { + a32 = base.ReadBytes(4); + Array.Reverse(a32); + return BitConverter.ToSingle(a32, 0); + } + else return base.ReadSingle(); + } + + public override Double ReadDouble() + { + if (endian == EndianType.BigEndian) + { + a64 = base.ReadBytes(8); + Array.Reverse(a64); + return BitConverter.ToUInt64(a64, 0); + } + else return base.ReadDouble(); + } + + public override string ReadString() + { + return base.ReadString(); + } + + public string ReadASCII(int length) + { + return ASCIIEncoding.ASCII.GetString(base.ReadBytes(length)); + } + + public void AlignStream(int alignment) + { + long pos = base.BaseStream.Position; + //long padding = alignment - pos + (pos / alignment) * alignment; + //if (padding != alignment) { base.BaseStream.Position += padding; } + if ((pos % alignment) != 0) { base.BaseStream.Position += alignment - (pos % alignment); } + } + + public string ReadAlignedString(int length) + { + + byte[] stringData = new byte[length]; + base.Read(stringData, 0, length); + var result = System.Text.Encoding.UTF8.GetString(stringData); //must verify strange characters in PS3 + + /*string result = ""; + char c; + for (int i = 0; i < length; i++) + { + c = (char)base.ReadByte(); + result += c.ToString(); + }*/ + + AlignStream(4); + return result; + } + + public string ReadStringToNull() + { + string result = ""; + char c; + for (int i = 0; i < base.BaseStream.Length; i++) + { + if ((c = (char)base.ReadByte()) == 0) + { + break; + } + result += c.ToString(); + } + return result; + } + } +} diff --git a/Unity Studio/FBXExport.Designer.cs b/Unity Studio/FBXExport.Designer.cs new file mode 100644 index 0000000..d27f706 --- /dev/null +++ b/Unity Studio/FBXExport.Designer.cs @@ -0,0 +1,331 @@ +namespace Unity_Studio +{ + partial class ExportOptions + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.includeBox = new System.Windows.Forms.GroupBox(); + this.embedBox = new System.Windows.Forms.CheckBox(); + this.lightsBox = new System.Windows.Forms.CheckBox(); + this.camerasBox = new System.Windows.Forms.CheckBox(); + this.animationBox = new System.Windows.Forms.CheckBox(); + this.geometryBox = new System.Windows.Forms.GroupBox(); + this.exportColors = new System.Windows.Forms.CheckBox(); + this.exportUVs = new System.Windows.Forms.CheckBox(); + this.exportTangents = new System.Windows.Forms.CheckBox(); + this.exportNormals = new System.Windows.Forms.CheckBox(); + this.advancedBox = new System.Windows.Forms.GroupBox(); + this.axisLabel = new System.Windows.Forms.Label(); + this.upAxis = new System.Windows.Forms.ComboBox(); + this.scaleFactor = new System.Windows.Forms.NumericUpDown(); + this.scaleLabel = new System.Windows.Forms.Label(); + this.fbxOKbutton = new System.Windows.Forms.Button(); + this.fbxCancel = new System.Windows.Forms.Button(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.showExpOpt = new System.Windows.Forms.CheckBox(); + this.includeBox.SuspendLayout(); + this.geometryBox.SuspendLayout(); + this.advancedBox.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).BeginInit(); + this.SuspendLayout(); + // + // includeBox + // + this.includeBox.AutoSize = true; + this.includeBox.Controls.Add(this.embedBox); + this.includeBox.Controls.Add(this.lightsBox); + this.includeBox.Controls.Add(this.camerasBox); + this.includeBox.Controls.Add(this.animationBox); + this.includeBox.Controls.Add(this.geometryBox); + this.includeBox.Location = new System.Drawing.Point(13, 13); + this.includeBox.Name = "includeBox"; + this.includeBox.Size = new System.Drawing.Size(359, 262); + this.includeBox.TabIndex = 0; + this.includeBox.TabStop = false; + this.includeBox.Text = "Include"; + // + // embedBox + // + this.embedBox.AutoSize = true; + this.embedBox.Enabled = false; + this.embedBox.Location = new System.Drawing.Point(14, 226); + this.embedBox.Name = "embedBox"; + this.embedBox.Size = new System.Drawing.Size(91, 17); + this.embedBox.TabIndex = 4; + this.embedBox.Text = "Embed Media"; + this.embedBox.UseVisualStyleBackColor = true; + // + // lightsBox + // + this.lightsBox.AutoSize = true; + this.lightsBox.Enabled = false; + this.lightsBox.Location = new System.Drawing.Point(14, 202); + this.lightsBox.Name = "lightsBox"; + this.lightsBox.Size = new System.Drawing.Size(54, 17); + this.lightsBox.TabIndex = 3; + this.lightsBox.Text = "Lights"; + this.lightsBox.UseVisualStyleBackColor = true; + // + // camerasBox + // + this.camerasBox.AutoSize = true; + this.camerasBox.Enabled = false; + this.camerasBox.Location = new System.Drawing.Point(14, 178); + this.camerasBox.Name = "camerasBox"; + this.camerasBox.Size = new System.Drawing.Size(67, 17); + this.camerasBox.TabIndex = 2; + this.camerasBox.Text = "Cameras"; + this.camerasBox.UseVisualStyleBackColor = true; + // + // animationBox + // + this.animationBox.AutoSize = true; + this.animationBox.Enabled = false; + this.animationBox.Location = new System.Drawing.Point(14, 154); + this.animationBox.Name = "animationBox"; + this.animationBox.Size = new System.Drawing.Size(72, 17); + this.animationBox.TabIndex = 1; + this.animationBox.Text = "Animation"; + this.animationBox.UseVisualStyleBackColor = true; + // + // geometryBox + // + this.geometryBox.AutoSize = true; + this.geometryBox.Controls.Add(this.exportColors); + this.geometryBox.Controls.Add(this.exportUVs); + this.geometryBox.Controls.Add(this.exportTangents); + this.geometryBox.Controls.Add(this.exportNormals); + this.geometryBox.Location = new System.Drawing.Point(7, 20); + this.geometryBox.Name = "geometryBox"; + this.geometryBox.Size = new System.Drawing.Size(346, 128); + this.geometryBox.TabIndex = 0; + this.geometryBox.TabStop = false; + this.geometryBox.Text = "Geometry"; + // + // exportColors + // + this.exportColors.AutoSize = true; + this.exportColors.Checked = true; + this.exportColors.CheckState = System.Windows.Forms.CheckState.Checked; + this.exportColors.Location = new System.Drawing.Point(7, 92); + this.exportColors.Name = "exportColors"; + this.exportColors.Size = new System.Drawing.Size(88, 17); + this.exportColors.TabIndex = 3; + this.exportColors.Text = "Vertex Colors"; + this.exportColors.UseVisualStyleBackColor = true; + this.exportColors.CheckedChanged += new System.EventHandler(this.exportOpnions_CheckedChanged); + // + // exportUVs + // + this.exportUVs.AutoSize = true; + this.exportUVs.Checked = true; + this.exportUVs.CheckState = System.Windows.Forms.CheckState.Checked; + this.exportUVs.Location = new System.Drawing.Point(7, 68); + this.exportUVs.Name = "exportUVs"; + this.exportUVs.Size = new System.Drawing.Size(100, 17); + this.exportUVs.TabIndex = 2; + this.exportUVs.Text = "UV Coordinates"; + this.exportUVs.UseVisualStyleBackColor = true; + this.exportUVs.CheckedChanged += new System.EventHandler(this.exportOpnions_CheckedChanged); + // + // exportTangents + // + this.exportTangents.AutoSize = true; + this.exportTangents.Enabled = false; + this.exportTangents.Location = new System.Drawing.Point(7, 44); + this.exportTangents.Name = "exportTangents"; + this.exportTangents.Size = new System.Drawing.Size(71, 17); + this.exportTangents.TabIndex = 1; + this.exportTangents.Text = "Tangents"; + this.exportTangents.UseVisualStyleBackColor = true; + this.exportTangents.CheckedChanged += new System.EventHandler(this.exportOpnions_CheckedChanged); + // + // exportNormals + // + this.exportNormals.AutoSize = true; + this.exportNormals.Checked = true; + this.exportNormals.CheckState = System.Windows.Forms.CheckState.Checked; + this.exportNormals.Location = new System.Drawing.Point(7, 20); + this.exportNormals.Name = "exportNormals"; + this.exportNormals.Size = new System.Drawing.Size(64, 17); + this.exportNormals.TabIndex = 0; + this.exportNormals.Text = "Normals"; + this.exportNormals.UseVisualStyleBackColor = true; + this.exportNormals.CheckedChanged += new System.EventHandler(this.exportOpnions_CheckedChanged); + // + // advancedBox + // + this.advancedBox.AutoSize = true; + this.advancedBox.Controls.Add(this.axisLabel); + this.advancedBox.Controls.Add(this.upAxis); + this.advancedBox.Controls.Add(this.scaleFactor); + this.advancedBox.Controls.Add(this.scaleLabel); + this.advancedBox.Location = new System.Drawing.Point(12, 281); + this.advancedBox.Name = "advancedBox"; + this.advancedBox.Size = new System.Drawing.Size(360, 80); + this.advancedBox.TabIndex = 5; + this.advancedBox.TabStop = false; + this.advancedBox.Text = "Advanced Options"; + // + // axisLabel + // + this.axisLabel.AutoSize = true; + this.axisLabel.Location = new System.Drawing.Point(6, 43); + this.axisLabel.Name = "axisLabel"; + this.axisLabel.Size = new System.Drawing.Size(46, 13); + this.axisLabel.TabIndex = 3; + this.axisLabel.Text = "Up Axis:"; + // + // upAxis + // + this.upAxis.FormattingEnabled = true; + this.upAxis.Items.AddRange(new object[] { + "Y-up"}); + this.upAxis.Location = new System.Drawing.Point(58, 40); + this.upAxis.MaxDropDownItems = 2; + this.upAxis.Name = "upAxis"; + this.upAxis.Size = new System.Drawing.Size(70, 21); + this.upAxis.TabIndex = 2; + // + // scaleFactor + // + this.scaleFactor.DecimalPlaces = 2; + this.scaleFactor.Increment = new decimal(new int[] { + 1, + 0, + 0, + 131072}); + this.scaleFactor.Location = new System.Drawing.Point(82, 14); + this.scaleFactor.Name = "scaleFactor"; + this.scaleFactor.Size = new System.Drawing.Size(46, 20); + this.scaleFactor.TabIndex = 1; + this.scaleFactor.Value = new decimal(new int[] { + 254, + 0, + 0, + 131072}); + // + // scaleLabel + // + this.scaleLabel.AutoSize = true; + this.scaleLabel.Location = new System.Drawing.Point(6, 16); + this.scaleLabel.Name = "scaleLabel"; + this.scaleLabel.Size = new System.Drawing.Size(70, 13); + this.scaleLabel.TabIndex = 0; + this.scaleLabel.Text = "Scale Factor:"; + // + // fbxOKbutton + // + this.fbxOKbutton.Location = new System.Drawing.Point(216, 367); + this.fbxOKbutton.Name = "fbxOKbutton"; + this.fbxOKbutton.Size = new System.Drawing.Size(75, 23); + this.fbxOKbutton.TabIndex = 6; + this.fbxOKbutton.Text = "OK"; + this.fbxOKbutton.UseVisualStyleBackColor = true; + this.fbxOKbutton.Click += new System.EventHandler(this.fbxOKbutton_Click); + // + // fbxCancel + // + this.fbxCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.fbxCancel.Location = new System.Drawing.Point(297, 367); + this.fbxCancel.Name = "fbxCancel"; + this.fbxCancel.Size = new System.Drawing.Size(75, 23); + this.fbxCancel.TabIndex = 7; + this.fbxCancel.Text = "Cancel"; + this.fbxCancel.UseVisualStyleBackColor = true; + this.fbxCancel.Click += new System.EventHandler(this.fbxCancel_Click); + // + // saveFileDialog1 + // + this.saveFileDialog1.Filter = "FBX file|*.fbx|Collada|*.dae"; + this.saveFileDialog1.RestoreDirectory = true; + // + // showExpOpt + // + this.showExpOpt.AutoSize = true; + this.showExpOpt.Location = new System.Drawing.Point(12, 371); + this.showExpOpt.Name = "showExpOpt"; + this.showExpOpt.Size = new System.Drawing.Size(127, 17); + this.showExpOpt.TabIndex = 8; + this.showExpOpt.Text = "Show for each export"; + this.showExpOpt.UseVisualStyleBackColor = true; + // + // ExportOptions + // + this.AcceptButton = this.fbxOKbutton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.fbxCancel; + this.ClientSize = new System.Drawing.Size(384, 401); + this.Controls.Add(this.showExpOpt); + this.Controls.Add(this.fbxCancel); + this.Controls.Add(this.fbxOKbutton); + this.Controls.Add(this.advancedBox); + this.Controls.Add(this.includeBox); + this.HelpButton = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ExportOptions"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.Text = "Export options"; + this.TopMost = true; + this.includeBox.ResumeLayout(false); + this.includeBox.PerformLayout(); + this.geometryBox.ResumeLayout(false); + this.geometryBox.PerformLayout(); + this.advancedBox.ResumeLayout(false); + this.advancedBox.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.scaleFactor)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.GroupBox includeBox; + private System.Windows.Forms.GroupBox advancedBox; + private System.Windows.Forms.NumericUpDown scaleFactor; + private System.Windows.Forms.Label scaleLabel; + private System.Windows.Forms.CheckBox embedBox; + private System.Windows.Forms.CheckBox lightsBox; + private System.Windows.Forms.CheckBox camerasBox; + private System.Windows.Forms.CheckBox animationBox; + private System.Windows.Forms.GroupBox geometryBox; + private System.Windows.Forms.CheckBox exportColors; + private System.Windows.Forms.CheckBox exportUVs; + private System.Windows.Forms.CheckBox exportTangents; + private System.Windows.Forms.CheckBox exportNormals; + private System.Windows.Forms.Label axisLabel; + private System.Windows.Forms.ComboBox upAxis; + private System.Windows.Forms.Button fbxOKbutton; + private System.Windows.Forms.Button fbxCancel; + private System.Windows.Forms.SaveFileDialog saveFileDialog1; + private System.Windows.Forms.CheckBox showExpOpt; + } +} \ No newline at end of file diff --git a/Unity Studio/FBXExport.cs b/Unity Studio/FBXExport.cs new file mode 100644 index 0000000..9fb9ec1 --- /dev/null +++ b/Unity Studio/FBXExport.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Unity_Studio +{ + public partial class ExportOptions : Form + { + public string selectedPath = ""; + + public ExportOptions() + { + InitializeComponent(); + exportNormals.Checked = (bool)Properties.Settings.Default["exportNormals"]; + exportTangents.Checked = (bool)Properties.Settings.Default["exportTangents"]; + exportUVs.Checked = (bool)Properties.Settings.Default["exportUVs"]; + exportColors.Checked = (bool)Properties.Settings.Default["exportColors"]; + scaleFactor.Value = (decimal)Properties.Settings.Default["scaleFactor"]; + upAxis.SelectedIndex = (int)Properties.Settings.Default["upAxis"]; + showExpOpt.Checked = (bool)Properties.Settings.Default["showExpOpt"]; + } + + private void exportOpnions_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default[((CheckBox)sender).Name] = ((CheckBox)sender).Checked; + Properties.Settings.Default.Save(); + } + + private void fbxOKbutton_Click(object sender, EventArgs e) + { + Properties.Settings.Default["exportNormals"] = exportNormals.Checked; + Properties.Settings.Default["exportTangents"] = exportTangents.Checked; + Properties.Settings.Default["exportUVs"] = exportUVs.Checked; + Properties.Settings.Default["exportColors"] = exportColors.Checked; + Properties.Settings.Default["scaleFactor"] = scaleFactor.Value; + Properties.Settings.Default["upAxis"] = upAxis.SelectedIndex; + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void fbxCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/Unity Studio/FBXExport.resx b/Unity Studio/FBXExport.resx new file mode 100644 index 0000000..053da59 --- /dev/null +++ b/Unity Studio/FBXExport.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Unity Studio/FMOD/fmod.cs b/Unity Studio/FMOD/fmod.cs new file mode 100644 index 0000000..81c4f0d --- /dev/null +++ b/Unity Studio/FMOD/fmod.cs @@ -0,0 +1,5510 @@ +/* ========================================================================================== */ +/* */ +/* FMOD Ex - C# Wrapper . Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ +/* */ +/* ========================================================================================== */ + +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace FMOD +{ + /* + FMOD version number. Check this against FMOD::System::getVersion / System_GetVersion + 0xaaaabbcc -> aaaa = major version number. bb = minor version number. cc = development version number. + */ + public class VERSION + { + public const int number = 0x00044441; +#if WIN64 + public const string dll = "fmodex64"; +#else + public const string dll = "fmodex"; +#endif + } + + /* + FMOD types + */ + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure describing a point in 3D space. + + [REMARKS] + FMOD uses a left handed co-ordinate system by default. + To use a right handed co-ordinate system specify FMOD_INIT_3D_RIGHTHANDED from FMOD_INITFLAGS in System::init. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::set3DListenerAttributes + System::get3DListenerAttributes + Channel::set3DAttributes + Channel::get3DAttributes + Geometry::addPolygon + Geometry::setPolygonVertex + Geometry::getPolygonVertex + Geometry::setRotation + Geometry::getRotation + Geometry::setPosition + Geometry::getPosition + Geometry::setScale + Geometry::getScale + FMOD_INITFLAGS + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct VECTOR + { + public float x; /* X co-ordinate in 3D space. */ + public float y; /* Y co-ordinate in 3D space. */ + public float z; /* Z co-ordinate in 3D space. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure describing a globally unique identifier. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::getDriverInfo + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct GUID + { + public uint Data1; /* Specifies the first 8 hexadecimal digits of the GUID */ + public ushort Data2; /* Specifies the first group of 4 hexadecimal digits. */ + public ushort Data3; /* Specifies the second group of 4 hexadecimal digits. */ + [MarshalAs(UnmanagedType.ByValArray,SizeConst=8)] + public byte[] Data4; /* Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits. */ + } + + /* + [STRUCTURE] + [ + [DESCRIPTION] + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii, iPhone + + [SEE_ALSO] + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct ASYNCREADINFO + { + public IntPtr handle; /* [r] The file handle that was filled out in the open callback. */ + public uint offset; /* [r] Seek position, make sure you read from this file offset. */ + public uint sizebytes; /* [r] how many bytes requested for read. */ + public int priority; /* [r] 0 = low importance. 100 = extremely important (ie 'must read now or stuttering may occur') */ + + public IntPtr buffer; /* [w] Buffer to read file data into. */ + public uint bytesread; /* [w] Fill this in before setting result code to tell FMOD how many bytes were read. */ + public RESULT result; /* [r/w] Result code, FMOD_OK tells the system it is ready to consume the data. Set this last! Default value = FMOD_ERR_NOTREADY. */ + + public IntPtr userdata; /* [r] User data pointer. */ + } + + /* + [ENUM] + [ + [DESCRIPTION] + error codes. Returned from every function. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + ] + */ + public enum RESULT :int + { + OK, /* No errors. */ + ERR_ALREADYLOCKED, /* Tried to call lock a second time before unlock was called. */ + ERR_BADCOMMAND, /* Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). */ + ERR_CDDA_DRIVERS, /* Neither NTSCSI nor ASPI could be initialised. */ + ERR_CDDA_INIT, /* An error occurred while initialising the CDDA subsystem. */ + ERR_CDDA_INVALID_DEVICE, /* Couldn't find the specified device. */ + ERR_CDDA_NOAUDIO, /* No audio tracks on the specified disc. */ + ERR_CDDA_NODEVICES, /* No CD/DVD devices were found. */ + ERR_CDDA_NODISC, /* No disc present in the specified drive. */ + ERR_CDDA_READ, /* A CDDA read error occurred. */ + ERR_CHANNEL_ALLOC, /* Error trying to allocate a channel. */ + ERR_CHANNEL_STOLEN, /* The specified channel has been reused to play another sound. */ + ERR_COM, /* A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. */ + ERR_DMA, /* DMA Failure. See debug output for more information. */ + ERR_DSP_CONNECTION, /* DSP connection error. Connection possibly caused a cyclic dependancy. */ + ERR_DSP_FORMAT, /* DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. */ + ERR_DSP_NOTFOUND, /* DSP connection error. Couldn't find the DSP unit specified. */ + ERR_DSP_RUNNING, /* DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. */ + ERR_DSP_TOOMANYCONNECTIONS,/* DSP connection error. The unit being connected to or disconnected should only have 1 input or output. */ + ERR_FILE_BAD, /* Error loading file. */ + ERR_FILE_COULDNOTSEEK, /* Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. */ + ERR_FILE_DISKEJECTED, /* Media was ejected while reading. */ + ERR_FILE_EOF, /* End of file unexpectedly reached while trying to read essential data (truncated data?). */ + ERR_FILE_NOTFOUND, /* File not found. */ + ERR_FILE_UNWANTED, /* Unwanted file access occured. */ + ERR_FORMAT, /* Unsupported file or audio format. */ + ERR_HTTP, /* A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. */ + ERR_HTTP_ACCESS, /* The specified resource requires authentication or is forbidden. */ + ERR_HTTP_PROXY_AUTH, /* Proxy authentication is required to access the specified resource. */ + ERR_HTTP_SERVER_ERROR, /* A HTTP server error occurred. */ + ERR_HTTP_TIMEOUT, /* The HTTP request timed out. */ + ERR_INITIALIZATION, /* FMOD was not initialized correctly to support this function. */ + ERR_INITIALIZED, /* Cannot call this command after System::init. */ + ERR_INTERNAL, /* An error occured that wasn't supposed to. Contact support. */ + ERR_INVALID_ADDRESS, /* On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) */ + ERR_INVALID_FLOAT, /* Value passed in was a NaN, Inf or denormalized float. */ + ERR_INVALID_HANDLE, /* An invalid object handle was used. */ + ERR_INVALID_PARAM, /* An invalid parameter was passed to this function. */ + ERR_INVALID_POSITION, /* An invalid seek position was passed to this function. */ + ERR_INVALID_SPEAKER, /* An invalid speaker was passed to this function based on the current speaker mode. */ + ERR_INVALID_SYNCPOINT, /* The syncpoint did not come from this sound handle. */ + ERR_INVALID_VECTOR, /* The vectors passed in are not unit length, or perpendicular. */ + ERR_MAXAUDIBLE, /* Reached maximum audible playback count for this sound's soundgroup. */ + ERR_MEMORY, /* Not enough memory or resources. */ + ERR_MEMORY_CANTPOINT, /* Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if CREATECOMPRESSEDSAMPLE was used. */ + ERR_MEMORY_SRAM, /* Not enough memory or resources on console sound ram. */ + ERR_NEEDS2D, /* Tried to call a command on a 3d sound when the command was meant for 2d sound. */ + ERR_NEEDS3D, /* Tried to call a command on a 2d sound when the command was meant for 3d sound. */ + ERR_NEEDSHARDWARE, /* Tried to use a feature that requires hardware support. (ie trying to play a GCADPCM compressed sound in software on Wii). */ + ERR_NEEDSSOFTWARE, /* Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. */ + ERR_NET_CONNECT, /* Couldn't connect to the specified host. */ + ERR_NET_SOCKET_ERROR, /* A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. */ + ERR_NET_URL, /* The specified URL couldn't be resolved. */ + ERR_NET_WOULD_BLOCK, /* Operation on a non-blocking socket could not complete immediately. */ + ERR_NOTREADY, /* Operation could not be performed because specified sound is not ready. */ + ERR_OUTPUT_ALLOCATED, /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */ + ERR_OUTPUT_CREATEBUFFER, /* Error creating hardware sound buffer. */ + ERR_OUTPUT_DRIVERCALL, /* A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. */ + ERR_OUTPUT_ENUMERATION, /* Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal. */ + ERR_OUTPUT_FORMAT, /* Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). */ + ERR_OUTPUT_INIT, /* Error initializing output device. */ + ERR_OUTPUT_NOHARDWARE, /* FMOD_HARDWARE was specified but the sound card does not have the resources nescessary to play it. */ + ERR_OUTPUT_NOSOFTWARE, /* Attempted to create a software sound but no software channels were specified in System::init. */ + ERR_PAN, /* Panning only works with mono or stereo sound sources. */ + ERR_PLUGIN, /* An unspecified error has been returned from a 3rd party plugin. */ + ERR_PLUGIN_INSTANCES, /* The number of allowed instances of a plugin has been exceeded */ + ERR_PLUGIN_MISSING, /* A requested output, dsp unit type or codec was not available. */ + ERR_PLUGIN_RESOURCE, /* A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback) */ + ERR_PRELOADED, /* The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. */ + ERR_PROGRAMMERSOUND, /* The specified sound is still in use by the event system, wait for the event which is using it finish with it. */ + ERR_RECORD, /* An error occured trying to initialize the recording device. */ + ERR_REVERB_INSTANCE, /* Specified Instance in REVERB_PROPERTIES couldn't be set. Most likely because another application has locked the EAX4 FX slot. */ + ERR_SUBSOUND_ALLOCATED, /* This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. */ + ERR_SUBSOUND_CANTMOVE, /* Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file. */ + ERR_SUBSOUND_MODE, /* The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with. */ + ERR_SUBSOUNDS, /* The error occured because the sound referenced contains subsounds. (ie you cannot play the parent sound as a static sample, only its subsounds.) */ + ERR_TAGNOTFOUND, /* The specified tag could not be found or there are no tags. */ + ERR_TOOMANYCHANNELS, /* The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. */ + ERR_UNIMPLEMENTED, /* Something in FMOD hasn't been implemented when it should be! contact support! */ + ERR_UNINITIALIZED, /* This command failed because System::init or System::setDriver was not called. */ + ERR_UNSUPPORTED, /* A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. */ + ERR_UPDATE, /* An error caused by System::update occured. */ + ERR_VERSION, /* The version number of this file format is not supported. */ + + ERR_EVENT_FAILED, /* An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. */ + ERR_EVENT_INFOONLY, /* Can't execute this command on an EVENT_INFOONLY event. */ + ERR_EVENT_INTERNAL, /* An error occured that wasn't supposed to. See debug log for reason. */ + ERR_EVENT_MAXSTREAMS, /* Event failed because 'Max streams' was hit when FMOD_INIT_FAIL_ON_MAXSTREAMS was specified. */ + ERR_EVENT_MISMATCH, /* FSB mis-matches the FEV it was compiled with. */ + ERR_EVENT_NAMECONFLICT, /* A category with the same name already exists. */ + ERR_EVENT_NOTFOUND, /* The requested event, event group, event category or event property could not be found. */ + ERR_EVENT_NEEDSSIMPLE, /* Tried to call a function on a complex event that's only supported by simple events. */ + ERR_EVENT_GUIDCONFLICT, /* An event with the same GUID already exists. */ + ERR_EVENT_ALREADY_LOADED, /* The specified project has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. */ + + ERR_MUSIC_UNINITIALIZED, /* Music system is not initialized probably because no music data is loaded. */ + ERR_MUSIC_NOTFOUND, /* The requested music entity could not be found. */ + ERR_MUSIC_NOCALLBACK, /* The music callback is required, but it has not been set. */ + } + + + + /* + [ENUM] + [ + [DESCRIPTION] + These output types are used with System::setOutput/System::getOutput, to choose which output method to use. + + [REMARKS] + To drive the output synchronously, and to disable FMOD's timing thread, use the FMOD_INIT_NONREALTIME flag. + + To pass information to the driver when initializing fmod use the extradriverdata parameter for the following reasons. +
  • FMOD_OUTPUTTYPE_WAVWRITER - extradriverdata is a pointer to a char * filename that the wav writer will output to. +
  • FMOD_OUTPUTTYPE_WAVWRITER_NRT - extradriverdata is a pointer to a char * filename that the wav writer will output to. +
  • FMOD_OUTPUTTYPE_DSOUND - extradriverdata is a pointer to a HWND so that FMOD can set the focus on the audio for a particular window. +
  • FMOD_OUTPUTTYPE_GC - extradriverdata is a pointer to a FMOD_ARAMBLOCK_INFO struct. This can be found in fmodgc.h. + Currently these are the only FMOD drivers that take extra information. Other unknown plugins may have different requirements. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setOutput + System::getOutput + System::setSoftwareFormat + System::getSoftwareFormat + System::init + ] + */ + public enum OUTPUTTYPE :int + { + AUTODETECT, /* Picks the best output mode for the platform. This is the default. */ + + UNKNOWN, /* All - 3rd party plugin, unknown. This is for use with System::getOutput only. */ + NOSOUND, /* All - All calls in this mode succeed but make no sound. */ + WAVWRITER, /* All - Writes output to fmodoutput.wav by default. Use the 'extradriverdata' parameter in System::init, by simply passing the filename as a string, to set the wav filename. */ + NOSOUND_NRT, /* All - Non-realtime version of _NOSOUND. User can drive mixer with System::update at whatever rate they want. */ + WAVWRITER_NRT, /* All - Non-realtime version of _WAVWRITER. User can drive mixer with System::update at whatever rate they want. */ + + DSOUND, /* Win32/Win64 - DirectSound output. (Default on Windows XP and below) */ + WINMM, /* Win32/Win64 - Windows Multimedia output. */ + WASAPI, /* Win32 - Windows Audio Session API. (Default on Windows Vista and above) */ + ASIO, /* Win32 - Low latency ASIO 2.0 driver. */ + OSS, /* Linux/Linux64 - Open Sound System output. (Default on Linux, third preference) */ + ALSA, /* Linux/Linux64 - Advanced Linux Sound Architecture output. (Default on Linux, second preference if available) */ + ESD, /* Linux/Linux64 - Enlightment Sound Daemon output. */ + PULSEAUDIO, /* Linux/Linux64 - PulseAudio output. (Default on Linux, first preference if available) */ + COREAUDIO, /* Mac - Macintosh CoreAudio output. (Default on Mac) */ + XBOX360, /* Xbox 360 - Native Xbox360 output. (Default on Xbox 360) */ + PSP, /* PSP - Native PSP output. (Default on PSP) */ + PS3, /* PS3 - Native PS3 output. (Default on PS3) */ + NGP, /* NGP - Native NGP output. (Default on NGP) */ + WII, /* Wii - Native Wii output. (Default on Wii) */ + _3DS, /* 3DS - Native 3DS output (Default on 3DS) */ + AUDIOTRACK, /* Android - Java Audio Track output. (Default on Android 2.2 and below) */ + OPENSL, /* Android - OpenSL ES output. (Default on Android 2.3 and above) */ + NACL, /* Native Client - Native Client output. (Default on Native Client) */ + WIIU, /* Wii U - Native Wii U output. (Default on Wii U) */ + + MAX /* Maximum number of output types supported. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + ] + */ + public enum CAPS + { + NONE = 0x00000000, /* Device has no special capabilities. */ + HARDWARE = 0x00000001, /* Device supports hardware mixing. */ + HARDWARE_EMULATED = 0x00000002, /* User has device set to 'Hardware acceleration = off' in control panel, and now extra 200ms latency is incurred. */ + OUTPUT_MULTICHANNEL = 0x00000004, /* Device can do multichannel output, ie greater than 2 channels. */ + OUTPUT_FORMAT_PCM8 = 0x00000008, /* Device can output to 8bit integer PCM. */ + OUTPUT_FORMAT_PCM16 = 0x00000010, /* Device can output to 16bit integer PCM. */ + OUTPUT_FORMAT_PCM24 = 0x00000020, /* Device can output to 24bit integer PCM. */ + OUTPUT_FORMAT_PCM32 = 0x00000040, /* Device can output to 32bit integer PCM. */ + OUTPUT_FORMAT_PCMFLOAT = 0x00000080, /* Device can output to 32bit floating point PCM. */ + REVERB_LIMITED = 0x00002000 /* Device supports some form of limited hardware reverb, maybe parameterless and only selectable by environment. */ + } + + /* + [DEFINE] + [ + [NAME] + FMOD_DEBUGLEVEL + + [DESCRIPTION] + Bit fields to use with FMOD::Debug_SetLevel / FMOD::Debug_GetLevel to control the level of tty debug output with logging versions of FMOD (fmodL). + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Debug_SetLevel + Debug_GetLevel + ] + */ + public enum DEBUGLEVEL + { + LEVEL_NONE = 0x00000000, + LEVEL_LOG = 0x00000001, + LEVEL_ERROR = 0x00000002, + LEVEL_WARNING = 0x00000004, + LEVEL_HINT = 0x00000008, + LEVEL_ALL = 0x000000FF, + TYPE_MEMORY = 0x00000100, + TYPE_THREAD = 0x00000200, + TYPE_FILE = 0x00000400, + TYPE_NET = 0x00000800, + TYPE_EVENT = 0x00001000, + TYPE_ALL = 0x0000FFFF, + DISPLAY_TIMESTAMPS = 0x01000000, + DISPLAY_LINENUMBERS = 0x02000000, + DISPLAY_COMPRESS = 0x04000000, + DISPLAY_THREAD = 0x08000000, + DISPLAY_ALL = 0x0F000000, + ALL = unchecked((int)0xffffffff) + } + + + /* + [DEFINE] + [ + [NAME] + FMOD_MEMORY_TYPE + + [DESCRIPTION] + Bit fields for memory allocation type being passed into FMOD memory callbacks. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + FMOD_MEMORY_ALLOCCALLBACK + FMOD_MEMORY_REALLOCCALLBACK + FMOD_MEMORY_FREECALLBACK + Memory_Initialize + + ] + */ + public enum MEMORY_TYPE + { + NORMAL = 0x00000000, /* Standard memory. */ + STREAM_FILE = 0x00000001, /* Stream file buffer, size controllable with System::setStreamBufferSize. */ + STREAM_DECODE = 0x00000002, /* Stream decode buffer, size controllable with FMOD_CREATESOUNDEXINFO::decodebuffersize. */ + SAMPLEDATA = 0x00000004, /* Sample data buffer. Raw audio data, usually PCM/MPEG/ADPCM/XMA data. */ + DSP_OUTPUTBUFFER = 0x00000008, /* DSP memory block allocated when more than 1 output exists on a DSP node. */ + XBOX360_PHYSICAL = 0x00100000, /* Requires XPhysicalAlloc / XPhysicalFree. */ + PERSISTENT = 0x00200000, /* Persistent memory. Memory will be freed when System::release is called. */ + SECONDARY = 0x00400000 /* Secondary memory. Allocation should be in secondary memory. For example RSX on the PS3. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These are speaker types defined for use with the System::setSpeakerMode or System::getSpeakerMode command. + + [REMARKS] + These are important notes on speaker modes in regards to sounds created with FMOD_SOFTWARE.
    + Note below the phrase 'sound channels' is used. These are the subchannels inside a sound, they are not related and + have nothing to do with the FMOD class "Channel".
    + For example a mono sound has 1 sound channel, a stereo sound has 2 sound channels, and an AC3 or 6 channel wav file have 6 "sound channels".
    +
    + FMOD_SPEAKERMODE_RAW
    + ---------------------
    + This mode is for output devices that are not specifically mono/stereo/quad/surround/5.1 or 7.1, but are multichannel.
    + Sound channels map to speakers sequentially, so a mono sound maps to output speaker 0, stereo sound maps to output speaker 0 & 1.
    + The user assumes knowledge of the speaker order. FMOD_SPEAKER enumerations may not apply, so raw channel indicies should be used.
    + Multichannel sounds map input channels to output channels 1:1.
    + Channel::setPan and Channel::setSpeakerMix do not work.
    + Speaker levels must be manually set with Channel::setSpeakerLevels.
    +
    + FMOD_SPEAKERMODE_MONO
    + ---------------------
    + This mode is for a 1 speaker arrangement.
    + Panning does not work in this speaker mode.
    + Mono, stereo and multichannel sounds have each sound channel played on the one speaker unity.
    + Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    + Channel::setSpeakerMix does not work.
    +
    + FMOD_SPEAKERMODE_STEREO
    + -----------------------
    + This mode is for 2 speaker arrangements that have a left and right speaker.
    +
  • Mono sounds default to an even distribution between left and right. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the middle, or full left in the left speaker and full right in the right speaker. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds have each sound channel played on each speaker at unity.
    +
  • Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but only front left and right parameters are used, the rest are ignored.
    +
    + FMOD_SPEAKERMODE_QUAD
    + ------------------------
    + This mode is for 4 speaker arrangements that have a front left, front right, rear left and a rear right speaker.
    +
  • Mono sounds default to an even distribution between front left and front right. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right.
    +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input.
    +
  • Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left, side right, center and lfe are ignored.
    +
    + FMOD_SPEAKERMODE_SURROUND
    + ------------------------
    + This mode is for 4 speaker arrangements that have a front left, front right, front center and a rear center.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input.
    +
  • Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left, side right and lfe are ignored, and rear left / rear right are averaged into the rear speaker.
    +
    + FMOD_SPEAKERMODE_5POINT1
    + ------------------------
    + This mode is for 5.1 speaker arrangements that have a left/right/center/rear left/rear right and a subwoofer speaker.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input. +
  • Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works but side left / side right are ignored.
    +
    + FMOD_SPEAKERMODE_7POINT1
    + ------------------------
    + This mode is for 7.1 speaker arrangements that have a left/right/center/rear left/rear right/side left/side right + and a subwoofer speaker.
    +
  • Mono sounds default to the center speaker. They can be panned with Channel::setPan.
    +
  • Stereo sounds default to the left sound channel played on the front left, and the right sound channel played on the front right. +
  • They can be cross faded with Channel::setPan.
    +
  • Multichannel sounds default to all of their sound channels being played on each speaker in order of input. +
  • Mix behaviour for multichannel sounds can be set with Channel::setSpeakerLevels.
    +
  • Channel::setSpeakerMix works and every parameter is used to set the balance of a sound in any speaker.
    +
    + FMOD_SPEAKERMODE_SRS5_1_MATRIX
    + ------------------------------------------------------
    + This mode is for mono, stereo, 5.1 and 7.1 speaker arrangements, as it is backwards and forwards compatible with + stereo, but to get a surround effect a SRS 5.1, Prologic or Prologic 2 hardware decoder / amplifier is needed.
    + Pan behavior is the same as FMOD_SPEAKERMODE_5POINT1.
    +
    + If this function is called the numoutputchannels setting in System::setSoftwareFormat is overwritten.
    +
    + Output rate must be 44100, 48000 or 96000 for this to work otherwise FMOD_ERR_OUTPUT_INIT will be returned.
    + + FMOD_SPEAKERMODE_MYEARS
    + ------------------------------------------------------
    + This mode is for headphones. This will attempt to load a MyEars profile (see myears.net.au) and use it to generate + surround sound on headphones using a personalized HRTF algorithm, for realistic 3d sound.
    + Pan behavior is the same as FMOD_SPEAKERMODE_7POINT1.
    + MyEars speaker mode will automatically be set if the speakermode is FMOD_SPEAKERMODE_STEREO and the MyEars profile exists.
    + If this mode is set explicitly, FMOD_INIT_DISABLE_MYEARS_AUTODETECT has no effect.
    + If this mode is set explicitly and the MyEars profile does not exist, FMOD_ERR_OUTPUT_DRIVERCALL will be returned. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setSpeakerMode + System::getSpeakerMode + System::getDriverCaps + Channel::setSpeakerLevels + ] + */ + public enum SPEAKERMODE :int + { + RAW, /* There is no specific speakermode. Sound channels are mapped in order of input to output. See remarks for more information. */ + MONO, /* The speakers are monaural. */ + STEREO, /* The speakers are stereo (DEFAULT). */ + QUAD, /* 4 speaker setup. This includes front left, front right, rear left, rear right. */ + SURROUND, /* 4 speaker setup. This includes front left, front right, center, rear center (rear left/rear right are averaged). */ + _5POINT1, /* 5.1 speaker setup. This includes front left, front right, center, rear left, rear right and a subwoofer. */ + _7POINT1, /* 7.1 speaker setup. This includes front left, front right, center, rear left, rear right, side left, side right and a subwoofer. */ + + SRS5_1_MATRIX, /* Stereo compatible output, embedded with surround information. SRS 5.1/Prologic/Prologic2 decoders will split the signal into a 5.1 speaker set-up or SRS virtual surround will decode into a 2-speaker/headphone setup. See remarks about limitations. */ + MYEARS, /* Stereo output, but data is encoded using personalized HRTF algorithms. See myears.net.au */ + + MAX, /* Maximum number of speaker modes supported. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These are speaker types defined for use with the Channel::setSpeakerLevels command. + It can also be used for speaker placement in the System::setSpeakerPosition command. + + [REMARKS] + If you are using FMOD_SPEAKERMODE_RAW and speaker assignments are meaningless, just cast a raw integer value to this type.
    + For example (FMOD_SPEAKER)7 would use the 7th speaker (also the same as FMOD_SPEAKER_SIDE_RIGHT).
    + Values higher than this can be used if an output system has more than 8 speaker types / output channels. 15 is the current maximum. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + FMOD_SPEAKERMODE + Channel::setSpeakerLevels + Channel::getSpeakerLevels + System::setSpeakerPosition + System::getSpeakerPosition + ] + */ + public enum SPEAKER :int + { + FRONT_LEFT, + FRONT_RIGHT, + FRONT_CENTER, + LOW_FREQUENCY, + BACK_LEFT, + BACK_RIGHT, + SIDE_LEFT, + SIDE_RIGHT, + + MAX, /* Maximum number of speaker types supported. */ + MONO = FRONT_LEFT, /* For use with FMOD_SPEAKERMODE_MONO and Channel::SetSpeakerLevels. Mapped to same value as FMOD_SPEAKER_FRONT_LEFT. */ + NULL = MAX, /* A non speaker. Use this to send. */ + SBL = SIDE_LEFT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + SBR = SIDE_RIGHT, /* For use with FMOD_SPEAKERMODE_7POINT1 on PS3 where the extra speakers are surround back inside of side speakers. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These are plugin types defined for use with the System::getNumPlugins / System_GetNumPlugins, + System::getPluginInfo / System_GetPluginInfo and System::unloadPlugin / System_UnloadPlugin functions. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::getNumPlugins + System::getPluginInfo + System::unloadPlugin + ] + */ + public enum PLUGINTYPE :int + { + OUTPUT, /* The plugin type is an output module. FMOD mixed audio will play through one of these devices */ + CODEC, /* The plugin type is a file format codec. FMOD will use these codecs to load file formats for playback. */ + DSP /* The plugin type is a DSP unit. FMOD will use these plugins as part of its DSP network to apply effects to output or generate sound in realtime. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Initialization flags. Use them with System::init in the flags parameter to change various behaviour. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::init + ] + */ + public enum INITFLAGS :int + { + NORMAL = 0x00000000, /* All platforms - Initialize normally */ + STREAM_FROM_UPDATE = 0x00000001, /* All platforms - No stream thread is created internally. Streams are driven from System::update. Mainly used with non-realtime outputs. */ + _3D_RIGHTHANDED = 0x00000002, /* All platforms - FMOD will treat +X as left, +Y as up and +Z as forwards. */ + SOFTWARE_DISABLE = 0x00000004, /* All platforms - Disable software mixer to save memory. Anything created with FMOD_SOFTWARE will fail and DSP will not work. */ + OCCLUSION_LOWPASS = 0x00000008, /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which is automatically used when Channel::set3DOcclusion is used or the geometry API. */ + HRTF_LOWPASS = 0x00000010, /* All platforms - All FMOD_SOFTWARE (and FMOD_HARDWARE on 3DS and NGP) with FMOD_3D based voices will add a software lowpass filter effect into the DSP chain which causes sounds to sound duller when the sound goes behind the listener. Use System::setAdvancedSettings to adjust cutoff frequency. */ + DISTANCE_FILTERING = 0x00000200, /* All platforms - All FMOD_SOFTWARE with FMOD_3D based voices will add a software lowpass and highpass filter effect into the DSP chain which will act as a distance-automated bandpass filter. Use System::setAdvancedSettings to adjust the center frequency. */ + SOFTWARE_REVERB_LOWMEM = 0x00000040, /* All platforms - SFX reverb is run using 22/24khz delay buffers, halving the memory required. */ + ENABLE_PROFILE = 0x00000020, /* All platforms - Enable TCP/IP based host which allows "DSPNet Listener.exe" to connect to it, and view the DSP dataflow network graph in real-time. */ + VOL0_BECOMES_VIRTUAL = 0x00000080, /* All platforms - Any sounds that are 0 volume will go virtual and not be processed except for having their positions updated virtually. Use System::setAdvancedSettings to adjust what volume besides zero to switch to virtual at. */ + WASAPI_EXCLUSIVE = 0x00000100, /* Win32 Vista only - for WASAPI output - Enable exclusive access to hardware, lower latency at the expense of excluding other applications from accessing the audio hardware. */ + DISABLEDOLBY = 0x00100000, /* Wii / 3DS - Disable Dolby Pro Logic surround. Speakermode will be set to STEREO even if user has selected surround in the system settings. */ + WII_DISABLEDOLBY = 0x00100000, /* Wii only - Disable Dolby Pro Logic surround. Speakermode will be set to STEREO even if user has selected surround in the Wii system settings. */ + _360_MUSICMUTENOTPAUSE = 0x00200000, /* Xbox 360 only - The "music" channelgroup which by default pauses when custom 360 dashboard music is played, can be changed to mute (therefore continues playing) instead of pausing, by using this flag. */ + SYNCMIXERWITHUPDATE = 0x00400000, /* Win32/Wii/PS3/Xbox 360 - FMOD Mixer thread is woken up to do a mix when System::update is called rather than waking periodically on its own timer. */ + DTS_NEURALSURROUND = 0x02000000, /* Win32/Mac/Linux - Use DTS Neural surround downmixing from 7.1 if speakermode set to FMOD_SPEAKERMODE_STEREO or FMOD_SPEAKERMODE_5POINT1. Internal DSP structure will be set to 7.1. */ + GEOMETRY_USECLOSEST = 0x04000000, /* All platforms - With the geometry engine, only process the closest polygon rather than accumulating all polygons the sound to listener line intersects. */ + DISABLE_MYEARS_AUTODETECT = 0x08000000 /* Win32 - Disables automatic setting of FMOD_SPEAKERMODE_STEREO to FMOD_SPEAKERMODE_MYEARS if the MyEars profile exists on the PC. MyEars is HRTF 7.1 downmixing through headphones. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These definitions describe the type of song being played. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getFormat + ] + */ + public enum SOUND_TYPE + { + UNKNOWN, /* 3rd party / unknown plugin format. */ + AIFF, /* AIFF. */ + ASF, /* Microsoft Advanced Systems Format (ie WMA/ASF/WMV). */ + AT3, /* Sony ATRAC 3 format */ + CDDA, /* Digital CD audio. */ + DLS, /* Sound font / downloadable sound bank. */ + FLAC, /* FLAC lossless codec. */ + FSB, /* FMOD Sample Bank. */ + GCADPCM, /* GameCube ADPCM */ + IT, /* Impulse Tracker. */ + MIDI, /* MIDI. */ + MOD, /* Protracker / Fasttracker MOD. */ + MPEG, /* MP2/MP3 MPEG. */ + OGGVORBIS, /* Ogg vorbis. */ + PLAYLIST, /* Information only from ASX/PLS/M3U/WAX playlists */ + RAW, /* Raw PCM data. */ + S3M, /* ScreamTracker 3. */ + SF2, /* Sound font 2 format. */ + USER, /* User created sound. */ + WAV, /* Microsoft WAV. */ + XM, /* FastTracker 2 XM. */ + XMA, /* Xbox360 XMA */ + VAG, /* PlayStation Portable adpcm VAG format. */ + AUDIOQUEUE, /* iPhone hardware decoder, supports AAC, ALAC and MP3. */ + XWMA, /* Xbox360 XWMA */ + BCWAV, /* 3DS BCWAV container format for DSP ADPCM and PCM */ + AT9, /* NGP ATRAC 9 format */ + VORBIS, /* Raw vorbis */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These definitions describe the native format of the hardware or software buffer that will be used. + + [REMARKS] + This is the format the native hardware or software buffer will be or is created in. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createSoundEx + Sound::getFormat + ] + */ + public enum SOUND_FORMAT :int + { + NONE, /* Unitialized / unknown */ + PCM8, /* 8bit integer PCM data */ + PCM16, /* 16bit integer PCM data */ + PCM24, /* 24bit integer PCM data */ + PCM32, /* 32bit integer PCM data */ + PCMFLOAT, /* 32bit floating point PCM data */ + GCADPCM, /* Compressed GameCube DSP data */ + IMAADPCM, /* Compressed XBox ADPCM data */ + VAG, /* Compressed PlayStation 2 ADPCM data */ + HEVAG, /* Compressed NGP ADPCM data. */ + XMA, /* Compressed Xbox360 data. */ + MPEG, /* Compressed MPEG layer 2 or 3 data. */ + MAX, /* Maximum number of sound formats supported. */ + CELT, /* Compressed CELT data. */ + AT9, /* Compressed ATRAC9 data. */ + XWMA, /* Compressed Xbox360 xWMA data. */ + VORBIS, /* Compressed Vorbis data. */ + } + + + /* + [DEFINE] + [ + [NAME] + FMOD_MODE + + [DESCRIPTION] + Sound description bitfields, bitwise OR them together for loading and describing sounds. + + [REMARKS] + By default a sound will open as a static sound that is decompressed fully into memory.
    + To have a sound stream instead, use FMOD_CREATESTREAM.
    + Some opening modes (ie FMOD_OPENUSER, FMOD_OPENMEMORY, FMOD_OPENRAW) will need extra information.
    + This can be provided using the FMOD_CREATESOUNDEXINFO structure. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createSound + System::createStream + Sound::setMode + Sound::getMode + Channel::setMode + Channel::getMode + Sound::set3DCustomRolloff + Channel::set3DCustomRolloff + ] + */ + public enum MODE :uint + { + DEFAULT = 0x00000000, /* FMOD_DEFAULT is a default sound type. Equivalent to all the defaults listed below. FMOD_LOOP_OFF, FMOD_2D, FMOD_HARDWARE. */ + LOOP_OFF = 0x00000001, /* For non looping sounds. (default). Overrides FMOD_LOOP_NORMAL / FMOD_LOOP_BIDI. */ + LOOP_NORMAL = 0x00000002, /* For forward looping sounds. */ + LOOP_BIDI = 0x00000004, /* For bidirectional looping sounds. (only works on software mixed static sounds). */ + _2D = 0x00000008, /* Ignores any 3d processing. (default). */ + _3D = 0x00000010, /* Makes the sound positionable in 3D. Overrides FMOD_2D. */ + HARDWARE = 0x00000020, /* Attempts to make sounds use hardware acceleration. (default). */ + SOFTWARE = 0x00000040, /* Makes sound reside in software. Overrides FMOD_HARDWARE. Use this for FFT, DSP, 2D multi speaker support and other software related features. */ + CREATESTREAM = 0x00000080, /* Decompress at runtime, streaming from the source provided (standard stream). Overrides FMOD_CREATESAMPLE. */ + CREATESAMPLE = 0x00000100, /* Decompress at loadtime, decompressing or decoding whole file into memory as the target sample format. (standard sample). */ + CREATECOMPRESSEDSAMPLE = 0x00000200, /* Load MP2, MP3, IMAADPCM or XMA into memory and leave it compressed. During playback the FMOD software mixer will decode it in realtime as a 'compressed sample'. Can only be used in combination with FMOD_SOFTWARE. */ + OPENUSER = 0x00000400, /* Opens a user created static sample or stream. Use FMOD_CREATESOUNDEXINFO to specify format and/or read callbacks. If a user created 'sample' is created with no read callback, the sample will be empty. Use FMOD_Sound_Lock and FMOD_Sound_Unlock to place sound data into the sound if this is the case. */ + OPENMEMORY = 0x00000800, /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. */ + OPENMEMORY_POINT = 0x10000000, /* "name_or_data" will be interpreted as a pointer to memory instead of filename for creating sounds. Use FMOD_CREATESOUNDEXINFO to specify length. This differs to FMOD_OPENMEMORY in that it uses the memory as is, without duplicating the memory into its own buffers. FMOD_SOFTWARE only. Doesn't work with FMOD_HARDWARE, as sound hardware cannot access main ram on a lot of platforms. Cannot be freed after open, only after Sound::release. Will not work if the data is compressed and FMOD_CREATECOMPRESSEDSAMPLE is not used. */ + OPENRAW = 0x00001000, /* Will ignore file format and treat as raw pcm. User may need to declare if data is FMOD_SIGNED or FMOD_UNSIGNED */ + OPENONLY = 0x00002000, /* Just open the file, dont prebuffer or read. Good for fast opens for info, or when sound::readData is to be used. */ + ACCURATETIME = 0x00004000, /* For FMOD_CreateSound - for accurate FMOD_Sound_GetLength / FMOD_Channel_SetPosition on VBR MP3, AAC and MOD/S3M/XM/IT/MIDI files. Scans file first, so takes longer to open. FMOD_OPENONLY does not affect this. */ + MPEGSEARCH = 0x00008000, /* For corrupted / bad MP3 files. This will search all the way through the file until it hits a valid MPEG header. Normally only searches for 4k. */ + NONBLOCKING = 0x00010000, /* For opening sounds and getting streamed subsounds (seeking) asyncronously. Use Sound::getOpenState to poll the state of the sound as it opens or retrieves the subsound in the background. */ + UNIQUE = 0x00020000, /* Unique sound, can only be played one at a time */ + _3D_HEADRELATIVE = 0x00040000, /* Make the sound's position, velocity and orientation relative to the listener. */ + _3D_WORLDRELATIVE = 0x00080000, /* Make the sound's position, velocity and orientation absolute (relative to the world). (DEFAULT) */ + _3D_INVERSEROLLOFF = 0x00100000, /* This sound will follow the inverse rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (DEFAULT) */ + _3D_LINEARSQUAREROLLOFF= 0x00400000, /* This sound will follow a linear-square rolloff model where mindistance = full volume, maxdistance = silence. Rolloffscale is ignored. */ + _3D_LOGROLLOFF = 0x00100000, /* This sound will follow the standard logarithmic rolloff model where mindistance = full volume, maxdistance = where sound stops attenuating, and rolloff is fixed according to the global rolloff factor. (default) */ + _3D_LINEARROLLOFF = 0x00200000, /* This sound will follow a linear rolloff model where mindistance = full volume, maxdistance = silence. */ + _3D_CUSTOMROLLOFF = 0x04000000, /* This sound will follow a rolloff model defined by Sound::set3DCustomRolloff / Channel::set3DCustomRolloff. */ + _3D_IGNOREGEOMETRY = 0x40000000, /* Is not affect by geometry occlusion. If not specified in Sound::setMode, or Channel::setMode, the flag is cleared and it is affected by geometry again. */ + CDDA_FORCEASPI = 0x00400000, /* For CDDA sounds only - use ASPI instead of NTSCSI to access the specified CD/DVD device. */ + CDDA_JITTERCORRECT = 0x00800000, /* For CDDA sounds only - perform jitter correction. Jitter correction helps produce a more accurate CDDA stream at the cost of more CPU time. */ + UNICODE = 0x01000000, /* Filename is double-byte unicode. */ + IGNORETAGS = 0x02000000, /* Skips id3v2/asf/etc tag checks when opening a sound, to reduce seek/read overhead when opening files (helps with CD performance). */ + LOWMEM = 0x08000000, /* Removes some features from samples to give a lower memory overhead, like Sound::getName. */ + LOADSECONDARYRAM = 0x20000000, /* Load sound into the secondary RAM of supported platform. On PS3, sounds will be loaded into RSX/VRAM. */ + VIRTUAL_PLAYFROMSTART = 0x80000000 /* For sounds that start virtual (due to being quiet or low importance), instead of swapping back to audible, and playing at the correct offset according to time, this flag makes the sound play from the start. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These values describe what state a sound is in after NONBLOCKING has been used to open it. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getOpenState + MODE + ] + */ + public enum OPENSTATE :int + { + READY = 0, /* Opened and ready to play */ + LOADING, /* Initial load in progress */ + ERROR, /* Failed to open - file not found, out of memory etc. See return value of Sound::getOpenState for what happened. */ + CONNECTING, /* Connecting to remote host (internet sounds only) */ + BUFFERING, /* Buffering data */ + SEEKING, /* Seeking to subsound and re-flushing stream buffer. */ + PLAYING, /* Ready and playing, but not possible to release at this time without stalling the main thread. */ + SETPOSITION, /* Seeking within a stream to a different position. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + These flags are used with SoundGroup::setMaxAudibleBehavior to determine what happens when more sounds + are played than are specified with SoundGroup::setMaxAudible. + + [REMARKS] + When using FMOD_SOUNDGROUP_BEHAVIOR_MUTE, SoundGroup::setMuteFadeSpeed can be used to stop a sudden transition. + Instead, the time specified will be used to cross fade between the sounds that go silent and the ones that become audible. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + SoundGroup::setMaxAudibleBehavior + SoundGroup::getMaxAudibleBehavior + SoundGroup::setMaxAudible + SoundGroup::getMaxAudible + SoundGroup::setMuteFadeSpeed + SoundGroup::getMuteFadeSpeed + ] + */ + public enum SOUNDGROUP_BEHAVIOR :int + { + BEHAVIOR_FAIL, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will simply fail during System::playSound. */ + BEHAVIOR_MUTE, /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will be silent, then if another sound in the group stops the sound that was silent before becomes audible again. */ + BEHAVIOR_STEALLOWEST /* Any sound played that puts the sound count over the SoundGroup::setMaxAudible setting, will steal the quietest / least important sound playing in the group. */ + } + + /* + [ENUM] + [ + [DESCRIPTION] + These callback types are used with System::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed as int unique to the type of callback.
    + See reference to FMOD_SYSTEM_CALLBACK to determine what they might mean for each type of callback.
    +
    + Note! Currently the user must call System::update for these callbacks to trigger! + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setCallback + FMOD_SYSTEM_CALLBACK + System::update + ] + */ + public enum SYSTEM_CALLBACKTYPE :int + { + DEVICELISTCHANGED, /* Called when the enumerated list of devices has changed. */ + DEVICELOST, /* Called from System::update when an output device has been lost due to control panel parameter changes and FMOD cannot automatically recover. */ + MEMORYALLOCATIONFAILED, /* Called directly when a memory allocation fails somewhere in FMOD. */ + THREADCREATED, /* Called directly when a thread is created. */ + BADDSPCONNECTION, /* Called when a bad connection was made with DSP::addInput. Usually called from mixer thread because that is where the connections are made. */ + BADDSPLEVEL, /* Called when too many effects were added exceeding the maximum tree depth of 128. This is most likely caused by accidentally adding too many DSP effects. Usually called from mixer thread because that is where the connections are made. */ + + MAX /* Maximum number of callback types supported. */ + } + + /* + [ENUM] + [ + [DESCRIPTION] + These callback types are used with Channel::setCallback. + + [REMARKS] + Each callback has commanddata parameters passed int unique to the type of callback. + See reference to FMOD_CHANNEL_CALLBACK to determine what they might mean for each type of callback. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Channel::setCallback + FMOD_CHANNEL_CALLBACK + ] + */ + public enum CHANNEL_CALLBACKTYPE :int + { + END, /* Called when a sound ends. */ + VIRTUALVOICE, /* Called when a voice is swapped out or swapped in. */ + SYNCPOINT, /* Called when a syncpoint is encountered. Can be from wav file markers. */ + OCCLUSION, /* Called when the channel has its geometry occlusion value calculated. Can be used to clamp or change the value. */ + + MAX + } + + + /* + FMOD Callbacks + */ + public delegate RESULT SYSTEM_CALLBACK (IntPtr systemraw, SYSTEM_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2); + + public delegate RESULT CHANNEL_CALLBACK (IntPtr channelraw, CHANNEL_CALLBACKTYPE type, IntPtr commanddata1, IntPtr commanddata2); + + public delegate RESULT SOUND_NONBLOCKCALLBACK (IntPtr soundraw, RESULT result); + public delegate RESULT SOUND_PCMREADCALLBACK (IntPtr soundraw, IntPtr data, uint datalen); + public delegate RESULT SOUND_PCMSETPOSCALLBACK (IntPtr soundraw, int subsound, uint position, TIMEUNIT postype); + + public delegate RESULT FILE_OPENCALLBACK ([MarshalAs(UnmanagedType.LPWStr)]string name, int unicode, ref uint filesize, ref IntPtr handle, ref IntPtr userdata); + public delegate RESULT FILE_CLOSECALLBACK (IntPtr handle, IntPtr userdata); + public delegate RESULT FILE_READCALLBACK (IntPtr handle, IntPtr buffer, uint sizebytes, ref uint bytesread, IntPtr userdata); + public delegate RESULT FILE_SEEKCALLBACK (IntPtr handle, int pos, IntPtr userdata); + public delegate RESULT FILE_ASYNCREADCALLBACK (IntPtr handle, IntPtr info, IntPtr userdata); + public delegate RESULT FILE_ASYNCCANCELCALLBACK (IntPtr handle, IntPtr userdata); + + public delegate float CB_3D_ROLLOFFCALLBACK (IntPtr channelraw, float distance); + + /* + [ENUM] + [ + [DESCRIPTION] + List of windowing methods used in spectrum analysis to reduce leakage / transient signals intefering with the analysis. + This is a problem with analysis of continuous signals that only have a small portion of the signal sample (the fft window size). + Windowing the signal with a curve or triangle tapers the sides of the fft window to help alleviate this problem. + + [REMARKS] + Cyclic signals such as a sine wave that repeat their cycle in a multiple of the window size do not need windowing. + I.e. If the sine wave repeats every 1024, 512, 256 etc samples and the FMOD fft window is 1024, then the signal would not need windowing. + Not windowing is the same as FMOD_DSP_FFT_WINDOW_RECT, which is the default. + If the cycle of the signal (ie the sine wave) is not a multiple of the window size, it will cause frequency abnormalities, so a different windowing method is needed. + + + FMOD_DSP_FFT_WINDOW_RECT. + + + FMOD_DSP_FFT_WINDOW_TRIANGLE. + + + FMOD_DSP_FFT_WINDOW_HAMMING. + + + FMOD_DSP_FFT_WINDOW_HANNING. + + + FMOD_DSP_FFT_WINDOW_BLACKMAN. + + + FMOD_DSP_FFT_WINDOW_BLACKMANHARRIS. + + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::getSpectrum + Channel::getSpectrum + ] + */ + public enum DSP_FFT_WINDOW :int + { + RECT, /* w[n] = 1.0 */ + TRIANGLE, /* w[n] = TRI(2n/N) */ + HAMMING, /* w[n] = 0.54 - (0.46 * COS(n/N) ) */ + HANNING, /* w[n] = 0.5 * (1.0 - COS(n/N) ) */ + BLACKMAN, /* w[n] = 0.42 - (0.5 * COS(n/N) ) + (0.08 * COS(2.0 * n/N) ) */ + BLACKMANHARRIS, /* w[n] = 0.35875 - (0.48829 * COS(1.0 * n/N)) + (0.14128 * COS(2.0 * n/N)) - (0.01168 * COS(3.0 * n/N)) */ + + MAX + } + + + /* + [ENUM] + [ + [DESCRIPTION] + List of interpolation types that the FMOD Ex software mixer supports. + + [REMARKS] + The default resampler type is FMOD_DSP_RESAMPLER_LINEAR.
    + Use System::setSoftwareFormat to tell FMOD the resampling quality you require for FMOD_SOFTWARE based sounds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setSoftwareFormat + System::getSoftwareFormat + ] + */ + public enum DSP_RESAMPLER :int + { + NOINTERP, /* No interpolation. High frequency aliasing hiss will be audible depending on the sample rate of the sound. */ + LINEAR, /* Linear interpolation (default method). Fast and good quality, causes very slight lowpass effect on low frequency sounds. */ + CUBIC, /* Cubic interpolation. Slower than linear interpolation but better quality. */ + SPLINE, /* 5 point spline interpolation. Slowest resampling method but best quality. */ + + MAX, /* Maximum number of resample methods supported. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + List of tag types that could be stored within a sound. These include id3 tags, metadata from netstreams and vorbis/asf data. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getTag + ] + */ + public enum TAGTYPE :int + { + UNKNOWN = 0, + ID3V1, + ID3V2, + VORBISCOMMENT, + SHOUTCAST, + ICECAST, + ASF, + MIDI, + PLAYLIST, + FMOD, + USER + } + + + /* + [ENUM] + [ + [DESCRIPTION] + List of data types that can be returned by Sound::getTag + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getTag + ] + */ + public enum TAGDATATYPE :int + { + BINARY = 0, + INT, + FLOAT, + STRING, + STRING_UTF16, + STRING_UTF16BE, + STRING_UTF8, + CDTOC + } + + /* + [ENUM] + [ + [DESCRIPTION] + Types of delay that can be used with Channel::setDelay / Channel::getDelay. + + [REMARKS] + If you haven't called Channel::setDelay yet, if you call Channel::getDelay with FMOD_DELAYTYPE_DSPCLOCK_START it will return the + equivalent global DSP clock value to determine when a channel started, so that you can use it for other channels to sync against.
    +
    + Use System::getDSPClock to also get the current dspclock time, a base for future calls to Channel::setDelay.
    +
    + Use FMOD_64BIT_ADD or FMOD_64BIT_SUB to add a hi/lo combination together and cope with wraparound. +
    + If FMOD_DELAYTYPE_END_MS is specified, the value is not treated as a 64 bit number, just the delayhi value is used and it is treated as milliseconds. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Channel::setDelay + Channel::getDelay + System::getDSPClock + ] + */ + public enum DELAYTYPE :int + { + END_MS, /* Delay at the end of the sound in milliseconds. Use delayhi only. Channel::isPlaying will remain true until this delay has passed even though the sound itself has stopped playing.*/ + DSPCLOCK_START, /* Time the sound started if Channel::getDelay is used, or if Channel::setDelay is used, the sound will delay playing until this exact tick. */ + DSPCLOCK_END, /* Time the sound should end. If this is non-zero, the channel will go silent at this exact tick. */ + DSPCLOCK_PAUSE, /* Time the sound should pause. If this is non-zero, the channel will pause at this exact tick. */ + + MAX /* Maximum number of tag datatypes supported. */ + } + + public class DELAYTYPE_UTILITY + { + void FMOD_64BIT_ADD(ref uint hi1, ref uint lo1, uint hi2, uint lo2) + { + hi1 += (uint)((hi2) + ((((lo1) + (lo2)) < (lo1)) ? 1 : 0)); + lo1 += (lo2); + } + + void FMOD_64BIT_SUB(ref uint hi1, ref uint lo1, uint hi2, uint lo2) + { + hi1 -= (uint)((hi2) + ((((lo1) - (lo2)) > (lo1)) ? 1 : 0)); + lo1 -= (lo2); + } + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure describing a piece of tag data. + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getTag + TAGTYPE + TAGDATATYPE + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct TAG + { + public TAGTYPE type; /* [out] The type of this tag. */ + public TAGDATATYPE datatype; /* [out] The type of data that this tag contains */ + public IntPtr namePtr; /* [out] The name of this tag i.e. "TITLE", "ARTIST" etc. */ + public IntPtr data; /* [out] Pointer to the tag data - its format is determined by the datatype member */ + public uint datalen; /* [out] Length of the data contained in this tag */ + public bool updated; /* [out] True if this tag has been updated since last being accessed with Sound::getTag */ + + public string name { get { return Marshal.PtrToStringAnsi(namePtr); } } + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure describing a CD/DVD table of contents + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getTag + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct CDTOC + { + public int numtracks; /* [out] The number of tracks on the CD */ + [MarshalAs(UnmanagedType.ByValArray,SizeConst=100)] + public int[] min; /* [out] The start offset of each track in minutes */ + [MarshalAs(UnmanagedType.ByValArray,SizeConst=100)] + public int[] sec; /* [out] The start offset of each track in seconds */ + [MarshalAs(UnmanagedType.ByValArray,SizeConst=100)] + public int[] frame; /* [out] The start offset of each track in frames */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + List of time types that can be returned by Sound::getLength and used with Channel::setPosition or Channel::getPosition. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Sound::getLength + Channel::setPosition + Channel::getPosition + ] + */ + public enum TIMEUNIT + { + MS = 0x00000001, /* Milliseconds. */ + PCM = 0x00000002, /* PCM Samples, related to milliseconds * samplerate / 1000. */ + PCMBYTES = 0x00000004, /* Bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ + RAWBYTES = 0x00000008, /* Raw file bytes of (compressed) sound data (does not include headers). Only used by Sound::getLength and Channel::getPosition. */ + PCMFRACTION = 0x00000010, /* Fractions of 1 PCM sample. Unsigned int range 0 to 0xFFFFFFFF. Used for sub-sample granularity for DSP purposes. */ + MODORDER = 0x00000100, /* MOD/S3M/XM/IT. Order in a sequenced module format. Use Sound::getFormat to determine the format. */ + MODROW = 0x00000200, /* MOD/S3M/XM/IT. Current row in a sequenced module format. Sound::getLength will return the number if rows in the currently playing or seeked to pattern. */ + MODPATTERN = 0x00000400, /* MOD/S3M/XM/IT. Current pattern in a sequenced module format. Sound::getLength will return the number of patterns in the song and Channel::getPosition will return the currently playing pattern. */ + SENTENCE_MS = 0x00010000, /* Currently playing subsound in a sentence time in milliseconds. */ + SENTENCE_PCM = 0x00020000, /* Currently playing subsound in a sentence time in PCM Samples, related to milliseconds * samplerate / 1000. */ + SENTENCE_PCMBYTES = 0x00040000, /* Currently playing subsound in a sentence time in bytes, related to PCM samples * channels * datawidth (ie 16bit = 2 bytes). */ + SENTENCE = 0x00080000, /* Currently playing sentence index according to the channel. */ + SENTENCE_SUBSOUND = 0x00100000, /* Currently playing subsound index in a sentence. */ + BUFFERED = 0x10000000, /* Time value as seen by buffered stream. This is always ahead of audible time, and is only used for processing. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + When creating a multichannel sound, FMOD will pan them to their default speaker locations, for example a 6 channel sound will default to one channel per 5.1 output speaker.
    + Another example is a stereo sound. It will default to left = front left, right = front right.
    +
    + This is for sounds that are not 'default'. For example you might have a sound that is 6 channels but actually made up of 3 stereo pairs, that should all be located in front left, front right only. + + [REMARKS] + For full flexibility of speaker assignments, use Channel::setSpeakerLevels. This functionality is cheaper, uses less memory and easier to use. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + FMOD_CREATESOUNDEXINFO + Channel::setSpeakerLevels + ] + */ + public enum SPEAKERMAPTYPE + { + DEFAULT, /* This is the default, and just means FMOD decides which speakers it puts the source channels. */ + ALLMONO, /* This means the sound is made up of all mono sounds. All voices will be panned to the front center by default in this case. */ + ALLSTEREO, /* This means the sound is made up of all stereo sounds. All voices will be panned to front left and front right alternating every second channel. */ + _51_PROTOOLS /* Map a 5.1 sound to use protools L C R Ls Rs LFE mapping. Will return an error if not a 6 channel sound. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Use this structure with System::createSound when more control is needed over loading. + The possible reasons to use this with System::createSound are: +
  • Loading a file from memory. +
  • Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. +
  • To create a user created / non file based sound. +
  • To specify a starting subsound to seek to within a multi-sample sounds (ie FSB/DLS/SF2) when created as a stream. +
  • To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. +
  • To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. +
  • To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + See below on what members to fill for each of the above types of sound you want to create. + + [REMARKS] + This structure is optional! Specify 0 or NULL in System::createSound if you don't need it! + + Members marked with [in] mean the user sets the value before passing it to the function. + Members marked with [out] mean FMOD sets the value to be used after the function exits. + + Loading a file from memory. +
  • Create the sound using the FMOD_OPENMEMORY flag. +
  • Mandantory. Specify 'length' for the size of the memory block in bytes. +
  • Other flags are optional. + + + Loading a file from within another larger (possibly wad/pak) file, by giving the loader an offset and length. +
  • Mandantory. Specify 'fileoffset' and 'length'. +
  • Other flags are optional. + + + To create a user created / non file based sound. +
  • Create the sound using the FMOD_OPENUSER flag. +
  • Mandantory. Specify 'defaultfrequency, 'numchannels' and 'format'. +
  • Other flags are optional. + + + To specify a starting subsound to seek to and flush with, within a multi-sample stream (ie FSB/DLS/SF2). + +
  • Mandantory. Specify 'initialsubsound'. + + + To specify which subsounds to load for multi-sample sounds (ie FSB/DLS/SF2) so that memory is saved and only a subset is actually loaded/read from disk. + +
  • Mandantory. Specify 'inclusionlist' and 'inclusionlistnum'. + + + To specify 'piggyback' read and seek callbacks for capture of sound data as fmod reads and decodes it. Useful for ripping decoded PCM data from sounds as they are loaded / played. + +
  • Mandantory. Specify 'pcmreadcallback' and 'pcmseekcallback'. + + + To specify a MIDI DLS/SF2 sample set file to load when opening a MIDI file. + +
  • Mandantory. Specify 'dlsname'. + + + Setting the 'decodebuffersize' is for cpu intensive codecs that may be causing stuttering, not file intensive codecs (ie those from CD or netstreams) which are normally altered with System::setStreamBufferSize. As an example of cpu intensive codecs, an mp3 file will take more cpu to decode than a PCM wav file. + If you have a stuttering effect, then it is using more cpu than the decode buffer playback rate can keep up with. Increasing the decode buffersize will most likely solve this problem. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createSound + System::setStreamBufferSize + FMOD_MODE + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct CREATESOUNDEXINFO + { + public int cbsize; /* [in] Size of this structure. This is used so the structure can be expanded in the future and still work on older versions of FMOD Ex. */ + public uint length; /* [in] Optional. Specify 0 to ignore. Size in bytes of file to load, or sound to create (in this case only if FMOD_OPENUSER is used). Required if loading from memory. If 0 is specified, then it will use the size of the file (unless loading from memory then an error will be returned). */ + public uint fileoffset; /* [in] Optional. Specify 0 to ignore. Offset from start of the file to start loading from. This is useful for loading files from inside big data files. */ + public int numchannels; /* [in] Optional. Specify 0 to ignore. Number of channels in a sound specified only if OPENUSER is used. */ + public int defaultfrequency; /* [in] Optional. Specify 0 to ignore. Default frequency of sound in a sound specified only if OPENUSER is used. Other formats use the frequency determined by the file format. */ + public SOUND_FORMAT format; /* [in] Optional. Specify 0 or SOUND_FORMAT_NONE to ignore. Format of the sound specified only if OPENUSER is used. Other formats use the format determined by the file format. */ + public uint decodebuffersize; /* [in] Optional. Specify 0 to ignore. For streams. This determines the size of the double buffer (in PCM samples) that a stream uses. Use this for user created streams if you want to determine the size of the callback buffer passed to you. Specify 0 to use FMOD's default size which is currently equivalent to 400ms of the sound format created/loaded. */ + public int initialsubsound; /* [in] Optional. Specify 0 to ignore. In a multi-sample file format such as .FSB/.DLS/.SF2, specify the initial subsound to seek to, only if CREATESTREAM is used. */ + public int numsubsounds; /* [in] Optional. Specify 0 to ignore or have no subsounds. In a user created multi-sample sound, specify the number of subsounds within the sound that are accessable with Sound::getSubSound / SoundGetSubSound. */ + public IntPtr inclusionlist; /* [in] Optional. Specify 0 to ignore. In a multi-sample format such as .FSB/.DLS/.SF2 it may be desirable to specify only a subset of sounds to be loaded out of the whole file. This is an array of subsound indicies to load into memory when created. */ + public int inclusionlistnum; /* [in] Optional. Specify 0 to ignore. This is the number of integers contained within the */ + public SOUND_PCMREADCALLBACK pcmreadcallback; /* [in] Optional. Specify 0 to ignore. Callback to 'piggyback' on FMOD's read functions and accept or even write PCM data while FMOD is opening the sound. Used for user sounds created with OPENUSER or for capturing decoded data as FMOD reads it. */ + public SOUND_PCMSETPOSCALLBACK pcmsetposcallback; /* [in] Optional. Specify 0 to ignore. Callback for when the user calls a seeking function such as Channel::setPosition within a multi-sample sound, and for when it is opened.*/ + public SOUND_NONBLOCKCALLBACK nonblockcallback; /* [in] Optional. Specify 0 to ignore. Callback for successful completion, or error while loading a sound that used the FMOD_NONBLOCKING flag.*/ + public string dlsname; /* [in] Optional. Specify 0 to ignore. Filename for a DLS or SF2 sample set when loading a MIDI file. If not specified, on windows it will attempt to open /windows/system32/drivers/gm.dls, otherwise the MIDI will fail to open. */ + public string encryptionkey; /* [in] Optional. Specify 0 to ignore. Key for encrypted FSB file. Without this key an encrypted FSB file will not load. */ + public int maxpolyphony; /* [in] Optional. Specify 0 to ingore. For sequenced formats with dynamic channel allocation such as .MID and .IT, this specifies the maximum voice count allowed while playing. .IT defaults to 64. .MID defaults to 32. */ + public IntPtr userdata; /* [in] Optional. Specify 0 to ignore. This is user data to be attached to the sound during creation. Access via Sound::getUserData. */ + public SOUND_TYPE suggestedsoundtype; /* [in] Optional. Specify 0 or FMOD_SOUND_TYPE_UNKNOWN to ignore. Instead of scanning all codec types, use this to speed up loading by making it jump straight to this codec. */ + public FILE_OPENCALLBACK useropen; /* [in] Optional. Specify 0 to ignore. Callback for opening this file. */ + public FILE_CLOSECALLBACK userclose; /* [in] Optional. Specify 0 to ignore. Callback for closing this file. */ + public FILE_READCALLBACK userread; /* [in] Optional. Specify 0 to ignore. Callback for reading from this file. */ + public FILE_SEEKCALLBACK userseek; /* [in] Optional. Specify 0 to ignore. Callback for seeking within this file. */ + public FILE_ASYNCREADCALLBACK userasyncread; /* [in] Optional. Specify 0 to ignore. Callback for asyncronously reading from this file. */ + public FILE_ASYNCCANCELCALLBACK userasynccancel; /* [in] Optional. Specify 0 to ignore. Callback for cancelling an asyncronous read. */ + public SPEAKERMAPTYPE speakermap; /* [in] Optional. Specify 0 to ignore. Use this to differ the way fmod maps multichannel sounds to speakers. See FMOD_SPEAKERMAPTYPE for more. */ + public IntPtr initialsoundgroup; /* [in] Optional. Specify 0 to ignore. Specify a sound group if required, to put sound in as it is created. */ + public uint initialseekposition; /* [in] Optional. Specify 0 to ignore. For streams. Specify an initial position to seek the stream to. */ + public TIMEUNIT initialseekpostype; /* [in] Optional. Specify 0 to ignore. For streams. Specify the time unit for the position set in initialseekposition. */ + public int ignoresetfilesystem; /* [in] Optional. Specify 0 to ignore. Set to 1 to use fmod's built in file system. Ignores setFileSystem callbacks and also FMOD_CREATESOUNEXINFO file callbacks. Useful for specific cases where you don't want to use your own file system but want to use fmod's file system (ie net streaming). */ + public int cddaforceaspi; /* [in] Optional. Specify 0 to ignore. For CDDA sounds only - if non-zero use ASPI instead of NTSCSI to access the specified CD/DVD device. */ + public uint audioqueuepolicy; /* [in] Optional. Specify 0 or FMOD_AUDIOQUEUE_CODECPOLICY_DEFAULT to ignore. Policy used to determine whether hardware or software is used for decoding, see FMOD_AUDIOQUEUE_CODECPOLICY for options (iOS >= 3.0 required, otherwise only hardware is available) */ + public uint minmidigranularity; /* [in] Optional. Specify 0 to ignore. Allows you to set a minimum desired MIDI mixer granularity. Values smaller than 512 give greater than default accuracy at the cost of more CPU and vise versa. Specify 0 for default (512 samples). */ + public int nonblockthreadid; /* [in] Optional. Specify 0 to ignore. Specifies a thread index to execute non blocking load on. Allows for up to 5 threads to be used for loading at once. This is to avoid one load blocking another. Maximum value = 4. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure defining a reverb environment.
    +
    + For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section.
    + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + [REMARKS] + Note the default reverb properties are the same as the FMOD_PRESET_GENERIC preset.
    + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras float values are always linear.
    +
    + The numerical values listed below are the maximum, minimum and default values for each variable respectively.
    +
    + SUPPORTED next to each parameter means the platform the parameter can be set on. Some platforms support all parameters and some don't.
    + EAX means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 1 to 4.
    + EAX4 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support EAX 4.
    + I3DL2 means hardware reverb on FMOD_OUTPUTTYPE_DSOUND on windows only (must use FMOD_HARDWARE), on soundcards that support I3DL2 non EAX native reverb.
    + GC means Nintendo Gamecube hardware reverb (must use FMOD_HARDWARE).
    + WII means Nintendo Wii hardware reverb (must use FMOD_HARDWARE).
    + PS2 means Playstation 2 hardware reverb (must use FMOD_HARDWARE).
    + SFX means FMOD SFX software reverb. This works on any platform that uses FMOD_SOFTWARE for loading sounds.
    +
    + Members marked with [in] mean the user sets the value before passing it to the function.
    + Members marked with [out] mean FMOD sets the value to be used after the function exits.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setReverbProperties + System::getReverbProperties + FMOD_REVERB_PRESETS + FMOD_REVERB_FLAGS + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct REVERB_PROPERTIES + { /* MIN MAX DEFAULT DESCRIPTION */ + public int Instance; /* [in] 0 , 3 , 0 , EAX4 only. Environment Instance. 3 seperate reverbs simultaneously are possible. This specifies which one to set. (win32 only) */ + public int Environment; /* [in/out] -1 , 25 , -1 , sets all listener properties (win32/ps2) */ + public float EnvDiffusion; /* [in/out] 0.0 , 1.0 , 1.0 , environment diffusion (win32/xbox) */ + public int Room; /* [in/out] -10000, 0 , -1000 , room effect level (at mid frequencies) (win32/xbox) */ + public int RoomHF; /* [in/out] -10000, 0 , -100 , relative room effect level at high frequencies (win32/xbox) */ + public int RoomLF; /* [in/out] -10000, 0 , 0 , relative room effect level at low frequencies (win32 only) */ + public float DecayTime; /* [in/out] 0.1 , 20.0 , 1.49 , reverberation decay time at mid frequencies (win32/xbox) */ + public float DecayHFRatio; /* [in/out] 0.1 , 2.0 , 0.83 , high-frequency to mid-frequency decay time ratio (win32/xbox) */ + public float DecayLFRatio; /* [in/out] 0.1 , 2.0 , 1.0 , low-frequency to mid-frequency decay time ratio (win32 only) */ + public int Reflections; /* [in/out] -10000, 1000 , -2602 , early reflections level relative to room effect (win32/xbox) */ + public float ReflectionsDelay; /* [in/out] 0.0 , 0.3 , 0.007 , initial reflection delay time (win32/xbox) */ + public int Reverb; /* [in/out] -10000, 2000 , 200 , late reverberation level relative to room effect (win32/xbox) */ + public float ReverbDelay; /* [in/out] 0.0 , 0.1 , 0.011 , late reverberation delay time relative to initial reflection (win32/xbox) */ + public float ModulationTime; /* [in/out] 0.04 , 4.0 , 0.25 , modulation time (win32 only) */ + public float ModulationDepth; /* [in/out] 0.0 , 1.0 , 0.0 , modulation depth (win32 only) */ + public float HFReference; /* [in/out] 1000.0, 20000 , 5000.0 , reference high frequency (hz) (win32/xbox) */ + public float LFReference; /* [in/out] 20.0 , 1000.0, 250.0 , reference low frequency (hz) (win32 only) */ + public float Diffusion; /* [in/out] 0.0 , 100.0 , 100.0 , Value that controls the echo density in the late reverberation decay. (xbox only) */ + public float Density; /* [in/out] 0.0 , 100.0 , 100.0 , Value that controls the modal density in the late reverberation decay (xbox only) */ + public uint Flags; /* [in/out] REVERB_FLAGS - modifies the behavior of above properties (win32/ps2) */ + + #region wrapperinternal + public REVERB_PROPERTIES(int instance, int environment, float envDiffusion, int room, int roomHF, int roomLF, + float decayTime, float decayHFRatio, float decayLFRatio, int reflections, float reflectionsDelay, + int reverb, float reverbDelay, float modulationTime, float modulationDepth, float hfReference, + float lfReference, float diffusion, float density, uint flags) + { + Instance = instance; + Environment = environment; + EnvDiffusion = envDiffusion; + Room = room; + RoomHF = roomHF; + RoomLF = roomLF; + DecayTime = decayTime; + DecayHFRatio = decayHFRatio; + DecayLFRatio = decayLFRatio; + Reflections = reflections; + ReflectionsDelay = reflectionsDelay; + Reverb = reverb; + ReverbDelay = reverbDelay; + ModulationTime = modulationTime; + ModulationDepth = modulationDepth; + HFReference = hfReference; + LFReference = lfReference; + Diffusion = diffusion; + Density = density; + Flags = flags; + } + #endregion + } + + + /* + [DEFINE] + [ + [NAME] + REVERB_FLAGS + + [DESCRIPTION] + Values for the Flags member of the REVERB_PROPERTIES structure. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + REVERB_PROPERTIES + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct REVERB_FLAGS + { + public const uint HIGHQUALITYREVERB = 0x00000400; /* Wii. Use high quality reverb */ + public const uint HIGHQUALITYDPL2REVERB = 0x00000800; /* Wii. Use high quality DPL2 reverb */ + public const uint DEFAULT = 0x00000000; + } + + + /* + [DEFINE] + [ + [NAME] + FMOD_REVERB_PRESETS + + [DESCRIPTION] + A set of predefined environment PARAMETERS, created by Creative Labs + These are used to initialize an FMOD_REVERB_PROPERTIES structure statically. + ie + FMOD_REVERB_PROPERTIES prop = FMOD_PRESET_GENERIC; + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::setReverbProperties + ] + */ + class PRESET + { + /* Instance Env Diffus Room RoomHF RmLF DecTm DecHF DecLF Refl RefDel Revb RevDel ModTm ModDp HFRef LFRef Diffus Densty FLAGS */ + public REVERB_PROPERTIES OFF() { return new REVERB_PROPERTIES(0, -1, 1.00f, -10000, -10000, 0, 1.00f, 1.00f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 0.0f, 0.0f, 0x33f );} + public REVERB_PROPERTIES GENERIC() { return new REVERB_PROPERTIES(0, 0, 1.00f, -1000, -100, 0, 1.49f, 0.83f, 1.0f, -2602, 0.007f, 200, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES PADDEDCELL() { return new REVERB_PROPERTIES(0, 1, 1.00f, -1000, -6000, 0, 0.17f, 0.10f, 1.0f, -1204, 0.001f, 207, 0.002f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES ROOM() { return new REVERB_PROPERTIES(0, 2, 1.00f, -1000, -454, 0, 0.40f, 0.83f, 1.0f, -1646, 0.002f, 53, 0.003f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES BATHROOM() { return new REVERB_PROPERTIES(0, 3, 1.00f, -1000, -1200, 0, 1.49f, 0.54f, 1.0f, -370, 0.007f, 1030, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 60.0f, 0x3f );} + public REVERB_PROPERTIES LIVINGROOM() { return new REVERB_PROPERTIES(0, 4, 1.00f, -1000, -6000, 0, 0.50f, 0.10f, 1.0f, -1376, 0.003f, -1104, 0.004f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES STONEROOM() { return new REVERB_PROPERTIES(0, 5, 1.00f, -1000, -300, 0, 2.31f, 0.64f, 1.0f, -711, 0.012f, 83, 0.017f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES AUDITORIUM() { return new REVERB_PROPERTIES(0, 6, 1.00f, -1000, -476, 0, 4.32f, 0.59f, 1.0f, -789, 0.020f, -289, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES CONCERTHALL() { return new REVERB_PROPERTIES(0, 7, 1.00f, -1000, -500, 0, 3.92f, 0.70f, 1.0f, -1230, 0.020f, -2, 0.029f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES CAVE() { return new REVERB_PROPERTIES(0, 8, 1.00f, -1000, 0, 0, 2.91f, 1.30f, 1.0f, -602, 0.015f, -302, 0.022f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f );} + public REVERB_PROPERTIES ARENA() { return new REVERB_PROPERTIES(0, 9, 1.00f, -1000, -698, 0, 7.24f, 0.33f, 1.0f, -1166, 0.020f, 16, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES HANGAR() { return new REVERB_PROPERTIES(0, 10, 1.00f, -1000, -1000, 0, 10.05f, 0.23f, 1.0f, -602, 0.020f, 198, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES CARPETTEDHALLWAY() { return new REVERB_PROPERTIES(0, 11, 1.00f, -1000, -4000, 0, 0.30f, 0.10f, 1.0f, -1831, 0.002f, -1630, 0.030f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES HALLWAY() { return new REVERB_PROPERTIES(0, 12, 1.00f, -1000, -300, 0, 1.49f, 0.59f, 1.0f, -1219, 0.007f, 441, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES STONECORRIDOR() { return new REVERB_PROPERTIES(0, 13, 1.00f, -1000, -237, 0, 2.70f, 0.79f, 1.0f, -1214, 0.013f, 395, 0.020f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES ALLEY() { return new REVERB_PROPERTIES(0, 14, 0.30f, -1000, -270, 0, 1.49f, 0.86f, 1.0f, -1204, 0.007f, -4, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES FOREST() { return new REVERB_PROPERTIES(0, 15, 0.30f, -1000, -3300, 0, 1.49f, 0.54f, 1.0f, -2560, 0.162f, -229, 0.088f, 0.25f, 0.000f, 5000.0f, 250.0f, 79.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES CITY() { return new REVERB_PROPERTIES(0, 16, 0.50f, -1000, -800, 0, 1.49f, 0.67f, 1.0f, -2273, 0.007f, -1691, 0.011f, 0.25f, 0.000f, 5000.0f, 250.0f, 50.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES MOUNTAINS() { return new REVERB_PROPERTIES(0, 17, 0.27f, -1000, -2500, 0, 1.49f, 0.21f, 1.0f, -2780, 0.300f, -1434, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 27.0f, 100.0f, 0x1f );} + public REVERB_PROPERTIES QUARRY() { return new REVERB_PROPERTIES(0, 18, 1.00f, -1000, -1000, 0, 1.49f, 0.83f, 1.0f, -10000, 0.061f, 500, 0.025f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES PLAIN() { return new REVERB_PROPERTIES(0, 19, 0.21f, -1000, -2000, 0, 1.49f, 0.50f, 1.0f, -2466, 0.179f, -1926, 0.100f, 0.25f, 0.000f, 5000.0f, 250.0f, 21.0f, 100.0f, 0x3f );} + public REVERB_PROPERTIES PARKINGLOT() { return new REVERB_PROPERTIES(0, 20, 1.00f, -1000, 0, 0, 1.65f, 1.50f, 1.0f, -1363, 0.008f, -1153, 0.012f, 0.25f, 0.000f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x1f );} + public REVERB_PROPERTIES SEWERPIPE() { return new REVERB_PROPERTIES(0, 21, 0.80f, -1000, -1000, 0, 2.81f, 0.14f, 1.0f, 429, 0.014f, 1023, 0.021f, 0.25f, 0.000f, 5000.0f, 250.0f, 80.0f, 60.0f, 0x3f );} + public REVERB_PROPERTIES UNDERWATER() { return new REVERB_PROPERTIES(0, 22, 1.00f, -1000, -4000, 0, 1.49f, 0.10f, 1.0f, -449, 0.007f, 1700, 0.011f, 1.18f, 0.348f, 5000.0f, 250.0f, 100.0f, 100.0f, 0x3f );} + } + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure defining the properties for a reverb source, related to a FMOD channel. + + For more indepth descriptions of the reverb properties under win32, please see the EAX3 + documentation at http://developer.creative.com/ under the 'downloads' section. + If they do not have the EAX3 documentation, then most information can be attained from + the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of + EAX2. + + Note the default reverb properties are the same as the PRESET_GENERIC preset. + Note that integer values that typically range from -10,000 to 1000 are represented in + decibels, and are of a logarithmic scale, not linear, wheras FLOAT values are typically linear. + PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox). + Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then + the reverb should product a similar effect on either platform. + Linux and FMODCE do not support the reverb api. + + The numerical values listed below are the maximum, minimum and default values for each variable respectively. + + [REMARKS] + For EAX4 support with multiple reverb environments, set FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT0, + FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT1 or/and FMOD_REVERB_CHANNELFLAGS_ENVIRONMENT2 in the flags member + of FMOD_REVERB_CHANNELPROPERTIES to specify which environment instance(s) to target. + Only up to 2 environments to target can be specified at once. Specifying three will result in an error. + If the sound card does not support EAX4, the environment flag is ignored. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + Channel::setReverbProperties + Channel::getReverbProperties + REVERB_CHANNELFLAGS + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct REVERB_CHANNELPROPERTIES + { /* MIN MAX DEFAULT DESCRIPTION */ + public int Direct; /* [in/out] -10000, 1000, 0, direct path level (at low and mid frequencies) (win32/xbox) */ + public int Room; /* [in/out] -10000, 1000, 0, room effect level (at low and mid frequencies) (win32/xbox) */ + public uint Flags; /* [in/out] REVERB_CHANNELFLAGS - modifies the behavior of properties (win32) */ + public IntPtr ConnectionPoint; /* [in/out] See remarks. DSP network location to connect reverb for this channel. (SUPPORTED:SFX only).*/ + } + + + /* + [DEFINE] + [ + [NAME] + REVERB_CHANNELFLAGS + + [DESCRIPTION] + Values for the Flags member of the REVERB_CHANNELPROPERTIES structure. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + REVERB_CHANNELPROPERTIES + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct REVERB_CHANNELFLAGS + { + public const uint INSTANCE0 = 0x00000010; /* SFX/Wii. Specify channel to target reverb instance 0. Default target. */ + public const uint INSTANCE1 = 0x00000020; /* SFX/Wii. Specify channel to target reverb instance 1. */ + public const uint INSTANCE2 = 0x00000040; /* SFX/Wii. Specify channel to target reverb instance 2. */ + public const uint INSTANCE3 = 0x00000080; /* SFX. Specify channel to target reverb instance 3. */ + public const uint DEFAULT = INSTANCE0; + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Settings for advanced features like configuring memory and cpu usage for the FMOD_CREATECOMPRESSEDSAMPLE feature. + + [REMARKS] + maxMPEGcodecs / maxADPCMcodecs / maxXMAcodecs will determine the maximum cpu usage of playing realtime samples. Use this to lower potential excess cpu usage and also control memory usage.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + System::setAdvancedSettings + System::getAdvancedSettings + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct ADVANCEDSETTINGS + { + public int cbsize; /* Size of structure. Use sizeof(FMOD_ADVANCEDSETTINGS) */ + public int maxMPEGcodecs; /* For use with FMOD_CREATECOMPRESSEDSAMPLE only. Mpeg codecs consume 48,696 per instance and this number will determine how many mpeg channels can be played simultaneously. Default = 16. */ + public int maxADPCMcodecs; /* For use with FMOD_CREATECOMPRESSEDSAMPLE only. ADPCM codecs consume 1k per instance and this number will determine how many ADPCM channels can be played simultaneously. Default = 32. */ + public int maxXMAcodecs; /* For use with FMOD_CREATECOMPRESSEDSAMPLE only. XMA codecs consume 8k per instance and this number will determine how many XMA channels can be played simultaneously. Default = 32. */ + public int maxPCMcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with PS3 only. PCM codecs consume 12,672 bytes per instance and this number will determine how many streams and PCM voices can be played simultaneously. Default = 16 */ + public int maxCELTcodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. CELT codecs consume 11,500 bytes per instance and this number will determine how many CELT channels can be played simultaneously. Default = 16 */ + public int maxVORBIScodecs; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_CREATECOMPRESSEDSAMPLE only. Vorbis codecs consume 12,000 bytes per instance and this number will determine how many Vorbis channels can be played simultaneously. Default = 32. */ + public int ASIONumChannels; /* [in/out] */ + public IntPtr ASIOChannelList; /* [in/out] */ + public IntPtr ASIOSpeakerList; /* [in/out] Optional. Specify 0 to ignore. Pointer to a list of speakers that the ASIO channels map to. This can be called after System::init to remap ASIO output. */ + public int max3DReverbDSPs; /* [in/out] The max number of 3d reverb DSP's in the system. */ + public float HRTFMinAngle; /* [in/out] For use with FMOD_INIT_HRTF_LOWPASS. The angle (0-360) of a 3D sound from the listener's forward vector at which the HRTF function begins to have an effect. Default = 180.0. */ + public float HRTFMaxAngle; /* [in/out] For use with FMOD_INIT_HRTF_LOWPASS. The angle (0-360) of a 3D sound from the listener's forward vector at which the HRTF function begins to have maximum effect. Default = 360.0. */ + public float HRTFFreq; /* [in/out] For use with FMOD_INIT_HRTF_LOWPASS. The cutoff frequency of the HRTF's lowpass filter function when at maximum effect. (i.e. at HRTFMaxAngle). Default = 4000.0. */ + public float vol0virtualvol; /* [in/out] For use with FMOD_INIT_VOL0_BECOMES_VIRTUAL. If this flag is used, and the volume is 0.0, then the sound will become virtual. Use this value to raise the threshold to a different point where a sound goes virtual. */ + public int eventqueuesize; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD Event system only. Specifies the number of slots available for simultaneous non blocking loads. Default = 32. */ + public uint defaultDecodeBufferSize; /* [in/out] Optional. Specify 0 to ignore. For streams. This determines the default size of the double buffer (in milliseconds) that a stream uses. Default = 400ms */ + public string debugLogFilename; /* [in/out] Optional. Specify 0 to ignore. Gives fmod's logging system a path/filename. Normally the log is placed in the same directory as the executable and called fmod.log. When using System::getAdvancedSettings, provide at least 256 bytes of memory to copy into. */ + public ushort profileport; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_ENABLE_PROFILE. Specify the port to listen on for connections by the profiler application. */ + public uint geometryMaxFadeTime; /* [in/out] Optional. Specify 0 to ignore. The maximum time in miliseconds it takes for a channel to fade to the new level when its occlusion changes. */ + public uint maxSpectrumWaveDataBuffers; /* [in/out] Optional. Specify 0 to ignore. The maximum number of buffers for use with getWaveData/getSpectrum. */ + public uint musicSystemCacheDelay; /* [in/out] Optional. Specify 0 to ignore. The delay the music system should allow for loading a sample from disk (in milliseconds). Default = 400 ms. */ + public float distanceFilterCenterFreq; /* [in/out] Optional. Specify 0 to ignore. For use with FMOD_INIT_DISTANCE_FILTERING. The default center frequency in Hz for the distance filtering effect. Default = 1500.0. */ + public uint stackSizeStream; /* [in/out] Optional. Specify 0 to ignore. Specify the stack size for the FMOD Stream thread in bytes. Useful for custom codecs that use excess stack. Default 49,152 (48kb) */ + public uint stackSizeNonBlocking; /* [in/out] Optional. Specify 0 to ignore. Specify the stack size for the FMOD_NONBLOCKING loading thread. Useful for custom codecs that use excess stack. Default 65,536 (64kb) */ + public uint stackSizeMixer; /* [in/out] Optional. Specify 0 to ignore. Specify the stack size for the FMOD mixer thread. Useful for custom dsps that use excess stack. Default 49,152 (48kb) */ + } + + + /* + [ENUM] + [ + [NAME] + FMOD_MISC_VALUES + + [DESCRIPTION] + Miscellaneous values for FMOD functions. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox360, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::playSound + System::playDSP + System::getChannel + ] + */ + public enum CHANNELINDEX + { + FREE = -1, /* For a channel index, FMOD chooses a free voice using the priority system. */ + REUSE = -2 /* For a channel index, re-use the channel handle that was passed in. */ + } + + + /* + FMOD System factory functions. Use this to create an FMOD System Instance. below you will see System_Init/Close to get started. + */ + public class Factory + { + public static RESULT System_Create(ref System system) + { +#if WIN64 + if (IntPtr.Size != 8) + { + /* Attempting to use 64-bit FMOD dll with 32-bit application.*/ + + return RESULT.ERR_FILE_BAD; + } +#else + if (IntPtr.Size != 4) + { + /* Attempting to use 32-bit FMOD dll with 64-bit application. A likely cause of this error + * is targetting platform 'Any CPU'. You cannot link to unmanaged dll with 'Any CPU' + * target. + * + * For 32-bit applications: set the platform to 'x86'. + * + * For 64-bit applications: + * 1. set the platform to x64 + * 2. add the conditional complication symbol WIN64 + * 3. download the win64 fmod release + * 4. copy the fmodex64.dll to the location of the .exe file for your application */ + + return RESULT.ERR_FILE_BAD; + } +#endif + + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + result = FMOD_System_Create(ref systemraw); + if (result != RESULT.OK) + { + return result; + } + + systemnew = new System(); + systemnew.setRaw(systemraw); + system = systemnew; + + return result; + } + + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Create (ref IntPtr system); + + #endregion + } + + + public class Memory + { + public static RESULT GetStats(ref int currentalloced, ref int maxalloced) + { + return FMOD_Memory_GetStats(ref currentalloced, ref maxalloced, 1); + } + + public static RESULT GetStats(ref int currentalloced, ref int maxalloced, bool blocking) + { + return FMOD_Memory_GetStats(ref currentalloced, ref maxalloced, (blocking ? 1 : 0)); + } + + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Memory_GetStats(ref int currentalloced, ref int maxalloced, int blocking); + + #endregion + } + + + /* + 'System' API + */ + public class System + { + public RESULT release () + { + return FMOD_System_Release(systemraw); + } + + + // Pre-init functions. + public RESULT setOutput (OUTPUTTYPE output) + { + return FMOD_System_SetOutput(systemraw, output); + } + public RESULT getOutput (ref OUTPUTTYPE output) + { + return FMOD_System_GetOutput(systemraw, ref output); + } + public RESULT getNumDrivers (ref int numdrivers) + { + return FMOD_System_GetNumDrivers(systemraw, ref numdrivers); + } + public RESULT getDriverInfo (int id, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder name, int namelen, ref GUID guid) + { + //use multibyte version + return FMOD_System_GetDriverInfoW(systemraw, id, name, namelen, ref guid); + } + public RESULT getDriverCaps (int id, ref CAPS caps, ref int controlpaneloutputrate, ref SPEAKERMODE controlpanelspeakermode) + { + return FMOD_System_GetDriverCaps(systemraw, id, ref caps, ref controlpaneloutputrate, ref controlpanelspeakermode); + } + public RESULT setDriver (int driver) + { + return FMOD_System_SetDriver(systemraw, driver); + } + public RESULT getDriver (ref int driver) + { + return FMOD_System_GetDriver(systemraw, ref driver); + } + public RESULT setHardwareChannels (int numhardwarechannels) + { + return FMOD_System_SetHardwareChannels(systemraw, numhardwarechannels); + } + public RESULT setSoftwareChannels (int numsoftwarechannels) + { + return FMOD_System_SetSoftwareChannels(systemraw, numsoftwarechannels); + } + public RESULT getSoftwareChannels (ref int numsoftwarechannels) + { + return FMOD_System_GetSoftwareChannels(systemraw, ref numsoftwarechannels); + } + public RESULT setSoftwareFormat (int samplerate, SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, DSP_RESAMPLER resamplemethod) + { + return FMOD_System_SetSoftwareFormat(systemraw, samplerate, format, numoutputchannels, maxinputchannels, resamplemethod); + } + public RESULT getSoftwareFormat (ref int samplerate, ref SOUND_FORMAT format, ref int numoutputchannels, ref int maxinputchannels, ref DSP_RESAMPLER resamplemethod, ref int bits) + { + return FMOD_System_GetSoftwareFormat(systemraw, ref samplerate, ref format, ref numoutputchannels, ref maxinputchannels, ref resamplemethod, ref bits); + } + public RESULT setDSPBufferSize (uint bufferlength, int numbuffers) + { + return FMOD_System_SetDSPBufferSize(systemraw, bufferlength, numbuffers); + } + public RESULT getDSPBufferSize (ref uint bufferlength, ref int numbuffers) + { + return FMOD_System_GetDSPBufferSize(systemraw, ref bufferlength, ref numbuffers); + } + public RESULT setFileSystem (FILE_OPENCALLBACK useropen, FILE_CLOSECALLBACK userclose, FILE_READCALLBACK userread, FILE_SEEKCALLBACK userseek, FILE_ASYNCREADCALLBACK userasyncread, FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign) + { + return FMOD_System_SetFileSystem(systemraw, useropen, userclose, userread, userseek, userasyncread, userasynccancel, blockalign); + } + public RESULT attachFileSystem (FILE_OPENCALLBACK useropen, FILE_CLOSECALLBACK userclose, FILE_READCALLBACK userread, FILE_SEEKCALLBACK userseek) + { + return FMOD_System_AttachFileSystem(systemraw, useropen, userclose, userread, userseek); + } + public RESULT setAdvancedSettings (ref ADVANCEDSETTINGS settings) + { + return FMOD_System_SetAdvancedSettings(systemraw, ref settings); + } + public RESULT getAdvancedSettings (ref ADVANCEDSETTINGS settings) + { + return FMOD_System_GetAdvancedSettings(systemraw, ref settings); + } + public RESULT setSpeakerMode (SPEAKERMODE speakermode) + { + return FMOD_System_SetSpeakerMode(systemraw, speakermode); + } + public RESULT getSpeakerMode (ref SPEAKERMODE speakermode) + { + return FMOD_System_GetSpeakerMode(systemraw, ref speakermode); + } + public RESULT setCallback (SYSTEM_CALLBACK callback) + { + return FMOD_System_SetCallback(systemraw, callback); + } + + // Plug-in support + public RESULT setPluginPath (string path) + { + return FMOD_System_SetPluginPath(systemraw, path); + } + public RESULT loadPlugin (string filename, ref uint handle, uint priority) + { + return FMOD_System_LoadPlugin(systemraw, filename, ref handle, priority); + } + public RESULT unloadPlugin (uint handle) + { + return FMOD_System_UnloadPlugin(systemraw, handle); + } + public RESULT getNumPlugins (PLUGINTYPE plugintype, ref int numplugins) + { + return FMOD_System_GetNumPlugins(systemraw, plugintype, ref numplugins); + } + public RESULT getPluginHandle (PLUGINTYPE plugintype, int index, ref uint handle) + { + return FMOD_System_GetPluginHandle(systemraw, plugintype, index, ref handle); + } + public RESULT getPluginInfo (uint handle, ref PLUGINTYPE plugintype, StringBuilder name, int namelen, ref uint version) + { + return FMOD_System_GetPluginInfo(systemraw, handle, ref plugintype, name, namelen, ref version); + } + + public RESULT setOutputByPlugin (uint handle) + { + return FMOD_System_SetOutputByPlugin(systemraw, handle); + } + public RESULT getOutputByPlugin (ref uint handle) + { + return FMOD_System_GetOutputByPlugin(systemraw, ref handle); + } + public RESULT createDSPByPlugin (uint handle, ref IntPtr dsp) + { + return FMOD_System_CreateDSPByPlugin(systemraw, handle, ref dsp); + } + public RESULT createCodec (IntPtr description, uint priority) + { + return FMOD_System_CreateCodec(systemraw, description, priority); + } + + + // Init/Close + public RESULT init (int maxchannels, INITFLAGS flags, IntPtr extradriverdata) + { + return FMOD_System_Init(systemraw, maxchannels, flags, extradriverdata); + } + public RESULT close () + { + return FMOD_System_Close(systemraw); + } + + + // General post-init system functions + public RESULT update () + { + return FMOD_System_Update(systemraw); + } + + public RESULT set3DSettings (float dopplerscale, float distancefactor, float rolloffscale) + { + return FMOD_System_Set3DSettings(systemraw, dopplerscale, distancefactor, rolloffscale); + } + public RESULT get3DSettings (ref float dopplerscale, ref float distancefactor, ref float rolloffscale) + { + return FMOD_System_Get3DSettings(systemraw, ref dopplerscale, ref distancefactor, ref rolloffscale); + } + public RESULT set3DNumListeners (int numlisteners) + { + return FMOD_System_Set3DNumListeners(systemraw, numlisteners); + } + public RESULT get3DNumListeners (ref int numlisteners) + { + return FMOD_System_Get3DNumListeners(systemraw, ref numlisteners); + } + public RESULT set3DListenerAttributes(int listener, ref VECTOR pos, ref VECTOR vel, ref VECTOR forward, ref VECTOR up) + { + return FMOD_System_Set3DListenerAttributes(systemraw, listener, ref pos, ref vel, ref forward, ref up); + } + public RESULT get3DListenerAttributes(int listener, ref VECTOR pos, ref VECTOR vel, ref VECTOR forward, ref VECTOR up) + { + return FMOD_System_Get3DListenerAttributes(systemraw, listener, ref pos, ref vel, ref forward, ref up); + } + + public RESULT set3DRolloffCallback (CB_3D_ROLLOFFCALLBACK callback) + { + return FMOD_System_Set3DRolloffCallback (systemraw, callback); + } + public RESULT set3DSpeakerPosition (SPEAKER speaker, float x, float y, bool active) + { + return FMOD_System_Set3DSpeakerPosition(systemraw, speaker, x, y, (active ? 1 : 0)); + } + public RESULT get3DSpeakerPosition (SPEAKER speaker, ref float x, ref float y, ref bool active) + { + RESULT result; + + int isactive = 0; + + result = FMOD_System_Get3DSpeakerPosition(systemraw, speaker, ref x, ref y, ref isactive); + + active = (isactive != 0); + + return result; + } + + public RESULT setStreamBufferSize (uint filebuffersize, TIMEUNIT filebuffersizetype) + { + return FMOD_System_SetStreamBufferSize(systemraw, filebuffersize, filebuffersizetype); + } + public RESULT getStreamBufferSize (ref uint filebuffersize, ref TIMEUNIT filebuffersizetype) + { + return FMOD_System_GetStreamBufferSize(systemraw, ref filebuffersize, ref filebuffersizetype); + } + + + // System information functions. + public RESULT getVersion (ref uint version) + { + return FMOD_System_GetVersion(systemraw, ref version); + } + public RESULT getOutputHandle (ref IntPtr handle) + { + return FMOD_System_GetOutputHandle(systemraw, ref handle); + } + public RESULT getChannelsPlaying (ref int channels) + { + return FMOD_System_GetChannelsPlaying(systemraw, ref channels); + } + public RESULT getHardwareChannels (ref int numhardwarechannels) + { + return FMOD_System_GetHardwareChannels(systemraw, ref numhardwarechannels); + } + public RESULT getCPUUsage (ref float dsp, ref float stream, ref float geometry, ref float update, ref float total) + { + return FMOD_System_GetCPUUsage(systemraw, ref dsp, ref stream, ref geometry, ref update, ref total); + } + public RESULT getSoundRAM (ref int currentalloced, ref int maxalloced, ref int total) + { + return FMOD_System_GetSoundRAM(systemraw, ref currentalloced, ref maxalloced, ref total); + } + public RESULT getNumCDROMDrives (ref int numdrives) + { + return FMOD_System_GetNumCDROMDrives(systemraw, ref numdrives); + } + public RESULT getCDROMDriveName (int drive, StringBuilder drivename, int drivenamelen, StringBuilder scsiname, int scsinamelen, StringBuilder devicename, int devicenamelen) + { + return FMOD_System_GetCDROMDriveName(systemraw, drive, drivename, drivenamelen, scsiname, scsinamelen, devicename, devicenamelen); + } + public RESULT getSpectrum (float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype) + { + return FMOD_System_GetSpectrum(systemraw, spectrumarray, numvalues, channeloffset, windowtype); + } + public RESULT getWaveData (float[] wavearray, int numvalues, int channeloffset) + { + return FMOD_System_GetWaveData(systemraw, wavearray, numvalues, channeloffset); + } + + + // Sound/DSP/Channel creation and retrieval. + public RESULT createSound (string name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + mode = mode | FMOD.MODE.UNICODE; + + try + { + result = FMOD_System_CreateSound(systemraw, name_or_data, mode, ref exinfo, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createSound (byte[] data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + try + { + result = FMOD_System_CreateSound(systemraw, data, mode, ref exinfo, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createSound (string name_or_data, MODE mode, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + mode = mode | FMOD.MODE.UNICODE; + + try + { + result = FMOD_System_CreateSound(systemraw, name_or_data, mode, 0, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createStream (string name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + mode = mode | FMOD.MODE.UNICODE; + + try + { + result = FMOD_System_CreateStream(systemraw, name_or_data, mode, ref exinfo, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createStream (byte[] data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + try + { + result = FMOD_System_CreateStream(systemraw, data, mode, ref exinfo, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createStream (string name_or_data, MODE mode, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + mode = mode | FMOD.MODE.UNICODE; + + try + { + result = FMOD_System_CreateStream(systemraw, name_or_data, mode, 0, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT createDSP (ref DSP_DESCRIPTION description, ref DSP dsp) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_System_CreateDSP(systemraw, ref description, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (dsp == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + dsp = dspnew; + } + else + { + dsp.setRaw(dspraw); + } + + return result; + } + public RESULT createDSPByType (DSP_TYPE type, ref DSP dsp) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_System_CreateDSPByType(systemraw, type, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (dsp == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + dsp = dspnew; + } + else + { + dsp.setRaw(dspraw); + } + + return result; + } + public RESULT createChannelGroup (string name, ref ChannelGroup channelgroup) + { + RESULT result = RESULT.OK; + IntPtr channelgroupraw = new IntPtr(); + ChannelGroup channelgroupnew = null; + + try + { + result = FMOD_System_CreateChannelGroup(systemraw, name, ref channelgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channelgroup == null) + { + channelgroupnew = new ChannelGroup(); + channelgroupnew.setRaw(channelgroupraw); + channelgroup = channelgroupnew; + } + else + { + channelgroup.setRaw(channelgroupraw); + } + + return result; + } + public RESULT createSoundGroup (string name, ref SoundGroup soundgroup) + { + RESULT result = RESULT.OK; + IntPtr soundgroupraw = new IntPtr(); + SoundGroup soundgroupnew = null; + + try + { + result = FMOD_System_CreateSoundGroup(systemraw, name, ref soundgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (soundgroup == null) + { + soundgroupnew = new SoundGroup(); + soundgroupnew.setRaw(soundgroupraw); + soundgroup = soundgroupnew; + } + else + { + soundgroup.setRaw(soundgroupraw); + } + + return result; + } + public RESULT createReverb (ref Reverb reverb) + { + RESULT result = RESULT.OK; + IntPtr reverbraw = new IntPtr(); + Reverb reverbnew = null; + + try + { + result = FMOD_System_CreateReverb(systemraw, ref reverbraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (reverb == null) + { + reverbnew = new Reverb(); + reverbnew.setRaw(reverbraw); + reverb = reverbnew; + } + else + { + reverb.setRaw(reverbraw); + } + + return result; + } + public RESULT playSound (CHANNELINDEX channelid, Sound sound, bool paused, ref Channel channel) + { + RESULT result = RESULT.OK; + IntPtr channelraw; + Channel channelnew = null; + + if (channel != null) + { + channelraw = channel.getRaw(); + } + else + { + channelraw = new IntPtr(); + } + + try + { + result = FMOD_System_PlaySound(systemraw, channelid, sound.getRaw(), (paused ? 1 : 0), ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channel == null) + { + channelnew = new Channel(); + channelnew.setRaw(channelraw); + channel = channelnew; + } + else + { + channel.setRaw(channelraw); + } + + return result; + } + public RESULT playDSP (CHANNELINDEX channelid, DSP dsp, bool paused, ref Channel channel) + { + RESULT result = RESULT.OK; + IntPtr channelraw; + Channel channelnew = null; + + if (channel != null) + { + channelraw = channel.getRaw(); + } + else + { + channelraw = new IntPtr(); + } + + try + { + result = FMOD_System_PlayDSP(systemraw, channelid, dsp.getRaw(), (paused ? 1 : 0), ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channel == null) + { + channelnew = new Channel(); + channelnew.setRaw(channelraw); + channel = channelnew; + } + else + { + channel.setRaw(channelraw); + } + + return result; + } + public RESULT getChannel (int channelid, ref Channel channel) + { + RESULT result = RESULT.OK; + IntPtr channelraw = new IntPtr(); + Channel channelnew = null; + + try + { + result = FMOD_System_GetChannel(systemraw, channelid, ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channel == null) + { + channelnew = new Channel(); + channelnew.setRaw(channelraw); + channel = channelnew; + } + else + { + channel.setRaw(channelraw); + } + + return result; + } + + public RESULT getMasterChannelGroup (ref ChannelGroup channelgroup) + { + RESULT result = RESULT.OK; + IntPtr channelgroupraw = new IntPtr(); + ChannelGroup channelgroupnew = null; + + try + { + result = FMOD_System_GetMasterChannelGroup(systemraw, ref channelgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channelgroup == null) + { + channelgroupnew = new ChannelGroup(); + channelgroupnew.setRaw(channelgroupraw); + channelgroup = channelgroupnew; + } + else + { + channelgroup.setRaw(channelgroupraw); + } + + return result; + } + + public RESULT getMasterSoundGroup (ref SoundGroup soundgroup) + { + RESULT result = RESULT.OK; + IntPtr soundgroupraw = new IntPtr(); + SoundGroup soundgroupnew = null; + + try + { + result = FMOD_System_GetMasterSoundGroup(systemraw, ref soundgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (soundgroup == null) + { + soundgroupnew = new SoundGroup(); + soundgroupnew.setRaw(soundgroupraw); + soundgroup = soundgroupnew; + } + else + { + soundgroup.setRaw(soundgroupraw); + } + + return result; + } + + // Reverb api + public RESULT setReverbProperties (ref REVERB_PROPERTIES prop) + { + return FMOD_System_SetReverbProperties(systemraw, ref prop); + } + public RESULT getReverbProperties (ref REVERB_PROPERTIES prop) + { + return FMOD_System_GetReverbProperties(systemraw, ref prop); + } + + public RESULT setReverbAmbientProperties (ref REVERB_PROPERTIES prop) + { + return FMOD_System_SetReverbAmbientProperties(systemraw, ref prop); + } + public RESULT getReverbAmbientProperties (ref REVERB_PROPERTIES prop) + { + return FMOD_System_GetReverbAmbientProperties(systemraw, ref prop); + } + + // System level DSP access. + public RESULT getDSPHead (ref DSP dsp) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_System_GetDSPHead(systemraw, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (dsp == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + dsp = dspnew; + } + else + { + dsp.setRaw(dspraw); + } + + return result; + } + public RESULT addDSP (DSP dsp, ref DSPConnection connection) + { + RESULT result = RESULT.OK; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_System_AddDSP(systemraw, dsp.getRaw(), ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (connection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + connection = dspconnectionnew; + } + else + { + connection.setRaw(dspconnectionraw); + } + + return result; + } + public RESULT lockDSP () + { + return FMOD_System_LockDSP(systemraw); + } + public RESULT unlockDSP () + { + return FMOD_System_UnlockDSP(systemraw); + } + public RESULT getDSPClock (ref uint hi, ref uint lo) + { + return FMOD_System_GetDSPClock (systemraw, ref hi, ref lo); + } + + + // Recording api + public RESULT getRecordNumDrivers (ref int numdrivers) + { + return FMOD_System_GetRecordNumDrivers(systemraw, ref numdrivers); + } + public RESULT getRecordDriverInfo (int id, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder name, int namelen, ref GUID guid) + { + //use multibyte version + return FMOD_System_GetRecordDriverInfoW(systemraw, id, name, namelen, ref guid); + } + public RESULT getRecordDriverCaps (int id, ref CAPS caps, ref int minfrequency, ref int maxfrequency) + { + return FMOD_System_GetRecordDriverCaps(systemraw, id, ref caps, ref minfrequency, ref maxfrequency); + } + public RESULT getRecordPosition (int id, ref uint position) + { + return FMOD_System_GetRecordPosition(systemraw, id, ref position); + } + + public RESULT recordStart (int id, Sound sound, bool loop) + { + return FMOD_System_RecordStart(systemraw, id, sound.getRaw(), (loop ? 1 : 0)); + } + public RESULT recordStop (int id) + { + return FMOD_System_RecordStop(systemraw, id); + } + public RESULT isRecording (int id, ref bool recording) + { + RESULT result; + int r = 0; + + result = FMOD_System_IsRecording(systemraw, id, ref r); + + recording = (r != 0); + + return result; + } + + + // Geometry api + public RESULT createGeometry (int maxpolygons, int maxvertices, ref Geometry geometry) + { + RESULT result = RESULT.OK; + IntPtr geometryraw = new IntPtr(); + Geometry geometrynew = null; + + try + { + result = FMOD_System_CreateGeometry(systemraw, maxpolygons, maxvertices, ref geometryraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (geometry == null) + { + geometrynew = new Geometry(); + geometrynew.setRaw(geometryraw); + geometry = geometrynew; + } + else + { + geometry.setRaw(geometryraw); + } + + return result; + } + public RESULT setGeometrySettings (float maxworldsize) + { + return FMOD_System_SetGeometrySettings(systemraw, maxworldsize); + } + public RESULT getGeometrySettings (ref float maxworldsize) + { + return FMOD_System_GetGeometrySettings(systemraw, ref maxworldsize); + } + public RESULT loadGeometry(IntPtr data, int datasize, ref Geometry geometry) + { + RESULT result = RESULT.OK; + IntPtr geometryraw = new IntPtr(); + Geometry geometrynew = null; + + try + { + result = FMOD_System_LoadGeometry(systemraw, data, datasize, ref geometryraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (geometry == null) + { + geometrynew = new Geometry(); + geometrynew.setRaw(geometryraw); + geometry = geometrynew; + } + else + { + geometry.setRaw(geometryraw); + } + + return result; + } + public RESULT getGeometryOcclusion (ref VECTOR listener, ref VECTOR source, ref float direct, ref float reverb) + { + return FMOD_System_GetGeometryOcclusion(systemraw, ref listener, ref source, ref direct, ref reverb); + } + + // Network functions + public RESULT setNetworkProxy (string proxy) + { + return FMOD_System_SetNetworkProxy(systemraw, proxy); + } + public RESULT getNetworkProxy (StringBuilder proxy, int proxylen) + { + return FMOD_System_GetNetworkProxy(systemraw, proxy, proxylen); + } + public RESULT setNetworkTimeout (int timeout) + { + return FMOD_System_SetNetworkTimeout(systemraw, timeout); + } + public RESULT getNetworkTimeout(ref int timeout) + { + return FMOD_System_GetNetworkTimeout(systemraw, ref timeout); + } + + // Userdata set/get + public RESULT setUserData (IntPtr userdata) + { + return FMOD_System_SetUserData(systemraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_System_GetUserData(systemraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_System_GetMemoryInfo(systemraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Release (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetOutput (IntPtr system, OUTPUTTYPE output); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetOutput (IntPtr system, ref OUTPUTTYPE output); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetNumDrivers (IntPtr system, ref int numdrivers); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDriverInfo (IntPtr system, int id, StringBuilder name, int namelen, ref GUID guid); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDriverInfoW (IntPtr system, int id, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder name, int namelen, ref GUID guid); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDriverCaps (IntPtr system, int id, ref CAPS caps, ref int controlpaneloutputrate, ref SPEAKERMODE controlpanelspeakermode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetDriver (IntPtr system, int driver); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDriver (IntPtr system, ref int driver); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetHardwareChannels (IntPtr system, int numhardwarechannels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetHardwareChannels (IntPtr system, ref int numhardwarechannels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetSoftwareChannels (IntPtr system, int numsoftwarechannels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetSoftwareChannels (IntPtr system, ref int numsoftwarechannels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetSoftwareFormat (IntPtr system, int samplerate, SOUND_FORMAT format, int numoutputchannels, int maxinputchannels, DSP_RESAMPLER resamplemethod); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetSoftwareFormat (IntPtr system, ref int samplerate, ref SOUND_FORMAT format, ref int numoutputchannels, ref int maxinputchannels, ref DSP_RESAMPLER resamplemethod, ref int bits); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetDSPBufferSize (IntPtr system, uint bufferlength, int numbuffers); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDSPBufferSize (IntPtr system, ref uint bufferlength, ref int numbuffers); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetFileSystem(IntPtr system, FILE_OPENCALLBACK useropen, FILE_CLOSECALLBACK userclose, FILE_READCALLBACK userread, FILE_SEEKCALLBACK userseek, FILE_ASYNCREADCALLBACK userasyncread, FILE_ASYNCCANCELCALLBACK userasynccancel, int blockalign); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_AttachFileSystem (IntPtr system, FILE_OPENCALLBACK useropen, FILE_CLOSECALLBACK userclose, FILE_READCALLBACK userread, FILE_SEEKCALLBACK userseek); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetPluginPath (IntPtr system, string path); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_LoadPlugin (IntPtr system, string filename, ref uint handle, uint priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_UnloadPlugin (IntPtr system, uint handle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetNumPlugins (IntPtr system, PLUGINTYPE plugintype, ref int numplugins); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetPluginHandle (IntPtr system, PLUGINTYPE plugintype, int index, ref uint handle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetPluginInfo (IntPtr system, uint handle, ref PLUGINTYPE plugintype, StringBuilder name, int namelen, ref uint version); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateDSPByPlugin (IntPtr system, uint handle, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateCodec (IntPtr system, IntPtr description, uint priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetOutputByPlugin (IntPtr system, uint handle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetOutputByPlugin (IntPtr system, ref uint handle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Init (IntPtr system, int maxchannels, INITFLAGS flags, IntPtr extradriverdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Close (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Update (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_UpdateFinished (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetAdvancedSettings (IntPtr system, ref ADVANCEDSETTINGS settings); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetAdvancedSettings (IntPtr system, ref ADVANCEDSETTINGS settings); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetSpeakerMode (IntPtr system, SPEAKERMODE speakermode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetSpeakerMode (IntPtr system, ref SPEAKERMODE speakermode); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_System_Set3DRolloffCallback(IntPtr system, CB_3D_ROLLOFFCALLBACK callback); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_System_SetCallback (IntPtr system, SYSTEM_CALLBACK callback); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_System_Set3DSpeakerPosition (IntPtr system, SPEAKER speaker, float x, float y, int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Get3DSpeakerPosition (IntPtr system, SPEAKER speaker, ref float x, ref float y, ref int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Set3DSettings (IntPtr system, float dopplerscale, float distancefactor, float rolloffscale); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Get3DSettings (IntPtr system, ref float dopplerscale, ref float distancefactor, ref float rolloffscale); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Set3DNumListeners (IntPtr system, int numlisteners); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Get3DNumListeners (IntPtr system, ref int numlisteners); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Set3DListenerAttributes(IntPtr system, int listener, ref VECTOR pos, ref VECTOR vel, ref VECTOR forward, ref VECTOR up); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_Get3DListenerAttributes(IntPtr system, int listener, ref VECTOR pos, ref VECTOR vel, ref VECTOR forward, ref VECTOR up); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetFileBufferSize (IntPtr system, int sizebytes); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetFileBufferSize (IntPtr system, ref int sizebytes); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetStreamBufferSize (IntPtr system, uint filebuffersize, TIMEUNIT filebuffersizetype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetStreamBufferSize (IntPtr system, ref uint filebuffersize, ref TIMEUNIT filebuffersizetype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetVersion (IntPtr system, ref uint version); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetOutputHandle (IntPtr system, ref IntPtr handle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetChannelsPlaying (IntPtr system, ref int channels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetCPUUsage (IntPtr system, ref float dsp, ref float stream, ref float geometry, ref float update, ref float total); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetSoundRAM (IntPtr system, ref int currentalloced, ref int maxalloced, ref int total); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetNumCDROMDrives (IntPtr system, ref int numdrives); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetCDROMDriveName (IntPtr system, int drive, StringBuilder drivename, int drivenamelen, StringBuilder scsiname, int scsinamelen, StringBuilder devicename, int devicenamelen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetSpectrum (IntPtr system, [MarshalAs(UnmanagedType.LPArray)]float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetWaveData (IntPtr system, [MarshalAs(UnmanagedType.LPArray)]float[] wavearray, int numvalues, int channeloffset); + [DllImport (VERSION.dll, CharSet = CharSet.Unicode)] + private static extern RESULT FMOD_System_CreateSound (IntPtr system, string name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound); + [DllImport (VERSION.dll, CharSet = CharSet.Unicode)] + private static extern RESULT FMOD_System_CreateStream (IntPtr system, string name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound); + [DllImport(VERSION.dll, CharSet = CharSet.Unicode)] + private static extern RESULT FMOD_System_CreateSound (IntPtr system, string name_or_data, MODE mode, int exinfo, ref IntPtr sound); + [DllImport(VERSION.dll, CharSet = CharSet.Unicode)] + private static extern RESULT FMOD_System_CreateStream (IntPtr system, string name_or_data, MODE mode, int exinfo, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateSound (IntPtr system, byte[] name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateStream (IntPtr system, byte[] name_or_data, MODE mode, ref CREATESOUNDEXINFO exinfo, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateSound (IntPtr system, byte[] name_or_data, MODE mode, int exinfo, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateStream (IntPtr system, byte[] name_or_data, MODE mode, int exinfo, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateDSP (IntPtr system, ref DSP_DESCRIPTION description, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateDSPByType (IntPtr system, DSP_TYPE type, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateChannelGroup (IntPtr system, string name, ref IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateSoundGroup (IntPtr system, string name, ref IntPtr soundgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateReverb (IntPtr system, ref IntPtr reverb); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_PlaySound (IntPtr system, CHANNELINDEX channelid, IntPtr sound, int paused, ref IntPtr channel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_PlayDSP (IntPtr system, CHANNELINDEX channelid, IntPtr dsp, int paused, ref IntPtr channel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetChannel (IntPtr system, int channelid, ref IntPtr channel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetMasterChannelGroup (IntPtr system, ref IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetMasterSoundGroup (IntPtr system, ref IntPtr soundgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetReverbProperties (IntPtr system, ref REVERB_PROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetReverbProperties (IntPtr system, ref REVERB_PROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetReverbAmbientProperties(IntPtr system, ref REVERB_PROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetReverbAmbientProperties(IntPtr system, ref REVERB_PROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDSPHead (IntPtr system, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_AddDSP (IntPtr system, IntPtr dsp, ref IntPtr connection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_LockDSP (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_UnlockDSP (IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetDSPClock (IntPtr system, ref uint hi, ref uint lo); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_System_GetRecordNumDrivers (IntPtr system, ref int numdrivers); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetRecordDriverInfo (IntPtr system, int id, StringBuilder name, int namelen, ref GUID guid); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetRecordDriverInfoW (IntPtr system, int id, [MarshalAs(UnmanagedType.LPWStr)]StringBuilder name, int namelen, ref GUID guid); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetRecordDriverCaps (IntPtr system, int id, ref CAPS caps, ref int minfrequency, ref int maxfrequency); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetRecordPosition (IntPtr system, int id, ref uint position); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_RecordStart (IntPtr system, int id, IntPtr sound, int loop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_RecordStop (IntPtr system, int id); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_IsRecording (IntPtr system, int id, ref int recording); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_CreateGeometry (IntPtr system, int maxpolygons, int maxvertices, ref IntPtr geometry); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetGeometrySettings (IntPtr system, float maxworldsize); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetGeometrySettings (IntPtr system, ref float maxworldsize); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_LoadGeometry (IntPtr system, IntPtr data, int datasize, ref IntPtr geometry); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetGeometryOcclusion (IntPtr system, ref VECTOR listener, ref VECTOR source, ref float direct, ref float reverb); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetNetworkProxy (IntPtr system, string proxy); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetNetworkProxy (IntPtr system, StringBuilder proxy, int proxylen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetNetworkTimeout (IntPtr system, int timeout); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetNetworkTimeout (IntPtr system, ref int timeout); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_SetUserData (IntPtr system, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetUserData (IntPtr system, ref IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_System_GetMemoryInfo (IntPtr system, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + + #endregion + + #region wrapperinternal + + private IntPtr systemraw; + + public void setRaw(IntPtr system) + { + systemraw = new IntPtr(); + + systemraw = system; + } + + public IntPtr getRaw() + { + return systemraw; + } + + #endregion + } + + + /* + 'Sound' API + */ + public class Sound + { + public RESULT release () + { + return FMOD_Sound_Release(soundraw); + } + public RESULT getSystemObject (ref System system) + { + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + try + { + result = FMOD_Sound_GetSystemObject(soundraw, ref systemraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (system == null) + { + systemnew = new System(); + systemnew.setRaw(systemraw); + system = systemnew; + } + else + { + system.setRaw(systemraw); + } + return result; + } + + + public RESULT @lock (uint offset, uint length, ref IntPtr ptr1, ref IntPtr ptr2, ref uint len1, ref uint len2) + { + return FMOD_Sound_Lock(soundraw, offset, length, ref ptr1, ref ptr2, ref len1, ref len2); + } + public RESULT unlock (IntPtr ptr1, IntPtr ptr2, uint len1, uint len2) + { + return FMOD_Sound_Unlock(soundraw, ptr1, ptr2, len1, len2); + } + public RESULT setDefaults (float frequency, float volume, float pan, int priority) + { + return FMOD_Sound_SetDefaults(soundraw, frequency, volume, pan, priority); + } + public RESULT getDefaults (ref float frequency, ref float volume, ref float pan, ref int priority) + { + return FMOD_Sound_GetDefaults(soundraw, ref frequency, ref volume, ref pan, ref priority); + } + public RESULT setVariations (float frequencyvar, float volumevar, float panvar) + { + return FMOD_Sound_SetVariations(soundraw, frequencyvar, volumevar, panvar); + } + public RESULT getVariations (ref float frequencyvar, ref float volumevar, ref float panvar) + { + return FMOD_Sound_GetVariations(soundraw, ref frequencyvar, ref volumevar, ref panvar); + } + public RESULT set3DMinMaxDistance (float min, float max) + { + return FMOD_Sound_Set3DMinMaxDistance(soundraw, min, max); + } + public RESULT get3DMinMaxDistance (ref float min, ref float max) + { + return FMOD_Sound_Get3DMinMaxDistance(soundraw, ref min, ref max); + } + public RESULT set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume) + { + return FMOD_Sound_Set3DConeSettings(soundraw, insideconeangle, outsideconeangle, outsidevolume); + } + public RESULT get3DConeSettings (ref float insideconeangle, ref float outsideconeangle, ref float outsidevolume) + { + return FMOD_Sound_Get3DConeSettings(soundraw, ref insideconeangle, ref outsideconeangle, ref outsidevolume); + } + public RESULT set3DCustomRolloff (ref VECTOR points, int numpoints) + { + return FMOD_Sound_Set3DCustomRolloff(soundraw, ref points, numpoints); + } + public RESULT get3DCustomRolloff (ref IntPtr points, ref int numpoints) + { + return FMOD_Sound_Get3DCustomRolloff(soundraw, ref points, ref numpoints); + } + public RESULT setSubSound (int index, Sound subsound) + { + IntPtr subsoundraw = subsound.getRaw(); + + return FMOD_Sound_SetSubSound(soundraw, index, subsoundraw); + } + public RESULT getSubSound (int index, ref Sound subsound) + { + RESULT result = RESULT.OK; + IntPtr subsoundraw = new IntPtr(); + Sound subsoundnew = null; + + try + { + result = FMOD_Sound_GetSubSound(soundraw, index, ref subsoundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (subsound == null) + { + subsoundnew = new Sound(); + subsoundnew.setRaw(subsoundraw); + subsound = subsoundnew; + } + else + { + subsound.setRaw(subsoundraw); + } + + return result; + } + public RESULT setSubSoundSentence (int[] subsoundlist, int numsubsounds) + { + return FMOD_Sound_SetSubSoundSentence(soundraw, subsoundlist, numsubsounds); + } + public RESULT getName (StringBuilder name, int namelen) + { + return FMOD_Sound_GetName(soundraw, name, namelen); + } + public RESULT getLength (ref uint length, TIMEUNIT lengthtype) + { + return FMOD_Sound_GetLength(soundraw, ref length, lengthtype); + } + public RESULT getFormat (ref SOUND_TYPE type, ref SOUND_FORMAT format, ref int channels, ref int bits) + { + return FMOD_Sound_GetFormat(soundraw, ref type, ref format, ref channels, ref bits); + } + public RESULT getNumSubSounds (ref int numsubsounds) + { + return FMOD_Sound_GetNumSubSounds(soundraw, ref numsubsounds); + } + public RESULT getNumTags (ref int numtags, ref int numtagsupdated) + { + return FMOD_Sound_GetNumTags(soundraw, ref numtags, ref numtagsupdated); + } + public RESULT getTag (string name, int index, ref TAG tag) + { + return FMOD_Sound_GetTag(soundraw, name, index, ref tag); + } + public RESULT getOpenState (ref OPENSTATE openstate, ref uint percentbuffered, ref bool starving, ref bool diskbusy) + { + RESULT result; + int s = 0; + int b = 0; + + result = FMOD_Sound_GetOpenState(soundraw, ref openstate, ref percentbuffered, ref s, ref b); + + starving = (s != 0); + diskbusy = (b != 0); + + return result; + } + public RESULT readData (IntPtr buffer, uint lenbytes, ref uint read) + { + return FMOD_Sound_ReadData(soundraw, buffer, lenbytes, ref read); + } + public RESULT seekData (uint pcm) + { + return FMOD_Sound_SeekData(soundraw, pcm); + } + + + public RESULT setSoundGroup (SoundGroup soundgroup) + { + return FMOD_Sound_SetSoundGroup(soundraw, soundgroup.getRaw()); + } + public RESULT getSoundGroup (ref SoundGroup soundgroup) + { + RESULT result = RESULT.OK; + IntPtr soundgroupraw = new IntPtr(); + SoundGroup soundgroupnew = null; + + try + { + result = FMOD_Sound_GetSoundGroup(soundraw, ref soundgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (soundgroup == null) + { + soundgroupnew = new SoundGroup(); + soundgroupnew.setRaw(soundgroupraw); + soundgroup = soundgroupnew; + } + else + { + soundgroup.setRaw(soundgroupraw); + } + + return result; + } + + + public RESULT getNumSyncPoints (ref int numsyncpoints) + { + return FMOD_Sound_GetNumSyncPoints(soundraw, ref numsyncpoints); + } + public RESULT getSyncPoint (int index, ref IntPtr point) + { + return FMOD_Sound_GetSyncPoint(soundraw, index, ref point); + } + public RESULT getSyncPointInfo (IntPtr point, StringBuilder name, int namelen, ref uint offset, TIMEUNIT offsettype) + { + return FMOD_Sound_GetSyncPointInfo(soundraw, point, name, namelen, ref offset, offsettype); + } + public RESULT addSyncPoint (uint offset, TIMEUNIT offsettype, string name, ref IntPtr point) + { + return FMOD_Sound_AddSyncPoint(soundraw, offset, offsettype, name, ref point); + } + public RESULT deleteSyncPoint (IntPtr point) + { + return FMOD_Sound_DeleteSyncPoint(soundraw, point); + } + + + public RESULT setMode (MODE mode) + { + return FMOD_Sound_SetMode(soundraw, mode); + } + public RESULT getMode (ref MODE mode) + { + return FMOD_Sound_GetMode(soundraw, ref mode); + } + public RESULT setLoopCount (int loopcount) + { + return FMOD_Sound_SetLoopCount(soundraw, loopcount); + } + public RESULT getLoopCount (ref int loopcount) + { + return FMOD_Sound_GetLoopCount(soundraw, ref loopcount); + } + public RESULT setLoopPoints (uint loopstart, TIMEUNIT loopstarttype, uint loopend, TIMEUNIT loopendtype) + { + return FMOD_Sound_SetLoopPoints(soundraw, loopstart, loopstarttype, loopend, loopendtype); + } + public RESULT getLoopPoints (ref uint loopstart, TIMEUNIT loopstarttype, ref uint loopend, TIMEUNIT loopendtype) + { + return FMOD_Sound_GetLoopPoints(soundraw, ref loopstart, loopstarttype, ref loopend, loopendtype); + } + + public RESULT getMusicNumChannels (ref int numchannels) + { + return FMOD_Sound_GetMusicNumChannels(soundraw, ref numchannels); + } + public RESULT setMusicChannelVolume (int channel, float volume) + { + return FMOD_Sound_SetMusicChannelVolume(soundraw, channel, volume); + } + public RESULT getMusicChannelVolume (int channel, ref float volume) + { + return FMOD_Sound_GetMusicChannelVolume(soundraw, channel, ref volume); + } + public RESULT setMusicSpeed(float speed) + { + return FMOD_Sound_SetMusicSpeed(soundraw, speed); + } + public RESULT getMusicSpeed(ref float speed) + { + return FMOD_Sound_GetMusicSpeed(soundraw, ref speed); + } + + public RESULT setUserData (IntPtr userdata) + { + return FMOD_Sound_SetUserData(soundraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_Sound_GetUserData(soundraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_Sound_GetMemoryInfo(soundraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_Release (IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetSystemObject (IntPtr sound, ref IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_Lock (IntPtr sound, uint offset, uint length, ref IntPtr ptr1, ref IntPtr ptr2, ref uint len1, ref uint len2); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_Unlock (IntPtr sound, IntPtr ptr1, IntPtr ptr2, uint len1, uint len2); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetDefaults (IntPtr sound, float frequency, float volume, float pan, int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetDefaults (IntPtr sound, ref float frequency, ref float volume, ref float pan, ref int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetVariations (IntPtr sound, float frequencyvar, float volumevar, float panvar); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetVariations (IntPtr sound, ref float frequencyvar, ref float volumevar, ref float panvar); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_Set3DMinMaxDistance (IntPtr sound, float min, float max); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_Get3DMinMaxDistance (IntPtr sound, ref float min, ref float max); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_Set3DConeSettings (IntPtr sound, float insideconeangle, float outsideconeangle, float outsidevolume); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_Get3DConeSettings (IntPtr sound, ref float insideconeangle, ref float outsideconeangle, ref float outsidevolume); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_Set3DCustomRolloff (IntPtr sound, ref VECTOR points, int numpoints); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_Get3DCustomRolloff (IntPtr sound, ref IntPtr points, ref int numpoints); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_SetSubSound (IntPtr sound, int index, IntPtr subsound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetSubSound (IntPtr sound, int index, ref IntPtr subsound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetSubSoundSentence (IntPtr sound, int[] subsoundlist, int numsubsounds); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetName (IntPtr sound, StringBuilder name, int namelen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetLength (IntPtr sound, ref uint length, TIMEUNIT lengthtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetFormat (IntPtr sound, ref SOUND_TYPE type, ref SOUND_FORMAT format, ref int channels, ref int bits); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetNumSubSounds (IntPtr sound, ref int numsubsounds); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetNumTags (IntPtr sound, ref int numtags, ref int numtagsupdated); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetTag (IntPtr sound, string name, int index, ref TAG tag); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetOpenState (IntPtr sound, ref OPENSTATE openstate, ref uint percentbuffered, ref int starving, ref int diskbusy); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_ReadData (IntPtr sound, IntPtr buffer, uint lenbytes, ref uint read); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SeekData (IntPtr sound, uint pcm); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetSoundGroup (IntPtr sound, IntPtr soundgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetSoundGroup (IntPtr sound, ref IntPtr soundgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetNumSyncPoints (IntPtr sound, ref int numsyncpoints); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetSyncPoint (IntPtr sound, int index, ref IntPtr point); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetSyncPointInfo (IntPtr sound, IntPtr point, StringBuilder name, int namelen, ref uint offset, TIMEUNIT offsettype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_AddSyncPoint (IntPtr sound, uint offset, TIMEUNIT offsettype, string name, ref IntPtr point); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_DeleteSyncPoint (IntPtr sound, IntPtr point); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetMode (IntPtr sound, MODE mode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetMode (IntPtr sound, ref MODE mode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetLoopCount (IntPtr sound, int loopcount); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetLoopCount (IntPtr sound, ref int loopcount); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_SetLoopPoints (IntPtr sound, uint loopstart, TIMEUNIT loopstarttype, uint loopend, TIMEUNIT loopendtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetLoopPoints (IntPtr sound, ref uint loopstart, TIMEUNIT loopstarttype, ref uint loopend, TIMEUNIT loopendtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetMusicNumChannels (IntPtr sound, ref int numchannels); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_SetMusicChannelVolume (IntPtr sound, int channel, float volume); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_GetMusicChannelVolume (IntPtr sound, int channel, ref float volume); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_SetMusicSpeed (IntPtr sound, float speed); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_GetMusicSpeed (IntPtr sound, ref float speed); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_SetUserData (IntPtr sound, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Sound_GetUserData (IntPtr sound, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Sound_GetMemoryInfo (IntPtr sound, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr soundraw; + + public void setRaw(IntPtr sound) + { + soundraw = new IntPtr(); + soundraw = sound; + } + + public IntPtr getRaw() + { + return soundraw; + } + + #endregion + } + + + /* + 'Channel' API + */ + public class Channel + { + public RESULT getSystemObject (ref System system) + { + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + try + { + result = FMOD_Channel_GetSystemObject(channelraw, ref systemraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (system == null) + { + systemnew = new System(); + systemnew.setRaw(systemraw); + system = systemnew; + } + else + { + system.setRaw(systemraw); + } + + return result; + } + + + public RESULT stop () + { + return FMOD_Channel_Stop(channelraw); + } + public RESULT setPaused (bool paused) + { + return FMOD_Channel_SetPaused(channelraw, (paused ? 1 : 0)); + } + public RESULT getPaused (ref bool paused) + { + RESULT result; + int p = 0; + + result = FMOD_Channel_GetPaused(channelraw, ref p); + + paused = (p != 0); + + return result; + } + public RESULT setVolume (float volume) + { + return FMOD_Channel_SetVolume(channelraw, volume); + } + public RESULT getVolume (ref float volume) + { + return FMOD_Channel_GetVolume(channelraw, ref volume); + } + public RESULT setFrequency (float frequency) + { + return FMOD_Channel_SetFrequency(channelraw, frequency); + } + public RESULT getFrequency (ref float frequency) + { + return FMOD_Channel_GetFrequency(channelraw, ref frequency); + } + public RESULT setPan (float pan) + { + return FMOD_Channel_SetPan(channelraw, pan); + } + public RESULT getPan (ref float pan) + { + return FMOD_Channel_GetPan(channelraw, ref pan); + } + public RESULT setDelay (DELAYTYPE delaytype, uint delayhi, uint delaylo) + { + return FMOD_Channel_SetDelay(channelraw, delaytype, delayhi, delaylo); + } + public RESULT getDelay (DELAYTYPE delaytype, ref uint delayhi, ref uint delaylo) + { + return FMOD_Channel_GetDelay(channelraw, delaytype, ref delayhi, ref delaylo); + } + public RESULT setSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright) + { + return FMOD_Channel_SetSpeakerMix(channelraw, frontleft, frontright, center, lfe, backleft, backright, sideleft, sideright); + } + public RESULT getSpeakerMix (ref float frontleft, ref float frontright, ref float center, ref float lfe, ref float backleft, ref float backright, ref float sideleft, ref float sideright) + { + return FMOD_Channel_GetSpeakerMix(channelraw, ref frontleft, ref frontright, ref center, ref lfe, ref backleft, ref backright, ref sideleft, ref sideright); + } + public RESULT setSpeakerLevels (SPEAKER speaker, float[] levels, int numlevels) + { + return FMOD_Channel_SetSpeakerLevels(channelraw, speaker, levels, numlevels); + } + public RESULT getSpeakerLevels (SPEAKER speaker, float[] levels, int numlevels) + { + return FMOD_Channel_GetSpeakerLevels(channelraw, speaker, levels, numlevels); + } + public RESULT setInputChannelMix (float[] levels, int numlevels) + { + return FMOD_Channel_SetInputChannelMix(channelraw, levels, numlevels); + } + public RESULT getInputChannelMix (float[] levels, int numlevels) + { + return FMOD_Channel_GetInputChannelMix(channelraw, levels, numlevels); + } + public RESULT setMute (bool mute) + { + return FMOD_Channel_SetMute(channelraw, (mute ? 1 : 0)); + } + public RESULT getMute (ref bool mute) + { + RESULT result; + int m = 0; + + result = FMOD_Channel_GetMute(channelraw, ref m); + + mute = (m != 0); + + return result; + } + public RESULT setPriority (int priority) + { + return FMOD_Channel_SetPriority(channelraw, priority); + } + public RESULT getPriority (ref int priority) + { + return FMOD_Channel_GetPriority(channelraw, ref priority); + } + public RESULT setPosition (uint position, TIMEUNIT postype) + { + return FMOD_Channel_SetPosition(channelraw, position, postype); + } + public RESULT getPosition (ref uint position, TIMEUNIT postype) + { + return FMOD_Channel_GetPosition(channelraw, ref position, postype); + } + + public RESULT setLowPassGain (float gain) + { + return FMOD_Channel_SetLowPassGain(channelraw, gain); + } + public RESULT getLowPassGain (ref float gain) + { + return FMOD_Channel_GetLowPassGain(channelraw, ref gain); + } + + public RESULT setReverbProperties (ref REVERB_CHANNELPROPERTIES prop) + { + return FMOD_Channel_SetReverbProperties(channelraw, ref prop); + } + public RESULT getReverbProperties (ref REVERB_CHANNELPROPERTIES prop) + { + return FMOD_Channel_GetReverbProperties(channelraw, ref prop); + } + public RESULT setChannelGroup (ChannelGroup channelgroup) + { + return FMOD_Channel_SetChannelGroup(channelraw, channelgroup.getRaw()); + } + public RESULT getChannelGroup (ref ChannelGroup channelgroup) + { + RESULT result = RESULT.OK; + IntPtr channelgroupraw = new IntPtr(); + ChannelGroup channelgroupnew = null; + + try + { + result = FMOD_Channel_GetChannelGroup(channelraw, ref channelgroupraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channelgroup == null) + { + channelgroupnew = new ChannelGroup(); + channelgroupnew.setRaw(channelgroupraw); + channelgroup = channelgroupnew; + } + else + { + channelgroup.setRaw(channelgroupraw); + } + + return result; + } + + public RESULT setCallback (CHANNEL_CALLBACK callback) + { + return FMOD_Channel_SetCallback(channelraw, callback); + } + + + public RESULT set3DAttributes (ref VECTOR pos, ref VECTOR vel) + { + return FMOD_Channel_Set3DAttributes(channelraw, ref pos, ref vel); + } + public RESULT get3DAttributes (ref VECTOR pos, ref VECTOR vel) + { + return FMOD_Channel_Get3DAttributes(channelraw, ref pos, ref vel); + } + public RESULT set3DMinMaxDistance (float mindistance, float maxdistance) + { + return FMOD_Channel_Set3DMinMaxDistance(channelraw, mindistance, maxdistance); + } + public RESULT get3DMinMaxDistance (ref float mindistance, ref float maxdistance) + { + return FMOD_Channel_Get3DMinMaxDistance(channelraw, ref mindistance, ref maxdistance); + } + public RESULT set3DConeSettings (float insideconeangle, float outsideconeangle, float outsidevolume) + { + return FMOD_Channel_Set3DConeSettings(channelraw, insideconeangle, outsideconeangle, outsidevolume); + } + public RESULT get3DConeSettings (ref float insideconeangle, ref float outsideconeangle, ref float outsidevolume) + { + return FMOD_Channel_Get3DConeSettings(channelraw, ref insideconeangle, ref outsideconeangle, ref outsidevolume); + } + public RESULT set3DConeOrientation (ref VECTOR orientation) + { + return FMOD_Channel_Set3DConeOrientation(channelraw, ref orientation); + } + public RESULT get3DConeOrientation (ref VECTOR orientation) + { + return FMOD_Channel_Get3DConeOrientation(channelraw, ref orientation); + } + public RESULT set3DCustomRolloff (ref VECTOR points, int numpoints) + { + return FMOD_Channel_Set3DCustomRolloff(channelraw, ref points, numpoints); + } + public RESULT get3DCustomRolloff (ref IntPtr points, ref int numpoints) + { + return FMOD_Channel_Get3DCustomRolloff(channelraw, ref points, ref numpoints); + } + public RESULT set3DOcclusion (float directocclusion, float reverbocclusion) + { + return FMOD_Channel_Set3DOcclusion(channelraw, directocclusion, reverbocclusion); + } + public RESULT get3DOcclusion (ref float directocclusion, ref float reverbocclusion) + { + return FMOD_Channel_Get3DOcclusion(channelraw, ref directocclusion, ref reverbocclusion); + } + public RESULT set3DSpread (float angle) + { + return FMOD_Channel_Set3DSpread(channelraw, angle); + } + public RESULT get3DSpread (ref float angle) + { + return FMOD_Channel_Get3DSpread(channelraw, ref angle); + } + public RESULT set3DPanLevel (float level) + { + return FMOD_Channel_Set3DPanLevel(channelraw, level); + } + public RESULT get3DPanLevel (ref float level) + { + return FMOD_Channel_Get3DPanLevel(channelraw, ref level); + } + public RESULT set3DDopplerLevel (float level) + { + return FMOD_Channel_Set3DDopplerLevel(channelraw, level); + } + public RESULT get3DDopplerLevel (ref float level) + { + return FMOD_Channel_Get3DDopplerLevel(channelraw, ref level); + } + + public RESULT isPlaying (ref bool isplaying) + { + RESULT result; + int p = 0; + + result = FMOD_Channel_IsPlaying(channelraw, ref p); + + isplaying = (p != 0); + + return result; + } + public RESULT isVirtual (ref bool isvirtual) + { + RESULT result; + int v = 0; + + result = FMOD_Channel_IsVirtual(channelraw, ref v); + + isvirtual = (v != 0); + + return result; + } + public RESULT getAudibility (ref float audibility) + { + return FMOD_Channel_GetAudibility(channelraw, ref audibility); + } + public RESULT getCurrentSound (ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + try + { + result = FMOD_Channel_GetCurrentSound(channelraw, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT getSpectrum (float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype) + { + return FMOD_Channel_GetSpectrum(channelraw, spectrumarray, numvalues, channeloffset, windowtype); + } + public RESULT getWaveData (float[] wavearray, int numvalues, int channeloffset) + { + return FMOD_Channel_GetWaveData(channelraw, wavearray, numvalues, channeloffset); + } + public RESULT getIndex (ref int index) + { + return FMOD_Channel_GetIndex(channelraw, ref index); + } + + public RESULT getDSPHead (ref DSP dsp) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_Channel_GetDSPHead(channelraw, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + dspnew = new DSP(); + dspnew.setRaw(dspraw); + dsp = dspnew; + + return result; + } + public RESULT addDSP (DSP dsp, ref DSPConnection connection) + { + RESULT result = RESULT.OK; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_Channel_AddDSP(channelraw, dsp.getRaw(), ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (connection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + connection = dspconnectionnew; + } + else + { + connection.setRaw(dspconnectionraw); + } + + return result; + } + + + public RESULT setMode (MODE mode) + { + return FMOD_Channel_SetMode(channelraw, mode); + } + public RESULT getMode (ref MODE mode) + { + return FMOD_Channel_GetMode(channelraw, ref mode); + } + public RESULT setLoopCount (int loopcount) + { + return FMOD_Channel_SetLoopCount(channelraw, loopcount); + } + public RESULT getLoopCount (ref int loopcount) + { + return FMOD_Channel_GetLoopCount(channelraw, ref loopcount); + } + public RESULT setLoopPoints (uint loopstart, TIMEUNIT loopstarttype, uint loopend, TIMEUNIT loopendtype) + { + return FMOD_Channel_SetLoopPoints(channelraw, loopstart, loopstarttype, loopend, loopendtype); + } + public RESULT getLoopPoints (ref uint loopstart, TIMEUNIT loopstarttype, ref uint loopend, TIMEUNIT loopendtype) + { + return FMOD_Channel_GetLoopPoints(channelraw, ref loopstart, loopstarttype, ref loopend, loopendtype); + } + + + public RESULT setUserData (IntPtr userdata) + { + return FMOD_Channel_SetUserData(channelraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_Channel_GetUserData(channelraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_Channel_GetMemoryInfo(channelraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetSystemObject (IntPtr channel, ref IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Stop (IntPtr channel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetPaused (IntPtr channel, int paused); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetPaused (IntPtr channel, ref int paused); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetVolume (IntPtr channel, float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetVolume (IntPtr channel, ref float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetFrequency (IntPtr channel, float frequency); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetFrequency (IntPtr channel, ref float frequency); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetPan (IntPtr channel, float pan); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetPan (IntPtr channel, ref float pan); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetDelay (IntPtr channel, DELAYTYPE delaytype, uint delayhi, uint delaylo); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetDelay (IntPtr channel, DELAYTYPE delaytype, ref uint delayhi, ref uint delaylo); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetSpeakerMix (IntPtr channel, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetSpeakerMix (IntPtr channel, ref float frontleft, ref float frontright, ref float center, ref float lfe, ref float backleft, ref float backright, ref float sideleft, ref float sideright); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetSpeakerLevels (IntPtr channel, SPEAKER speaker, float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetSpeakerLevels (IntPtr channel, SPEAKER speaker, [MarshalAs(UnmanagedType.LPArray)]float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetInputChannelMix (IntPtr channel, float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetInputChannelMix (IntPtr channel, [MarshalAs(UnmanagedType.LPArray)]float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetMute (IntPtr channel, int mute); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetMute (IntPtr channel, ref int mute); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetPriority (IntPtr channel, int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetPriority (IntPtr channel, ref int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DAttributes (IntPtr channel, ref VECTOR pos, ref VECTOR vel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DAttributes (IntPtr channel, ref VECTOR pos, ref VECTOR vel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DMinMaxDistance (IntPtr channel, float mindistance, float maxdistance); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DMinMaxDistance (IntPtr channel, ref float mindistance, ref float maxdistance); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DConeSettings (IntPtr channel, float insideconeangle, float outsideconeangle, float outsidevolume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DConeSettings (IntPtr channel, ref float insideconeangle, ref float outsideconeangle, ref float outsidevolume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DConeOrientation (IntPtr channel, ref VECTOR orientation); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DConeOrientation (IntPtr channel, ref VECTOR orientation); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DCustomRolloff (IntPtr channel, ref VECTOR points, int numpoints); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DCustomRolloff (IntPtr channel, ref IntPtr points, ref int numpoints); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DOcclusion (IntPtr channel, float directocclusion, float reverbocclusion); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DOcclusion (IntPtr channel, ref float directocclusion, ref float reverbocclusion); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DSpread (IntPtr channel, float angle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DSpread (IntPtr channel, ref float angle); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DPanLevel (IntPtr channel, float level); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DPanLevel (IntPtr channel, ref float level); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Set3DDopplerLevel (IntPtr channel, float level); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_Get3DDopplerLevel (IntPtr channel, ref float level); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetReverbProperties (IntPtr channel, ref REVERB_CHANNELPROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetReverbProperties (IntPtr channel, ref REVERB_CHANNELPROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetLowPassGain (IntPtr channel, float gain); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetLowPassGain (IntPtr channel, ref float gain); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetChannelGroup (IntPtr channel, IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetChannelGroup (IntPtr channel, ref IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_IsPlaying (IntPtr channel, ref int isplaying); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_IsVirtual (IntPtr channel, ref int isvirtual); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetAudibility (IntPtr channel, ref float audibility); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetCurrentSound (IntPtr channel, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetSpectrum (IntPtr channel, [MarshalAs(UnmanagedType.LPArray)] float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetWaveData (IntPtr channel, [MarshalAs(UnmanagedType.LPArray)] float[] wavearray, int numvalues, int channeloffset); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetIndex (IntPtr channel, ref int index); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetCallback (IntPtr channel, CHANNEL_CALLBACK callback); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetPosition (IntPtr channel, uint position, TIMEUNIT postype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetPosition (IntPtr channel, ref uint position, TIMEUNIT postype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetDSPHead (IntPtr channel, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_AddDSP (IntPtr channel, IntPtr dsp, ref IntPtr connection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetMode (IntPtr channel, MODE mode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetMode (IntPtr channel, ref MODE mode); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetLoopCount (IntPtr channel, int loopcount); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetLoopCount (IntPtr channel, ref int loopcount); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetLoopPoints (IntPtr channel, uint loopstart, TIMEUNIT loopstarttype, uint loopend, TIMEUNIT loopendtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetLoopPoints (IntPtr channel, ref uint loopstart, TIMEUNIT loopstarttype, ref uint loopend, TIMEUNIT loopendtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_SetUserData (IntPtr channel, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Channel_GetUserData (IntPtr channel, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Channel_GetMemoryInfo (IntPtr channel, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr channelraw; + + public void setRaw(IntPtr channel) + { + channelraw = new IntPtr(); + + channelraw = channel; + } + + public IntPtr getRaw() + { + return channelraw; + } + + #endregion + } + + + /* + 'ChannelGroup' API + */ + public class ChannelGroup + { + public RESULT release () + { + return FMOD_ChannelGroup_Release(channelgroupraw); + } + public RESULT getSystemObject (ref System system) + { + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + try + { + result = FMOD_ChannelGroup_GetSystemObject(channelgroupraw, ref systemraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (system == null) + { + systemnew = new System(); + systemnew.setRaw(systemraw); + system = systemnew; + } + else + { + system.setRaw(systemraw); + } + + return result; + } + + + // Channelgroup scale values. (scales the current volume or pitch of all channels and channel groups, DOESN'T overwrite) + public RESULT setVolume (float volume) + { + return FMOD_ChannelGroup_SetVolume(channelgroupraw, volume); + } + public RESULT getVolume (ref float volume) + { + return FMOD_ChannelGroup_GetVolume(channelgroupraw, ref volume); + } + public RESULT setPitch (float pitch) + { + return FMOD_ChannelGroup_SetPitch(channelgroupraw, pitch); + } + public RESULT getPitch (ref float pitch) + { + return FMOD_ChannelGroup_GetPitch(channelgroupraw, ref pitch); + } + public RESULT set3DOcclusion (float directocclusion, float reverbocclusion) + { + return FMOD_ChannelGroup_Set3DOcclusion(channelgroupraw, directocclusion, reverbocclusion); + } + public RESULT get3DOcclusion (ref float directocclusion, ref float reverbocclusion) + { + return FMOD_ChannelGroup_Get3DOcclusion(channelgroupraw, ref directocclusion, ref reverbocclusion); + } + public RESULT setPaused (bool paused) + { + return FMOD_ChannelGroup_SetPaused(channelgroupraw, (paused ? 1 : 0)); + } + public RESULT getPaused (ref bool paused) + { + RESULT result; + int p = 0; + + result = FMOD_ChannelGroup_GetPaused(channelgroupraw, ref p); + + paused = (p != 0); + + return result; + } + public RESULT setMute (bool mute) + { + return FMOD_ChannelGroup_SetMute(channelgroupraw, (mute ? 1 : 0)); + } + public RESULT getMute (ref bool mute) + { + RESULT result; + int m = 0; + + result = FMOD_ChannelGroup_GetMute(channelgroupraw, ref m); + + mute = (m != 0); + + return result; + } + + + // Channelgroup override values. (recursively overwrites whatever settings the channels had) + public RESULT stop () + { + return FMOD_ChannelGroup_Stop(channelgroupraw); + } + public RESULT overrideVolume (float volume) + { + return FMOD_ChannelGroup_OverrideVolume(channelgroupraw, volume); + } + public RESULT overrideFrequency (float frequency) + { + return FMOD_ChannelGroup_OverrideFrequency(channelgroupraw, frequency); + } + public RESULT overridePan (float pan) + { + return FMOD_ChannelGroup_OverridePan(channelgroupraw, pan); + } + public RESULT overrideReverbProperties (ref REVERB_CHANNELPROPERTIES prop) + { + return FMOD_ChannelGroup_OverrideReverbProperties(channelgroupraw, ref prop); + } + public RESULT override3DAttributes (ref VECTOR pos, ref VECTOR vel) + { + return FMOD_ChannelGroup_Override3DAttributes(channelgroupraw, ref pos, ref vel); + } + public RESULT overrideSpeakerMix (float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright) + { + return FMOD_ChannelGroup_OverrideSpeakerMix(channelgroupraw, frontleft, frontright, center, lfe, backleft, backright, sideleft, sideright); + } + + + // Nested channel groups. + public RESULT addGroup (ChannelGroup group) + { + return FMOD_ChannelGroup_AddGroup(channelgroupraw, group.getRaw()); + } + public RESULT getNumGroups (ref int numgroups) + { + return FMOD_ChannelGroup_GetNumGroups(channelgroupraw, ref numgroups); + } + public RESULT getGroup (int index, ref ChannelGroup group) + { + RESULT result = RESULT.OK; + IntPtr channelraw = new IntPtr(); + ChannelGroup channelnew = null; + + try + { + result = FMOD_ChannelGroup_GetGroup(channelgroupraw, index, ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (group == null) + { + channelnew = new ChannelGroup(); + channelnew.setRaw(channelraw); + group = channelnew; + } + else + { + group.setRaw(channelraw); + } + + return result; + } + public RESULT getParentGroup (ref ChannelGroup group) + { + RESULT result = RESULT.OK; + IntPtr channelraw = new IntPtr(); + ChannelGroup channelnew = null; + + try + { + result = FMOD_ChannelGroup_GetParentGroup(channelgroupraw, ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (group == null) + { + channelnew = new ChannelGroup(); + channelnew.setRaw(channelraw); + group = channelnew; + } + else + { + group.setRaw(channelraw); + } + + return result; + } + + + // DSP functionality only for channel groups playing sounds created with FMOD_SOFTWARE. + public RESULT getDSPHead (ref DSP dsp) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_ChannelGroup_GetDSPHead(channelgroupraw, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (dsp == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + dsp = dspnew; + } + else + { + dsp.setRaw(dspraw); + } + + return result; + } + + public RESULT addDSP (DSP dsp, ref DSPConnection connection) + { + RESULT result = RESULT.OK; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_ChannelGroup_AddDSP(channelgroupraw, dsp.getRaw(), ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (connection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + connection = dspconnectionnew; + } + else + { + connection.setRaw(dspconnectionraw); + } + + return result; + } + + + // Information only functions. + public RESULT getName (StringBuilder name, int namelen) + { + return FMOD_ChannelGroup_GetName(channelgroupraw, name, namelen); + } + public RESULT getNumChannels (ref int numchannels) + { + return FMOD_ChannelGroup_GetNumChannels(channelgroupraw, ref numchannels); + } + public RESULT getChannel (int index, ref Channel channel) + { + RESULT result = RESULT.OK; + IntPtr channelraw = new IntPtr(); + Channel channelnew = null; + + try + { + result = FMOD_ChannelGroup_GetChannel(channelgroupraw, index, ref channelraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (channel == null) + { + channelnew = new Channel(); + channelnew.setRaw(channelraw); + channel = channelnew; + } + else + { + channel.setRaw(channelraw); + } + + return result; + } + public RESULT getSpectrum (float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype) + { + return FMOD_ChannelGroup_GetSpectrum(channelgroupraw, spectrumarray, numvalues, channeloffset, windowtype); + } + public RESULT getWaveData (float[] wavearray, int numvalues, int channeloffset) + { + return FMOD_ChannelGroup_GetWaveData(channelgroupraw, wavearray, numvalues, channeloffset); + } + + + // Userdata set/get. + public RESULT setUserData (IntPtr userdata) + { + return FMOD_ChannelGroup_SetUserData(channelgroupraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_ChannelGroup_GetUserData(channelgroupraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_ChannelGroup_GetMemoryInfo(channelgroupraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_Release (IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetSystemObject (IntPtr channelgroup, ref IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_SetVolume (IntPtr channelgroup, float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetVolume (IntPtr channelgroup, ref float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_SetPitch (IntPtr channelgroup, float pitch); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetPitch (IntPtr channelgroup, ref float pitch); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_Set3DOcclusion (IntPtr channelgroup, float directocclusion, float reverbocclusion); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_Get3DOcclusion (IntPtr channelgroup, ref float directocclusion, ref float reverbocclusion); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_SetPaused (IntPtr channelgroup, int paused); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetPaused (IntPtr channelgroup, ref int paused); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_SetMute (IntPtr channelgroup, int mute); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetMute (IntPtr channelgroup, ref int mute); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_Stop (IntPtr channelgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverridePaused (IntPtr channelgroup, int paused); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverrideVolume (IntPtr channelgroup, float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverrideFrequency(IntPtr channelgroup, float frequency); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverridePan (IntPtr channelgroup, float pan); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverrideMute (IntPtr channelgroup, int mute); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverrideReverbProperties(IntPtr channelgroup, ref REVERB_CHANNELPROPERTIES prop); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_Override3DAttributes (IntPtr channelgroup, ref VECTOR pos, ref VECTOR vel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_OverrideSpeakerMix(IntPtr channelgroup, float frontleft, float frontright, float center, float lfe, float backleft, float backright, float sideleft, float sideright); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_AddGroup (IntPtr channelgroup, IntPtr group); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetNumGroups (IntPtr channelgroup, ref int numgroups); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetGroup (IntPtr channelgroup, int index, ref IntPtr group); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetParentGroup (IntPtr channelgroup, ref IntPtr group); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetDSPHead (IntPtr channelgroup, ref IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_AddDSP (IntPtr channelgroup, IntPtr dsp, ref IntPtr connection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetName (IntPtr channelgroup, StringBuilder name, int namelen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetNumChannels (IntPtr channelgroup, ref int numchannels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetChannel (IntPtr channelgroup, int index, ref IntPtr channel); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetSpectrum (IntPtr channelgroup, [MarshalAs(UnmanagedType.LPArray)] float[] spectrumarray, int numvalues, int channeloffset, DSP_FFT_WINDOW windowtype); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetWaveData (IntPtr channelgroup, [MarshalAs(UnmanagedType.LPArray)] float[] wavearray, int numvalues, int channeloffset); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_SetUserData (IntPtr channelgroup, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetUserData (IntPtr channelgroup, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_ChannelGroup_GetMemoryInfo (IntPtr channelgroup, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr channelgroupraw; + + public void setRaw(IntPtr channelgroup) + { + channelgroupraw = new IntPtr(); + + channelgroupraw = channelgroup; + } + + public IntPtr getRaw() + { + return channelgroupraw; + } + + #endregion + } + + + /* + 'SoundGroup' API + */ + public class SoundGroup + { + public RESULT release () + { + return FMOD_SoundGroup_Release(soundgroupraw); + } + + public RESULT getSystemObject (ref System system) + { + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + try + { + result = FMOD_SoundGroup_GetSystemObject(soundgroupraw, ref systemraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (system == null) + { + systemnew = new System(); + systemnew.setRaw(systemraw); + system = systemnew; + } + else + { + system.setRaw(systemraw); + } + + return result; + } + + // SoundGroup control functions. + public RESULT setMaxAudible (int maxaudible) + { + return FMOD_SoundGroup_SetMaxAudible(soundgroupraw, maxaudible); + } + + public RESULT getMaxAudible (ref int maxaudible) + { + return FMOD_SoundGroup_GetMaxAudible(soundgroupraw, ref maxaudible); + } + + public RESULT setMaxAudibleBehavior (SOUNDGROUP_BEHAVIOR behavior) + { + return FMOD_SoundGroup_SetMaxAudibleBehavior(soundgroupraw, behavior); + } + public RESULT getMaxAudibleBehavior (ref SOUNDGROUP_BEHAVIOR behavior) + { + return FMOD_SoundGroup_GetMaxAudibleBehavior(soundgroupraw, ref behavior); + } + public RESULT setMuteFadeSpeed (float speed) + { + return FMOD_SoundGroup_SetMuteFadeSpeed(soundgroupraw, speed); + } + public RESULT getMuteFadeSpeed (ref float speed) + { + return FMOD_SoundGroup_GetMuteFadeSpeed(soundgroupraw, ref speed); + } + + public RESULT setVolume (float volume) + { + return FMOD_SoundGroup_SetVolume(soundgroupraw, volume); + } + public RESULT getVolume (ref float volume) + { + return FMOD_SoundGroup_GetVolume(soundgroupraw, ref volume); + } + public RESULT stop () + { + return FMOD_SoundGroup_Stop(soundgroupraw); + } + + // Information only functions. + public RESULT getName (StringBuilder name, int namelen) + { + return FMOD_SoundGroup_GetName(soundgroupraw, name, namelen); + } + public RESULT getNumSounds (ref int numsounds) + { + return FMOD_SoundGroup_GetNumSounds(soundgroupraw, ref numsounds); + } + public RESULT getSound (int index, ref Sound sound) + { + RESULT result = RESULT.OK; + IntPtr soundraw = new IntPtr(); + Sound soundnew = null; + + try + { + result = FMOD_SoundGroup_GetSound(soundgroupraw, index, ref soundraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (sound == null) + { + soundnew = new Sound(); + soundnew.setRaw(soundraw); + sound = soundnew; + } + else + { + sound.setRaw(soundraw); + } + + return result; + } + public RESULT getNumPlaying (ref int numplaying) + { + return FMOD_SoundGroup_GetNumPlaying(soundgroupraw, ref numplaying); + } + + // Userdata set/get. + public RESULT setUserData (IntPtr userdata) + { + return FMOD_SoundGroup_SetUserData(soundgroupraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_SoundGroup_GetUserData(soundgroupraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_SoundGroup_GetMemoryInfo(soundgroupraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_Release (IntPtr soundgroup); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetSystemObject (IntPtr soundgroup, ref IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_SetMaxAudible (IntPtr soundgroup, int maxaudible); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetMaxAudible (IntPtr soundgroup, ref int maxaudible); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_SetMaxAudibleBehavior(IntPtr soundgroup, SOUNDGROUP_BEHAVIOR behavior); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetMaxAudibleBehavior(IntPtr soundgroup, ref SOUNDGROUP_BEHAVIOR behavior); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_SetMuteFadeSpeed (IntPtr soundgroup, float speed); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetMuteFadeSpeed (IntPtr soundgroup, ref float speed); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_SetVolume (IntPtr soundgroup, float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetVolume (IntPtr soundgroup, ref float volume); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_Stop (IntPtr soundgroup); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetName (IntPtr soundgroup, StringBuilder name, int namelen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetNumSounds (IntPtr soundgroup, ref int numsounds); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetSound (IntPtr soundgroup, int index, ref IntPtr sound); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetNumPlaying (IntPtr soundgroup, ref int numplaying); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_SetUserData (IntPtr soundgroup, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetUserData (IntPtr soundgroup, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_SoundGroup_GetMemoryInfo (IntPtr soundgroup, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr soundgroupraw; + + public void setRaw(IntPtr soundgroup) + { + soundgroupraw = new IntPtr(); + + soundgroupraw = soundgroup; + } + + public IntPtr getRaw() + { + return soundgroupraw; + } + + #endregion + } + + + /* + 'DSP' API + */ + public class DSP + { + public RESULT release () + { + return FMOD_DSP_Release(dspraw); + } + public RESULT getSystemObject (ref System system) + { + RESULT result = RESULT.OK; + IntPtr systemraw = new IntPtr(); + System systemnew = null; + + try + { + result = FMOD_DSP_GetSystemObject(dspraw, ref systemraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (system == null) + { + systemnew = new System(); + systemnew.setRaw(dspraw); + system = systemnew; + } + else + { + system.setRaw(systemraw); + } + + return result; + } + + + public RESULT addInput(DSP target, ref DSPConnection connection) + { + RESULT result = RESULT.OK; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_DSP_AddInput(dspraw, target.getRaw(), ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (connection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + connection = dspconnectionnew; + } + else + { + connection.setRaw(dspconnectionraw); + } + + return result; + } + public RESULT disconnectFrom (DSP target) + { + return FMOD_DSP_DisconnectFrom(dspraw, target.getRaw()); + } + public RESULT disconnectAll (bool inputs, bool outputs) + { + return FMOD_DSP_DisconnectAll(dspraw, (inputs ? 1 : 0), (outputs ? 1 : 0)); + } + public RESULT remove () + { + return FMOD_DSP_Remove(dspraw); + } + public RESULT getNumInputs (ref int numinputs) + { + return FMOD_DSP_GetNumInputs(dspraw, ref numinputs); + } + public RESULT getNumOutputs (ref int numoutputs) + { + return FMOD_DSP_GetNumOutputs(dspraw, ref numoutputs); + } + public RESULT getInput (int index, ref DSP input, ref DSPConnection inputconnection) + { + RESULT result = RESULT.OK; + IntPtr dsprawnew = new IntPtr(); + DSP dspnew = null; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_DSP_GetInput(dspraw, index, ref dsprawnew, ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (input == null) + { + dspnew = new DSP(); + dspnew.setRaw(dsprawnew); + input = dspnew; + } + else + { + input.setRaw(dsprawnew); + } + + if (inputconnection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + inputconnection = dspconnectionnew; + } + else + { + inputconnection.setRaw(dspconnectionraw); + } + + return result; + } + public RESULT getOutput (int index, ref DSP output, ref DSPConnection outputconnection) + { + RESULT result = RESULT.OK; + IntPtr dsprawnew = new IntPtr(); + DSP dspnew = null; + IntPtr dspconnectionraw = new IntPtr(); + DSPConnection dspconnectionnew = null; + + try + { + result = FMOD_DSP_GetOutput(dspraw, index, ref dsprawnew, ref dspconnectionraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (output == null) + { + dspnew = new DSP(); + dspnew.setRaw(dsprawnew); + output = dspnew; + } + else + { + output.setRaw(dsprawnew); + } + + if (outputconnection == null) + { + dspconnectionnew = new DSPConnection(); + dspconnectionnew.setRaw(dspconnectionraw); + outputconnection = dspconnectionnew; + } + else + { + outputconnection.setRaw(dspconnectionraw); + } + + return result; + } + + public RESULT setActive (bool active) + { + return FMOD_DSP_SetActive(dspraw, (active ? 1 : 0)); + } + public RESULT getActive (ref bool active) + { + RESULT result; + int a = 0; + + result = FMOD_DSP_GetActive(dspraw, ref a); + + active = (a != 0); + + return result; + } + public RESULT setBypass (bool bypass) + { + return FMOD_DSP_SetBypass(dspraw, (bypass? 1 : 0)); + } + public RESULT getBypass (ref bool bypass) + { + RESULT result; + int b = 0; + + result = FMOD_DSP_GetBypass(dspraw, ref b); + + bypass = (b != 0); + + return result; + } + + public RESULT setSpeakerActive (SPEAKER speaker, bool active) + { + return FMOD_DSP_SetSpeakerActive(dspraw, speaker, (active ? 1 : 0)); + } + public RESULT getSpeakerActive (SPEAKER speaker, ref bool active) + { + RESULT result; + int a = 0; + + result = FMOD_DSP_GetSpeakerActive(dspraw, speaker, ref a); + + active = (a != 0); + + return result; + } + + public RESULT reset () + { + return FMOD_DSP_Reset(dspraw); + } + + + public RESULT setParameter (int index, float value) + { + return FMOD_DSP_SetParameter(dspraw, index, value); + } + public RESULT getParameter (int index, ref float value, StringBuilder valuestr, int valuestrlen) + { + return FMOD_DSP_GetParameter(dspraw, index, ref value, valuestr, valuestrlen); + } + public RESULT getNumParameters (ref int numparams) + { + return FMOD_DSP_GetNumParameters(dspraw, ref numparams); + } + public RESULT getParameterInfo (int index, StringBuilder name, StringBuilder label, StringBuilder description, int descriptionlen, ref float min, ref float max) + { + return FMOD_DSP_GetParameterInfo(dspraw, index, name, label, description, descriptionlen, ref min, ref max); + } + public RESULT showConfigDialog (IntPtr hwnd, bool show) + { + return FMOD_DSP_ShowConfigDialog (dspraw, hwnd, (show ? 1 : 0)); + } + + + public RESULT getInfo (StringBuilder name, ref uint version, ref int channels, ref int configwidth, ref int configheight) + { + return FMOD_DSP_GetInfo(dspraw, name, ref version, ref channels, ref configwidth, ref configheight); + } + public RESULT getType (ref DSP_TYPE type) + { + return FMOD_DSP_GetType(dspraw, ref type); + } + public RESULT setDefaults (float frequency, float volume, float pan, int priority) + { + return FMOD_DSP_SetDefaults(dspraw, frequency, volume, pan, priority); + } + public RESULT getDefaults (ref float frequency, ref float volume, ref float pan, ref int priority) + { + return FMOD_DSP_GetDefaults(dspraw, ref frequency, ref volume, ref pan, ref priority); + } + + + public RESULT setUserData (IntPtr userdata) + { + return FMOD_DSP_SetUserData(dspraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_DSP_GetUserData(dspraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_DSP_GetMemoryInfo(dspraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_Release (IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetSystemObject (IntPtr dsp, ref IntPtr system); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_AddInput (IntPtr dsp, IntPtr target, ref IntPtr connection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_DisconnectFrom (IntPtr dsp, IntPtr target); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_DisconnectAll (IntPtr dsp, int inputs, int outputs); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_Remove (IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetNumInputs (IntPtr dsp, ref int numinputs); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetNumOutputs (IntPtr dsp, ref int numoutputs); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetInput (IntPtr dsp, int index, ref IntPtr input, ref IntPtr inputconnection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetOutput (IntPtr dsp, int index, ref IntPtr output, ref IntPtr outputconnection); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetActive (IntPtr dsp, int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetActive (IntPtr dsp, ref int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetBypass (IntPtr dsp, int bypass); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetBypass (IntPtr dsp, ref int bypass); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetSpeakerActive (IntPtr dsp, SPEAKER speaker, int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetSpeakerActive (IntPtr dsp, SPEAKER speaker, ref int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_Reset (IntPtr dsp); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetParameter (IntPtr dsp, int index, float value); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetParameter (IntPtr dsp, int index, ref float value, StringBuilder valuestr, int valuestrlen); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetNumParameters (IntPtr dsp, ref int numparams); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetParameterInfo (IntPtr dsp, int index, StringBuilder name, StringBuilder label, StringBuilder description, int descriptionlen, ref float min, ref float max); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_ShowConfigDialog (IntPtr dsp, IntPtr hwnd, int show); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetInfo (IntPtr dsp, StringBuilder name, ref uint version, ref int channels, ref int configwidth, ref int configheight); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetType (IntPtr dsp, ref DSP_TYPE type); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetDefaults (IntPtr dsp, float frequency, float volume, float pan, int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetDefaults (IntPtr dsp, ref float frequency, ref float volume, ref float pan, ref int priority); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_SetUserData (IntPtr dsp, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSP_GetUserData (IntPtr dsp, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_DSP_GetMemoryInfo (IntPtr dsp, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr dspraw; + + public void setRaw(IntPtr dsp) + { + dspraw = new IntPtr(); + + dspraw = dsp; + } + + public IntPtr getRaw() + { + return dspraw; + } + + #endregion + } + + + /* + 'DSPConnection' API + */ + public class DSPConnection + { + public RESULT getInput (ref DSP input) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_DSPConnection_GetInput(dspconnectionraw, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (input == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + input = dspnew; + } + else + { + input.setRaw(dspraw); + } + + return result; + } + public RESULT getOutput (ref DSP output) + { + RESULT result = RESULT.OK; + IntPtr dspraw = new IntPtr(); + DSP dspnew = null; + + try + { + result = FMOD_DSPConnection_GetOutput(dspconnectionraw, ref dspraw); + } + catch + { + result = RESULT.ERR_INVALID_PARAM; + } + if (result != RESULT.OK) + { + return result; + } + + if (output == null) + { + dspnew = new DSP(); + dspnew.setRaw(dspraw); + output = dspnew; + } + else + { + output.setRaw(dspraw); + } + + return result; + } + public RESULT setMix (float volume) + { + return FMOD_DSPConnection_SetMix(dspconnectionraw, volume); + } + public RESULT getMix (ref float volume) + { + return FMOD_DSPConnection_GetMix(dspconnectionraw, ref volume); + } + public RESULT setLevels (SPEAKER speaker, float[] levels, int numlevels) + { + return FMOD_DSPConnection_SetLevels(dspconnectionraw, speaker, levels, numlevels); + } + public RESULT getLevels (SPEAKER speaker, float[] levels, int numlevels) + { + return FMOD_DSPConnection_GetLevels(dspconnectionraw, speaker, levels, numlevels); + } + public RESULT setUserData(IntPtr userdata) + { + return FMOD_DSPConnection_SetUserData(dspconnectionraw, userdata); + } + public RESULT getUserData(ref IntPtr userdata) + { + return FMOD_DSPConnection_GetUserData(dspconnectionraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_DSPConnection_GetMemoryInfo(dspconnectionraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetInput (IntPtr dspconnection, ref IntPtr input); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetOutput (IntPtr dspconnection, ref IntPtr output); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_SetMix (IntPtr dspconnection, float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetMix (IntPtr dspconnection, ref float volume); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_SetLevels (IntPtr dspconnection, SPEAKER speaker, float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetLevels (IntPtr dspconnection, SPEAKER speaker, [MarshalAs(UnmanagedType.LPArray)]float[] levels, int numlevels); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_SetUserData (IntPtr dspconnection, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetUserData (IntPtr dspconnection, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_DSPConnection_GetMemoryInfo (IntPtr dspconnection, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr dspconnectionraw; + + public void setRaw(IntPtr dspconnection) + { + dspconnectionraw = new IntPtr(); + + dspconnectionraw = dspconnection; + } + + public IntPtr getRaw() + { + return dspconnectionraw; + } + + #endregion + } + + /* + 'Geometry' API + */ + public class Geometry + { + public RESULT release () + { + return FMOD_Geometry_Release(geometryraw); + } + public RESULT addPolygon (float directocclusion, float reverbocclusion, bool doublesided, int numvertices, VECTOR[] vertices, ref int polygonindex) + { + return FMOD_Geometry_AddPolygon(geometryraw, directocclusion, reverbocclusion, (doublesided ? 1 : 0), numvertices, vertices, ref polygonindex); + } + + + public RESULT getNumPolygons (ref int numpolygons) + { + return FMOD_Geometry_GetNumPolygons(geometryraw, ref numpolygons); + } + public RESULT getMaxPolygons (ref int maxpolygons, ref int maxvertices) + { + return FMOD_Geometry_GetMaxPolygons(geometryraw, ref maxpolygons, ref maxvertices); + } + public RESULT getPolygonNumVertices (int index, ref int numvertices) + { + return FMOD_Geometry_GetPolygonNumVertices(geometryraw, index, ref numvertices); + } + public RESULT setPolygonVertex (int index, int vertexindex, ref VECTOR vertex) + { + return FMOD_Geometry_SetPolygonVertex(geometryraw, index, vertexindex, ref vertex); + } + public RESULT getPolygonVertex (int index, int vertexindex, ref VECTOR vertex) + { + return FMOD_Geometry_GetPolygonVertex(geometryraw, index, vertexindex, ref vertex); + } + public RESULT setPolygonAttributes (int index, float directocclusion, float reverbocclusion, bool doublesided) + { + return FMOD_Geometry_SetPolygonAttributes(geometryraw, index, directocclusion, reverbocclusion, (doublesided ? 1 : 0)); + } + public RESULT getPolygonAttributes (int index, ref float directocclusion, ref float reverbocclusion, ref bool doublesided) + { + RESULT result; + int ds = 0; + + result = FMOD_Geometry_GetPolygonAttributes(geometryraw, index, ref directocclusion, ref reverbocclusion, ref ds); + + doublesided = (ds != 0); + + return result; + } + + public RESULT setActive (bool active) + { + return FMOD_Geometry_SetActive (geometryraw, (active ? 1 : 0)); + } + public RESULT getActive (ref bool active) + { + RESULT result; + int a = 0; + + result = FMOD_Geometry_GetActive (geometryraw, ref a); + + active = (a != 0); + + return result; + } + public RESULT setRotation (ref VECTOR forward, ref VECTOR up) + { + return FMOD_Geometry_SetRotation(geometryraw, ref forward, ref up); + } + public RESULT getRotation (ref VECTOR forward, ref VECTOR up) + { + return FMOD_Geometry_GetRotation(geometryraw, ref forward, ref up); + } + public RESULT setPosition (ref VECTOR position) + { + return FMOD_Geometry_SetPosition(geometryraw, ref position); + } + public RESULT getPosition (ref VECTOR position) + { + return FMOD_Geometry_GetPosition(geometryraw, ref position); + } + public RESULT setScale (ref VECTOR scale) + { + return FMOD_Geometry_SetScale(geometryraw, ref scale); + } + public RESULT getScale (ref VECTOR scale) + { + return FMOD_Geometry_GetScale(geometryraw, ref scale); + } + public RESULT save (IntPtr data, ref int datasize) + { + return FMOD_Geometry_Save(geometryraw, data, ref datasize); + } + + + public RESULT setUserData (IntPtr userdata) + { + return FMOD_Geometry_SetUserData(geometryraw, userdata); + } + public RESULT getUserData (ref IntPtr userdata) + { + return FMOD_Geometry_GetUserData(geometryraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_Geometry_GetMemoryInfo(geometryraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_Release (IntPtr geometry); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_AddPolygon (IntPtr geometry, float directocclusion, float reverbocclusion, int doublesided, int numvertices, VECTOR[] vertices, ref int polygonindex); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetNumPolygons (IntPtr geometry, ref int numpolygons); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetMaxPolygons (IntPtr geometry, ref int maxpolygons, ref int maxvertices); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetPolygonNumVertices(IntPtr geometry, int index, ref int numvertices); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetPolygonVertex (IntPtr geometry, int index, int vertexindex, ref VECTOR vertex); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetPolygonVertex (IntPtr geometry, int index, int vertexindex, ref VECTOR vertex); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetPolygonAttributes (IntPtr geometry, int index, float directocclusion, float reverbocclusion, int doublesided); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetPolygonAttributes (IntPtr geometry, int index, ref float directocclusion, ref float reverbocclusion, ref int doublesided); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_Flush (IntPtr geometry); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetActive (IntPtr geometry, int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetActive (IntPtr geometry, ref int active); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetRotation (IntPtr geometry, ref VECTOR forward, ref VECTOR up); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetRotation (IntPtr geometry, ref VECTOR forward, ref VECTOR up); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetPosition (IntPtr geometry, ref VECTOR position); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetPosition (IntPtr geometry, ref VECTOR position); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetScale (IntPtr geometry, ref VECTOR scale); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetScale (IntPtr geometry, ref VECTOR scale); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_Save (IntPtr geometry, IntPtr data, ref int datasize); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_SetUserData (IntPtr geometry, IntPtr userdata); + [DllImport (VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetUserData (IntPtr geometry, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Geometry_GetMemoryInfo (IntPtr geometry, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr geometryraw; + + public void setRaw(IntPtr geometry) + { + geometryraw = new IntPtr(); + + geometryraw = geometry; + } + + public IntPtr getRaw() + { + return geometryraw; + } + + #endregion + } + + /* + 'Reverb' API + */ + public class Reverb + { + + public RESULT release() + { + return FMOD_Reverb_Release(reverbraw); + } + + // Reverb manipulation. + public RESULT set3DAttributes(ref VECTOR position, float mindistance, float maxdistance) + { + return FMOD_Reverb_Set3DAttributes(reverbraw, ref position, mindistance, maxdistance); + } + public RESULT get3DAttributes(ref VECTOR position, ref float mindistance, ref float maxdistance) + { + return FMOD_Reverb_Get3DAttributes(reverbraw, ref position, ref mindistance, ref maxdistance); + } + public RESULT setProperties(ref REVERB_PROPERTIES properties) + { + return FMOD_Reverb_SetProperties(reverbraw, ref properties); + } + public RESULT getProperties(ref REVERB_PROPERTIES properties) + { + return FMOD_Reverb_GetProperties(reverbraw, ref properties); + } + public RESULT setActive(bool active) + { + return FMOD_Reverb_SetActive(reverbraw, (active ? 1 : 0)); + } + public RESULT getActive(ref bool active) + { + RESULT result; + int a = 0; + + result = FMOD_Reverb_GetActive(reverbraw, ref a); + + active = (a != 0); + + return result; + } + + // Userdata set/get. + public RESULT setUserData(IntPtr userdata) + { + return FMOD_Reverb_SetUserData(reverbraw, userdata); + } + public RESULT getUserData(ref IntPtr userdata) + { + return FMOD_Reverb_GetUserData(reverbraw, ref userdata); + } + + public RESULT getMemoryInfo(uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details) + { + return FMOD_Reverb_GetMemoryInfo(reverbraw, memorybits, event_memorybits, ref memoryused, ref memoryused_details); + } + + #region importfunctions + + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_Release(IntPtr reverb); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_Set3DAttributes(IntPtr reverb, ref VECTOR position, float mindistance, float maxdistance); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_Get3DAttributes(IntPtr reverb, ref VECTOR position, ref float mindistance, ref float maxdistance); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_SetProperties(IntPtr reverb, ref REVERB_PROPERTIES properties); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_GetProperties(IntPtr reverb, ref REVERB_PROPERTIES properties); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_SetActive(IntPtr reverb, int active); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_GetActive(IntPtr reverb, ref int active); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_SetUserData(IntPtr reverb, IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_GetUserData(IntPtr reverb, ref IntPtr userdata); + [DllImport(VERSION.dll)] + private static extern RESULT FMOD_Reverb_GetMemoryInfo(IntPtr reverb, uint memorybits, uint event_memorybits, ref uint memoryused, ref MEMORY_USAGE_DETAILS memoryused_details); + #endregion + + #region wrapperinternal + + private IntPtr reverbraw; + + public void setRaw(IntPtr rev) + { + reverbraw = new IntPtr(); + + reverbraw = rev; + } + + public IntPtr getRaw() + { + return reverbraw; + } + + #endregion + } +} diff --git a/Unity Studio/FMOD/fmod_dsp.cs b/Unity Studio/FMOD/fmod_dsp.cs new file mode 100644 index 0000000..78bd332 --- /dev/null +++ b/Unity Studio/FMOD/fmod_dsp.cs @@ -0,0 +1,739 @@ +/*$ preserve start $*/ +/* ========================================================================================== */ +/* FMOD Ex - DSP header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ +/* */ +/* Use this header if you are interested in delving deeper into the FMOD software mixing / */ +/* DSP engine. In this header you can find parameter structures for FMOD system reigstered */ +/* DSP effects and generators. */ +/* */ +/* ========================================================================================== */ + +using System; +using System.Text; +using System.Runtime.InteropServices; + +namespace FMOD +{ +/*$ preserve end $*/ + + /* + DSP callbacks + */ + public delegate RESULT DSP_CREATECALLBACK (ref DSP_STATE dsp_state); + public delegate RESULT DSP_RELEASECALLBACK (ref DSP_STATE dsp_state); + public delegate RESULT DSP_RESETCALLBACK (ref DSP_STATE dsp_state); + public delegate RESULT DSP_READCALLBACK (ref DSP_STATE dsp_state, IntPtr inbuffer, IntPtr outbuffer, uint length, int inchannels, int outchannels); + public delegate RESULT DSP_SETPOSITIONCALLBACK (ref DSP_STATE dsp_state, uint seeklen); + public delegate RESULT DSP_SETPARAMCALLBACK (ref DSP_STATE dsp_state, int index, float val); + public delegate RESULT DSP_GETPARAMCALLBACK (ref DSP_STATE dsp_state, int index, ref float val, StringBuilder valuestr); + public delegate RESULT DSP_DIALOGCALLBACK (ref DSP_STATE dsp_state, IntPtr hwnd, bool show); + + + /* + [ENUM] + [ + [DESCRIPTION] + These definitions can be used for creating FMOD defined special effects or DSP units. + + [REMARKS] + To get them to be active, first create the unit, then add it somewhere into the DSP network, either at the front of the network near the soundcard unit to affect the global output (by using System::getDSPHead), or on a single channel (using Channel::getDSPHead). + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createDSPByType + ] + */ + public enum DSP_TYPE :int + { + UNKNOWN, /* This unit was created via a non FMOD plugin so has an unknown purpose */ + MIXER, /* This unit does nothing but take inputs and mix them together then feed the result to the soundcard unit. */ + OSCILLATOR, /* This unit generates sine/square/saw/triangle or noise tones. */ + LOWPASS, /* This unit filters sound using a high quality, resonant lowpass filter algorithm but consumes more CPU time. */ + ITLOWPASS, /* This unit filters sound using a resonant lowpass filter algorithm that is used in Impulse Tracker, but with limited cutoff range (0 to 8060hz). */ + HIGHPASS, /* This unit filters sound using a resonant highpass filter algorithm. */ + ECHO, /* This unit produces an echo on the sound and fades out at the desired rate. */ + FLANGE, /* This unit produces a flange effect on the sound. */ + DISTORTION, /* This unit distorts the sound. */ + NORMALIZE, /* This unit normalizes or amplifies the sound to a certain level. */ + PARAMEQ, /* This unit attenuates or amplifies a selected frequency range. */ + PITCHSHIFT, /* This unit bends the pitch of a sound without changing the speed of playback. */ + CHORUS, /* This unit produces a chorus effect on the sound. */ + VSTPLUGIN, /* This unit allows the use of Steinberg VST plugins */ + WINAMPPLUGIN, /* This unit allows the use of Nullsoft Winamp plugins */ + ITECHO, /* This unit produces an echo on the sound and fades out at the desired rate as is used in Impulse Tracker. */ + COMPRESSOR, /* This unit implements dynamic compression (linked multichannel, wideband) */ + SFXREVERB, /* This unit implements SFX reverb */ + LOWPASS_SIMPLE, /* This unit filters sound using a simple lowpass with no resonance, but has flexible cutoff and is fast. */ + DELAY, /* This unit produces different delays on individual channels of the sound. */ + TREMOLO, /* This unit produces a tremolo / chopper effect on the sound. */ + LADSPAPLUGIN, /* This unit allows the use of LADSPA standard plugins. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function.
    + Members marked with [out] mean FMOD sets the value to be used after the function exits.
    +
    + The step parameter tells the gui or application that the parameter has a certain granularity.
    + For example in the example of cutoff frequency with a range from 100.0 to 22050.0 you might only want the selection to be in 10hz increments. For this you would simply use 10.0 as the step value.
    + For a boolean, you can use min = 0.0, max = 1.0, step = 1.0. This way the only possible values are 0.0 and 1.0.
    + Some applications may detect min = 0.0, max = 1.0, step = 1.0 and replace a graphical slider bar with a checkbox instead.
    + A step value of 1.0 would simulate integer values only.
    + A step value of 0.0 would mean the full floating point range is accessable.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createDSP + System::getDSP + ] + */ + public struct DSP_PARAMETERDESC + { + public float min; /* [in] Minimum value of the parameter (ie 100.0). */ + public float max; /* [in] Maximum value of the parameter (ie 22050.0). */ + public float defaultval; /* [in] Default value of parameter. */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public char[] name; /* [in] Name of the parameter to be displayed (ie "Cutoff frequency"). */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public char[] label; /* [in] Short string to be put next to value to denote the unit type (ie "hz"). */ + public string description; /* [in] Description of the parameter to be displayed as a help item / tooltip for this parameter. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + Strcture to define the parameters for a DSP unit. + + [REMARKS] + Members marked with [in] mean the user sets the value before passing it to the function.
    + Members marked with [out] mean FMOD sets the value to be used after the function exits.
    +
    + There are 2 different ways to change a parameter in this architecture.
    + One is to use DSP::setParameter / DSP::getParameter. This is platform independant and is dynamic, so new unknown plugins can have their parameters enumerated and used.
    + The other is to use DSP::showConfigDialog. This is platform specific and requires a GUI, and will display a dialog box to configure the plugin.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + System::createDSP + System::getDSP + ] + */ + public struct DSP_DESCRIPTION + { + [MarshalAs(UnmanagedType.ByValArray,SizeConst=32)] + public char[] name; /* [in] Name of the unit to be displayed in the network. */ + public uint version; /* [in] Plugin writer's version number. */ + public int channels; /* [in] Number of channels. Use 0 to process whatever number of channels is currently in the network. >0 would be mostly used if the unit is a unit that only generates sound. */ + public DSP_CREATECALLBACK create; /* [in] Create callback. This is called when DSP unit is created. Can be null. */ + public DSP_RELEASECALLBACK release; /* [in] Release callback. This is called just before the unit is freed so the user can do any cleanup needed for the unit. Can be null. */ + public DSP_RESETCALLBACK reset; /* [in] Reset callback. This is called by the user to reset any history buffers that may need resetting for a filter, when it is to be used or re-used for the first time to its initial clean state. Use to avoid clicks or artifacts. */ + public DSP_READCALLBACK read; /* [in] Read callback. Processing is done here. Can be null. */ + public DSP_SETPOSITIONCALLBACK setposition; /* [in] Setposition callback. This is called if the unit wants to update its position info but not process data. Can be null. */ + + public int numparameters; /* [in] Number of parameters used in this filter. The user finds this with DSP::getNumParameters */ + public DSP_PARAMETERDESC[] paramdesc; /* [in] Variable number of parameter structures. */ + public DSP_SETPARAMCALLBACK setparameter; /* [in] This is called when the user calls DSP::setParameter. Can be null. */ + public DSP_GETPARAMCALLBACK getparameter; /* [in] This is called when the user calls DSP::getParameter. Can be null. */ + public DSP_DIALOGCALLBACK config; /* [in] This is called when the user calls DSP::showConfigDialog. Can be used to display a dialog to configure the filter. Can be null. */ + public int configwidth; /* [in] Width of config dialog graphic if there is one. 0 otherwise.*/ + public int configheight; /* [in] Height of config dialog graphic if there is one. 0 otherwise.*/ + public IntPtr userdata; /* [in] Optional. Specify 0 to ignore. This is user data to be attached to the DSP unit during creation. Access via DSP::getUserData. */ + } + + + /* + [STRUCTURE] + [ + [DESCRIPTION] + DSP plugin structure that is passed into each callback. + + [REMARKS] + Members marked with [in] mean the variable can be written to. The user can set the value.
    + Members marked with [out] mean the variable is modified by FMOD and is for reading purposes only. Do not change this value.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + FMOD_DSP_DESCRIPTION + ] + */ + public struct DSP_STATE + { + public IntPtr instance; /* [out] Handle to the DSP hand the user created. Not to be modified. C++ users cast to FMOD::DSP to use. */ + public IntPtr plugindata; /* [in] Plugin writer created data the output author wants to attach to this object. */ + public ushort speakermask; /* Specifies which speakers the DSP effect is active on */ + }; + + + /* + ============================================================================================================== + + FMOD built in effect parameters. + Use DSP::setParameter with these enums for the 'index' parameter. + + ============================================================================================================== + */ + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_OSCILLATOR filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_OSCILLATOR + { + TYPE, /* Waveform type. 0 = sine. 1 = square. 2 = sawup. 3 = sawdown. 4 = triangle. 5 = noise. */ + RATE /* Frequency of the sinewave in hz. 1.0 to 22000.0. Default = 220.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_LOWPASS + { + CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0. */ + RESONANCE /* Lowpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITLOWPASS filter. + This is different to the default FMOD_DSP_TYPE_ITLOWPASS filter in that it uses a different quality algorithm and is + the filter used to produce the correct sounding playback in .IT files.
    + FMOD Ex's .IT playback uses this filter.
    + + [REMARKS] + Note! This filter actually has a limited cutoff frequency below the specified maximum, due to its limited design, + so for a more open range filter use FMOD_DSP_LOWPASS or if you don't mind not having resonance, + FMOD_DSP_LOWPASS_SIMPLE.
    + The effective maximum cutoff is about 8060hz. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_ITLOWPASS + { + CUTOFF, /* Lowpass cutoff frequency in hz. 1.0 to 22000.0. Default = 5000.0/ */ + RESONANCE /* Lowpass resonance Q value. 0.0 to 127.0. Default = 1.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_HIGHPASS filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_HIGHPASS + { + CUTOFF, /* Highpass cutoff frequency in hz. 10.0 to output 22000.0. Default = 5000.0. */ + RESONANCE /* Highpass resonance Q value. 1.0 to 10.0. Default = 1.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ECHO filter. + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
    + Larger echo delays result in larger amounts of memory allocated.
    +
    + 'maxchannels' also dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the echo unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel echo, etc.
    + If the echo effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
    + When the echo is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
    + If a channel echo is set to a lower number than the sound's channel count that is coming in, it will not echo the sound.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_ECHO + { + DELAY, /* Echo delay in ms. 10 to 5000. Default = 500. */ + DECAYRATIO, /* Echo decay per delay. 0 to 1. 1.0 = No decay, 0.0 = total decay. Default = 0.5. */ + MAXCHANNELS, /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ + DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 1.0. */ + WETMIX /* Volume of echo signal to pass to output. 0.0 to 1.0. Default = 1.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DELAY filter. + + [REMARKS] + Note. Every time MaxDelay is changed, the plugin re-allocates the delay buffer. This means the delay will dissapear at that time while it refills its new buffer.
    + A larger MaxDelay results in larger amounts of memory allocated.
    + Channel delays above MaxDelay will be clipped to MaxDelay and the delay buffer will not be resized.
    +
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_DELAY + { + CH0, /* Channel #0 Delay in ms. 0 to 10000. Default = 0. */ + CH1, /* Channel #1 Delay in ms. 0 to 10000. Default = 0. */ + CH2, /* Channel #2 Delay in ms. 0 to 10000. Default = 0. */ + CH3, /* Channel #3 Delay in ms. 0 to 10000. Default = 0. */ + CH4, /* Channel #4 Delay in ms. 0 to 10000. Default = 0. */ + CH5, /* Channel #5 Delay in ms. 0 to 10000. Default = 0. */ + CH6, /* Channel #6 Delay in ms. 0 to 10000. Default = 0. */ + CH7, /* Channel #7 Delay in ms. 0 to 10000. Default = 0. */ + CH8, /* Channel #8 Delay in ms. 0 to 10000. Default = 0. */ + CH9, /* Channel #9 Delay in ms. 0 to 10000. Default = 0. */ + CH10, /* Channel #10 Delay in ms. 0 to 10000. Default = 0. */ + CH11, /* Channel #11 Delay in ms. 0 to 10000. Default = 0. */ + CH12, /* Channel #12 Delay in ms. 0 to 10000. Default = 0. */ + CH13, /* Channel #13 Delay in ms. 0 to 10000. Default = 0. */ + CH14, /* Channel #14 Delay in ms. 0 to 10000. Default = 0. */ + CH15, /* Channel #15 Delay in ms. 0 to 10000. Default = 0. */ + MAXDELAY, /* Maximum delay in ms. 0 to 1000. Default = 10. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_FLANGE filter. + + [REMARKS] + Flange is an effect where the signal is played twice at the same time, and one copy slides back and forth creating a whooshing or flanging effect.
    + As there are 2 copies of the same signal, by default each signal is given 50% mix, so that the total is not louder than the original unaffected signal.
    +
    + Flange depth is a percentage of a 10ms shift from the original signal. Anything above 10ms is not considered flange because to the ear it begins to 'echo' so 10ms is the highest value possible.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_FLANGE + { + DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.45. */ + WETMIX, /* Volume of flange signal to pass to output. 0.0 to 1.0. Default = 0.55. */ + DEPTH, /* Flange depth. 0.01 to 1.0. Default = 1.0. */ + RATE /* Flange speed in hz. 0.0 to 20.0. Default = 0.1. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_TREMOLO filter. + + [REMARKS] + The tremolo effect varies the amplitude of a sound. Depending on the settings, this unit can produce a tremolo, chopper or auto-pan effect.
    +
    + The shape of the LFO (low freq. oscillator) can morphed between sine, triangle and sawtooth waves using the FMOD_DSP_TREMOLO_SHAPE and FMOD_DSP_TREMOLO_SKEW parameters.
    + FMOD_DSP_TREMOLO_DUTY and FMOD_DSP_TREMOLO_SQUARE are useful for a chopper-type effect where the first controls the on-time duration and second controls the flatness of the envelope.
    + FMOD_DSP_TREMOLO_SPREAD varies the LFO phase between channels to get an auto-pan effect. This works best with a sine shape LFO.
    + The LFO can be synchronized using the FMOD_DSP_TREMOLO_PHASE parameter which sets its instantaneous phase.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_TREMOLO + { + FREQUENCY, /* LFO frequency in Hz. 0.1 to 20. Default = 4. */ + DEPTH, /* Tremolo depth. 0 to 1. Default = 0. */ + SHAPE, /* LFO shape morph between triangle and sine. 0 to 1. Default = 0. */ + SKEW, /* Time-skewing of LFO cycle. -1 to 1. Default = 0. */ + DUTY, /* LFO on-time. 0 to 1. Default = 0.5. */ + SQUARE, /* Flatness of the LFO shape. 0 to 1. Default = 0. */ + PHASE, /* Instantaneous LFO phase. 0 to 1. Default = 0. */ + SPREAD /* Rotation / auto-pan effect. -1 to 1. Default = 0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_DISTORTION filter. + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_DISTORTION + { + LEVEL /* Distortion value. 0.0 to 1.0. Default = 0.5. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_NORMALIZE filter. + + [REMARKS] + Normalize amplifies the sound based on the maximum peaks within the signal.
    + For example if the maximum peaks in the signal were 50% of the bandwidth, it would scale the whole sound by 2.
    + The lower threshold value makes the normalizer ignores peaks below a certain point, to avoid over-amplification if a loud signal suddenly came in, and also to avoid amplifying to maximum things like background hiss.
    +
    + Because FMOD is a realtime audio processor, it doesn't have the luxury of knowing the peak for the whole sound (ie it can't see into the future), so it has to process data as it comes in.
    + To avoid very sudden changes in volume level based on small samples of new data, fmod fades towards the desired amplification which makes for smooth gain control. The fadetime parameter can control this.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_NORMALIZE + { + FADETIME, /* Time to ramp the silence to full in ms. 0.0 to 20000.0. Default = 5000.0. */ + THRESHHOLD, /* Lower volume range threshold to ignore. 0.0 to 1.0. Default = 0.1. Raise higher to stop amplification of very quiet signals. */ + MAXAMP /* Maximum amplification allowed. 1.0 to 100000.0. Default = 20.0. 1.0 = no amplifaction, higher values allow more boost. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PARAMEQ filter. + + [REMARKS] + Parametric EQ is a bandpass filter that attenuates or amplifies a selected frequency and its neighbouring frequencies.
    +
    + To create a multi-band EQ create multiple FMOD_DSP_TYPE_PARAMEQ units and set each unit to different frequencies, for example 1000hz, 2000hz, 4000hz, 8000hz, 16000hz with a range of 1 octave each.
    +
    + When a frequency has its gain set to 1.0, the sound will be unaffected and represents the original signal exactly.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_PARAMEQ + { + CENTER, /* Frequency center. 20.0 to 22000.0. Default = 8000.0. */ + BANDWIDTH, /* Octave range around the center frequency to filter. 0.2 to 5.0. Default = 1.0. */ + GAIN /* Frequency Gain. 0.05 to 3.0. Default = 1.0. */ + } + + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_PITCHSHIFT filter. + + [REMARKS] + This pitch shifting unit can be used to change the pitch of a sound without speeding it up or slowing it down.
    + It can also be used for time stretching or scaling, for example if the pitch was doubled, and the frequency of the sound was halved, the pitch of the sound would sound correct but it would be twice as slow.
    +
    + Warning! This filter is very computationally expensive! Similar to a vocoder, it requires several overlapping FFT and IFFT's to produce smooth output, and can require around 440mhz for 1 stereo 48khz signal using the default settings.
    + Reducing the signal to mono will half the cpu usage, as will the overlap count.
    + Reducing this will lower audio quality, but what settings to use are largely dependant on the sound being played. A noisy polyphonic signal will need higher overlap and fft size compared to a speaking voice for example.
    +
    + This pitch shifter is based on the pitch shifter code at http://www.dspdimension.com, written by Stephan M. Bernsee.
    + The original code is COPYRIGHT 1999-2003 Stephan M. Bernsee .
    +
    + 'maxchannels' dictates the amount of memory allocated. By default, the maxchannels value is 0. If FMOD is set to stereo, the pitch shift unit will allocate enough memory for 2 channels. If it is 5.1, it will allocate enough memory for a 6 channel pitch shift, etc.
    + If the pitch shift effect is only ever applied to the global mix (ie it was added with System::addDSP), then 0 is the value to set as it will be enough to handle all speaker modes.
    + When the pitch shift is added to a channel (ie Channel::addDSP) then the channel count that comes in could be anything from 1 to 8 possibly. It is only in this case where you might want to increase the channel count above the output's channel count.
    + If a channel pitch shift is set to a lower number than the sound's channel count that is coming in, it will not pitch shift the sound.
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_PITCHSHIFT + { + PITCH, /* Pitch value. 0.5 to 2.0. Default = 1.0. 0.5 = one octave down, 2.0 = one octave up. 1.0 does not change the pitch. */ + FFTSIZE, /* FFT window size. 256, 512, 1024, 2048, 4096. Default = 1024. Increase this to reduce 'smearing'. This effect is a warbling sound similar to when an mp3 is encoded at very low bitrates. */ + OVERLAP, /* Window overlap. 1 to 32. Default = 4. Increase this to reduce 'tremolo' effect. Increasing it by a factor of 2 doubles the CPU usage. */ + MAXCHANNELS /* Maximum channels supported. 0 to 16. 0 = same as fmod's default output polyphony, 1 = mono, 2 = stereo etc. See remarks for more. Default = 0. It is suggested to leave at 0! */ + } + + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_CHORUS filter. + + [REMARKS] + Chrous is an effect where the sound is more 'spacious' due to 1 to 3 versions of the sound being played along side the original signal but with the pitch of each copy modulating on a sine wave.
    + This is a highly configurable chorus unit. It supports 3 taps, small and large delay times and also feedback.
    + This unit also could be used to do a simple echo, or a flange effect. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_CHORUS + { + DRYMIX, /* Volume of original signal to pass to output. 0.0 to 1.0. Default = 0.5. */ + WETMIX1, /* Volume of 1st chorus tap. 0.0 to 1.0. Default = 0.5. */ + WETMIX2, /* Volume of 2nd chorus tap. This tap is 90 degrees out of phase of the first tap. 0.0 to 1.0. Default = 0.5. */ + WETMIX3, /* Volume of 3rd chorus tap. This tap is 90 degrees out of phase of the second tap. 0.0 to 1.0. Default = 0.5. */ + DELAY, /* Chorus delay in ms. 0.1 to 100.0. Default = 40.0 ms. */ + RATE, /* Chorus modulation rate in hz. 0.0 to 20.0. Default = 0.8 hz. */ + DEPTH, /* Chorus modulation depth. 0.0 to 1.0. Default = 0.03. */ + FEEDBACK /* Chorus feedback. Controls how much of the wet signal gets fed back into the chorus buffer. 0.0 to 1.0. Default = 0.0. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_ITECHO filter.
    + This is effectively a software based echo filter that emulates the DirectX DMO echo effect. Impulse tracker files can support this, and FMOD will produce the effect on ANY platform, not just those that support DirectX effects!
    + + [REMARKS] + Note. Every time the delay is changed, the plugin re-allocates the echo buffer. This means the echo will dissapear at that time while it refills its new buffer.
    + Larger echo delays result in larger amounts of memory allocated.
    +
    + For stereo signals only! This will not work on mono or multichannel signals. This is fine for .IT format purposes, and also if you use System::addDSP with a standard stereo output.
    + + [PLATFORMS] + Win32, Win64, Linux, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + System::addDSP + ] + */ + public enum DSP_ITECHO + { + WETDRYMIX, /* Ratio of wet (processed) signal to dry (unprocessed) signal. Must be in the range from 0.0 through 100.0 (all wet). The default value is 50. */ + FEEDBACK, /* Percentage of output fed back into input, in the range from 0.0 through 100.0. The default value is 50. */ + LEFTDELAY, /* Delay for left channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + RIGHTDELAY, /* Delay for right channel, in milliseconds, in the range from 1.0 through 2000.0. The default value is 500 ms. */ + PANDELAY /* Value that specifies whether to swap left and right delays with each successive echo. The default value is zero, meaning no swap. Possible values are defined as 0.0 (equivalent to FALSE) and 1.0 (equivalent to TRUE). */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_COMPRESSOR unit.
    + This is a simple linked multichannel software limiter that is uniform across the whole spectrum.
    + + [REMARKS] + The parameters are as follows: + Threshold: [-60dB to 0dB, default 0dB] + Attack Time: [10ms to 200ms, default 50ms] + Release Time: [20ms to 1000ms, default 50ms] + Gain Make Up: [0dB to +30dB, default 0dB] +
    + The limiter is not guaranteed to catch every peak above the threshold level, + because it cannot apply gain reduction instantaneously - the time delay is + determined by the attack time. However setting the attack time too short will + distort the sound, so it is a compromise. High level peaks can be avoided by + using a short attack time - but not too short, and setting the threshold a few + decibels below the critical level. +
    + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP + ] + */ + public enum DSP_COMPRESSOR + { + THRESHOLD, /* Threshold level (dB)in the range from -60 through 0. The default value is 50. */ + ATTACK, /* Gain reduction attack time (milliseconds), in the range from 10 through 200. The default value is 50. */ + RELEASE, /* Gain reduction release time (milliseconds), in the range from 20 through 1000. The default value is 50. */ + GAINMAKEUP /* Make-up gain applied after limiting, in the range from 0.0 through 100.0. The default value is 50. */ + } + + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_SFXREVERB unit.
    + + [REMARKS] + This is a high quality I3DL2 based reverb which improves greatly on FMOD_DSP_REVERB.
    + On top of the I3DL2 property set, "Dry Level" is also included to allow the dry mix to be changed.
    +
    + Currently FMOD_DSP_SFXREVERB_REFLECTIONSLEVEL, FMOD_DSP_SFXREVERB_REFLECTIONSDELAY and FMOD_DSP_SFXREVERB_REVERBDELAY are not enabled but will come in future versions.
    +
    + These properties can be set with presets in FMOD_REVERB_PRESETS. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + DSP::SetParameter + DSP::GetParameter + FMOD_DSP_TYPE + System::addDSP + FMOD_REVERB_PRESETS + ] + */ + public enum DSP_SFXREVERB + { + DRYLEVEL, /* Dry Level : Mix level of dry signal in output in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + ROOM, /* Room : Room effect level at low frequencies in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + ROOMHF, /* Room HF : Room effect high-frequency level re. low frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + ROOMROLLOFFFACTOR, /* Room Rolloff : Like DS3D flRolloffFactor but for room effect. Ranges from 0.0 to 10.0. Default is 10.0 */ + DECAYTIME, /* Decay Time : Reverberation decay time at low-frequencies in seconds. Ranges from 0.1 to 20.0. Default is 1.0. */ + DECAYHFRATIO, /* Decay HF Ratio : High-frequency to low-frequency decay time ratio. Ranges from 0.1 to 2.0. Default is 0.5. */ + REFLECTIONSLEVEL, /* Reflections : Early reflections level relative to room effect in mB. Ranges from -10000.0 to 1000.0. Default is -10000.0. */ + REFLECTIONSDELAY, /* Reflect Delay : Delay time of first reflection in seconds. Ranges from 0.0 to 0.3. Default is 0.02. */ + REVERBLEVEL, /* Reverb : Late reverberation level relative to room effect in mB. Ranges from -10000.0 to 2000.0. Default is 0.0. */ + REVERBDELAY, /* Reverb Delay : Late reverberation delay time relative to first reflection in seconds. Ranges from 0.0 to 0.1. Default is 0.04. */ + DIFFUSION, /* Diffusion : Reverberation diffusion (echo density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + DENSITY, /* Density : Reverberation density (modal density) in percent. Ranges from 0.0 to 100.0. Default is 100.0. */ + HFREFERENCE, /* HF Reference : Reference high frequency in Hz. Ranges from 20.0 to 20000.0. Default is 5000.0. */ + ROOMLF, /* Room LF : Room effect low-frequency level in mB. Ranges from -10000.0 to 0.0. Default is 0.0. */ + LFREFERENCE /* LF Reference : Reference low-frequency in Hz. Ranges from 20.0 to 1000.0. Default is 250.0. */ + } + + /* + [ENUM] + [ + [DESCRIPTION] + Parameter types for the FMOD_DSP_TYPE_LOWPASS_SIMPLE filter.
    + This is a very simple low pass filter, based on two single-pole RC time-constant modules. + The emphasis is on speed rather than accuracy, so this should not be used for task requiring critical filtering.
    + + [REMARKS] + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii + + [SEE_ALSO] + DSP::setParameter + DSP::getParameter + FMOD_DSP_TYPE + ] + */ + public enum DSP_LOWPASS_SIMPLE + { + CUTOFF /* Lowpass cutoff frequency in hz. 10.0 to 22000.0. Default = 5000.0 */ + } +/*$ preserve start $*/ +} +/*$ preserve end $*/ diff --git a/Unity Studio/FMOD/fmod_errors.cs b/Unity Studio/FMOD/fmod_errors.cs new file mode 100644 index 0000000..efb0ead --- /dev/null +++ b/Unity Studio/FMOD/fmod_errors.cs @@ -0,0 +1,120 @@ +/* ============================================================================================= = */ +/* FMOD Ex - Error string header file. Copyright (c), Firelight Technologies Pty, Ltd. 2004-2014. */ +/* */ +/* Use this header if you want to store or display a string version / english explanation of */ +/* the FMOD error codes. */ +/* */ +/* =============================================================================================== */ + +namespace FMOD +{ + public class Error + { + public static string String(FMOD.RESULT errcode) + { + switch (errcode) + { + case FMOD.RESULT.OK: return "No errors."; + case FMOD.RESULT.ERR_ALREADYLOCKED: return "Tried to call lock a second time before unlock was called. "; + case FMOD.RESULT.ERR_BADCOMMAND: return "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound). "; + case FMOD.RESULT.ERR_CDDA_DRIVERS: return "Neither NTSCSI nor ASPI could be initialised. "; + case FMOD.RESULT.ERR_CDDA_INIT: return "An error occurred while initialising the CDDA subsystem. "; + case FMOD.RESULT.ERR_CDDA_INVALID_DEVICE: return "Couldn't find the specified device. "; + case FMOD.RESULT.ERR_CDDA_NOAUDIO: return "No audio tracks on the specified disc. "; + case FMOD.RESULT.ERR_CDDA_NODEVICES: return "No CD/DVD devices were found. "; + case FMOD.RESULT.ERR_CDDA_NODISC: return "No disc present in the specified drive. "; + case FMOD.RESULT.ERR_CDDA_READ: return "A CDDA read error occurred. "; + case FMOD.RESULT.ERR_CHANNEL_ALLOC: return "Error trying to allocate a channel. "; + case FMOD.RESULT.ERR_CHANNEL_STOLEN: return "The specified channel has been reused to play another sound. "; + case FMOD.RESULT.ERR_COM: return "A Win32 COM related error occured. COM failed to initialize or a QueryInterface failed meaning a Windows codec or driver was not installed properly. "; + case FMOD.RESULT.ERR_DMA: return "DMA Failure. See debug output for more information. "; + case FMOD.RESULT.ERR_DSP_CONNECTION: return "DSP connection error. Connection possibly caused a cyclic dependancy. "; + case FMOD.RESULT.ERR_DSP_FORMAT: return "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format. "; + case FMOD.RESULT.ERR_DSP_NOTFOUND: return "DSP connection error. Couldn't find the DSP unit specified. "; + case FMOD.RESULT.ERR_DSP_RUNNING: return "DSP error. Cannot perform this operation while the network is in the middle of running. This will most likely happen if a connection or disconnection is attempted in a DSP callback. "; + case FMOD.RESULT.ERR_DSP_TOOMANYCONNECTIONS: return "DSP connection error. The unit being connected to or disconnected should only have 1 input or output. "; + case FMOD.RESULT.ERR_FILE_BAD: return "Error loading file. "; + case FMOD.RESULT.ERR_FILE_COULDNOTSEEK: return "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format. "; + case FMOD.RESULT.ERR_FILE_DISKEJECTED: return "Media was ejected while reading. "; + case FMOD.RESULT.ERR_FILE_EOF: return "End of file unexpectedly reached while trying to read essential data (truncated data?). "; + case FMOD.RESULT.ERR_FILE_NOTFOUND: return "File not found. "; + case FMOD.RESULT.ERR_FILE_UNWANTED: return "Unwanted file access occured. "; + case FMOD.RESULT.ERR_FORMAT: return "Unsupported file or audio format. "; + case FMOD.RESULT.ERR_HTTP: return "A HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere. "; + case FMOD.RESULT.ERR_HTTP_ACCESS: return "The specified resource requires authentication or is forbidden. "; + case FMOD.RESULT.ERR_HTTP_PROXY_AUTH: return "Proxy authentication is required to access the specified resource. "; + case FMOD.RESULT.ERR_HTTP_SERVER_ERROR: return "A HTTP server error occurred. "; + case FMOD.RESULT.ERR_HTTP_TIMEOUT: return "The HTTP request timed out. "; + case FMOD.RESULT.ERR_INITIALIZATION: return "FMOD was not initialized correctly to support this function. "; + case FMOD.RESULT.ERR_INITIALIZED: return "Cannot call this command after System::init. "; + case FMOD.RESULT.ERR_INTERNAL: return "An error occured that wasn't supposed to. Contact support. "; + case FMOD.RESULT.ERR_INVALID_ADDRESS: return "On Xbox 360, this memory address passed to FMOD must be physical, (ie allocated with XPhysicalAlloc.) "; + case FMOD.RESULT.ERR_INVALID_FLOAT: return "Value passed in was a NaN, Inf or denormalized float. "; + case FMOD.RESULT.ERR_INVALID_HANDLE: return "An invalid object handle was used. "; + case FMOD.RESULT.ERR_INVALID_PARAM: return "An invalid parameter was passed to this function. "; + case FMOD.RESULT.ERR_INVALID_POSITION: return "An invalid seek position was passed to this function. "; + case FMOD.RESULT.ERR_INVALID_SPEAKER: return "An invalid speaker was passed to this function based on the current speaker mode. "; + case FMOD.RESULT.ERR_INVALID_SYNCPOINT: return "The syncpoint did not come from this sound handle."; + case FMOD.RESULT.ERR_INVALID_VECTOR: return "The vectors passed in are not unit length, or perpendicular. "; + case FMOD.RESULT.ERR_MAXAUDIBLE: return "Reached maximum audible playback count for this sound's soundgroup. "; + case FMOD.RESULT.ERR_MEMORY: return "Not enough memory or resources. "; + case FMOD.RESULT.ERR_MEMORY_CANTPOINT: return "Can't use FMOD_OPENMEMORY_POINT on non PCM source data, or non mp3/xma/adpcm data if FMOD_CREATECOMPRESSEDSAMPLE was used. "; + case FMOD.RESULT.ERR_MEMORY_SRAM: return "Not enough memory or resources on console sound ram. "; + case FMOD.RESULT.ERR_NEEDS2D: return "Tried to call a command on a 3d sound when the command was meant for 2d sound. "; + case FMOD.RESULT.ERR_NEEDS3D: return "Tried to call a command on a 2d sound when the command was meant for 3d sound. "; + case FMOD.RESULT.ERR_NEEDSHARDWARE: return "Tried to use a feature that requires hardware support. (ie trying to play a VAG compressed sound in software on PS2). "; + case FMOD.RESULT.ERR_NEEDSSOFTWARE: return "Tried to use a feature that requires the software engine. Software engine has either been turned off, or command was executed on a hardware channel which does not support this feature. "; + case FMOD.RESULT.ERR_NET_CONNECT: return "Couldn't connect to the specified host. "; + case FMOD.RESULT.ERR_NET_SOCKET_ERROR: return "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere. "; + case FMOD.RESULT.ERR_NET_URL: return "The specified URL couldn't be resolved. "; + case FMOD.RESULT.ERR_NET_WOULD_BLOCK: return "Operation on a non-blocking socket could not complete immediately. "; + case FMOD.RESULT.ERR_NOTREADY: return "Operation could not be performed because specified sound is not ready. "; + case FMOD.RESULT.ERR_OUTPUT_ALLOCATED: return "Error initializing output device, but more specifically, the output device is already in use and cannot be reused. "; + case FMOD.RESULT.ERR_OUTPUT_CREATEBUFFER: return "Error creating hardware sound buffer. "; + case FMOD.RESULT.ERR_OUTPUT_DRIVERCALL: return "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted. "; + case FMOD.RESULT.ERR_OUTPUT_ENUMERATION: return "Error enumerating the available driver list. List may be inconsistent due to a recent device addition or removal."; + case FMOD.RESULT.ERR_OUTPUT_FORMAT: return "Soundcard does not support the minimum features needed for this soundsystem (16bit stereo output). "; + case FMOD.RESULT.ERR_OUTPUT_INIT: return "Error initializing output device. "; + case FMOD.RESULT.ERR_OUTPUT_NOHARDWARE: return "FMOD_HARDWARE was specified but the sound card does not have the resources nescessary to play it. "; + case FMOD.RESULT.ERR_OUTPUT_NOSOFTWARE: return "Attempted to create a software sound but no software channels were specified in System::init. "; + case FMOD.RESULT.ERR_PAN: return "Panning only works with mono or stereo sound sources. "; + case FMOD.RESULT.ERR_PLUGIN: return "An unspecified error has been returned from a 3rd party plugin. "; + case FMOD.RESULT.ERR_PLUGIN_INSTANCES: return "The number of allowed instances of a plugin has been exceeded "; + case FMOD.RESULT.ERR_PLUGIN_MISSING: return "A requested output, dsp unit type or codec was not available. "; + case FMOD.RESULT.ERR_PLUGIN_RESOURCE: return "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback) "; + case FMOD.RESULT.ERR_PRELOADED: return "The specified sound is still in use by the event system, call EventSystem::unloadFSB before trying to release it. "; + case FMOD.RESULT.ERR_PROGRAMMERSOUND: return "The specified sound is still in use by the event system, wait for the event which is using it finish with it. "; + case FMOD.RESULT.ERR_RECORD: return "An error occured trying to initialize the recording device. "; + case FMOD.RESULT.ERR_REVERB_INSTANCE: return "Specified Instance in FMOD_REVERB_PROPERTIES couldn't be set. Most likely because another application has locked the EAX4 FX slot. "; + case FMOD.RESULT.ERR_SUBSOUND_ALLOCATED: return "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first. "; + case FMOD.RESULT.ERR_SUBSOUND_CANTMOVE: return "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file."; + case FMOD.RESULT.ERR_SUBSOUND_MODE: return "The subsound's mode bits do not match with the parent sound's mode bits. See documentation for function that it was called with."; + case FMOD.RESULT.ERR_SUBSOUNDS: return "The error occured because the sound referenced contains subsounds. (ie you cannot play the parent sound as a static sample, only its subsounds.) "; + case FMOD.RESULT.ERR_TAGNOTFOUND: return "The specified tag could not be found or there are no tags. "; + case FMOD.RESULT.ERR_TOOMANYCHANNELS: return "The sound created exceeds the allowable input channel count. This can be increased using the maxinputchannels parameter in System::setSoftwareFormat. "; + case FMOD.RESULT.ERR_UNIMPLEMENTED: return "Something in FMOD hasn't been implemented when it should be! contact support! "; + case FMOD.RESULT.ERR_UNINITIALIZED: return "This command failed because System::init or System::setDriver was not called. "; + case FMOD.RESULT.ERR_UNSUPPORTED: return "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified. "; + case FMOD.RESULT.ERR_UPDATE: return "An error caused by System::update occured. "; + case FMOD.RESULT.ERR_VERSION: return "The version number of this file format is not supported. "; + + case FMOD.RESULT.ERR_EVENT_FAILED: return "An Event failed to be retrieved, most likely due to 'just fail' being specified as the max playbacks behavior. "; + case FMOD.RESULT.ERR_EVENT_GUIDCONFLICT: return "An event with the same GUID already exists. "; + case FMOD.RESULT.ERR_EVENT_INFOONLY: return "Can't execute this command on an EVENT_INFOONLY event. "; + case FMOD.RESULT.ERR_EVENT_INTERNAL: return "An error occured that wasn't supposed to. See debug log for reason. "; + case FMOD.RESULT.ERR_EVENT_MAXSTREAMS: return "Event failed because 'Max streams' was hit when FMOD_INIT_FAIL_ON_MAXSTREAMS was specified. "; + case FMOD.RESULT.ERR_EVENT_MISMATCH: return "FSB mis-matches the FEV it was compiled with. "; + case FMOD.RESULT.ERR_EVENT_NAMECONFLICT: return "A category with the same name already exists. "; + case FMOD.RESULT.ERR_EVENT_NEEDSSIMPLE: return "Tried to call a function on a complex event that's only supported by simple events. "; + case FMOD.RESULT.ERR_EVENT_NOTFOUND: return "The requested event, event group, event category or event property could not be found. "; + case FMOD.RESULT.ERR_EVENT_ALREADY_LOADED: return "The specified project has already been loaded. Having multiple copies of the same project loaded simultaneously is forbidden. "; + + case FMOD.RESULT.ERR_MUSIC_NOCALLBACK: return "The music callback is required, but it has not been set. "; + case FMOD.RESULT.ERR_MUSIC_UNINITIALIZED: return "Music system is not initialized probably because no music data is loaded. "; + case FMOD.RESULT.ERR_MUSIC_NOTFOUND: return "The requested music entity could not be found."; + + default : return "Unknown error."; + } + } + } +} diff --git a/Unity Studio/FMOD/fmod_memoryinfo.cs b/Unity Studio/FMOD/fmod_memoryinfo.cs new file mode 100644 index 0000000..1413bde --- /dev/null +++ b/Unity Studio/FMOD/fmod_memoryinfo.cs @@ -0,0 +1,199 @@ +/* ============================================================================================= */ +/* FMOD Ex - Memory info header file. Copyright (c), Firelight Technologies Pty, Ltd. 2009-2014. */ +/* */ +/* Use this header if you are interested in getting detailed information on FMOD's memory */ +/* usage. See the documentation for more details. */ +/* */ +/* ============================================================================================= */ + +using System.Runtime.InteropServices; + +namespace FMOD +{ + /* + [STRUCTURE] + [ + [DESCRIPTION] + Structure to be filled with detailed memory usage information of an FMOD object + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + On return from getMemoryInfo, each member of this structure will hold the amount of memory used for its type in bytes.
    +
    + Members marked with [in] mean the user sets the value before passing it to the function.
    + Members marked with [out] mean FMOD sets the value to be used after the function exits.
    + + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3 + + [SEE_ALSO] + System::getMemoryInfo + EventSystem::getMemoryInfo + FMOD_MEMBITS + FMOD_EVENT_MEMBITS + ] + */ + [StructLayout(LayoutKind.Sequential)] + public struct MEMORY_USAGE_DETAILS + { + public uint other; /* [out] Memory not accounted for by other types */ + public uint stringdata; /* [out] String data */ + public uint system; /* [out] System object and various internals */ + public uint plugins; /* [out] Plugin objects and internals */ + public uint output; /* [out] Output module object and internals */ + public uint channel; /* [out] Channel related memory */ + public uint channelgroup; /* [out] ChannelGroup objects and internals */ + public uint codec; /* [out] Codecs allocated for streaming */ + public uint file; /* [out] File buffers and structures */ + public uint sound; /* [out] Sound objects and internals */ + public uint secondaryram; /* [out] Sound data stored in secondary RAM */ + public uint soundgroup; /* [out] SoundGroup objects and internals */ + public uint streambuffer; /* [out] Stream buffer memory */ + public uint dspconnection; /* [out] DSPConnection objects and internals */ + public uint dsp; /* [out] DSP implementation objects */ + public uint dspcodec; /* [out] Realtime file format decoding DSP objects */ + public uint profile; /* [out] Profiler memory footprint. */ + public uint recordbuffer; /* [out] Buffer used to store recorded data from microphone */ + public uint reverb; /* [out] Reverb implementation objects */ + public uint reverbchannelprops; /* [out] Reverb channel properties structs */ + public uint geometry; /* [out] Geometry objects and internals */ + public uint syncpoint; /* [out] Sync point memory. */ + public uint eventsystem; /* [out] EventSystem and various internals */ + public uint musicsystem; /* [out] MusicSystem and various internals */ + public uint fev; /* [out] Definition of objects contained in all loaded projects e.g. events, groups, categories */ + public uint memoryfsb; /* [out] Data loaded with registerMemoryFSB */ + public uint eventproject; /* [out] EventProject objects and internals */ + public uint eventgroupi; /* [out] EventGroup objects and internals */ + public uint soundbankclass; /* [out] Objects used to manage wave banks */ + public uint soundbanklist; /* [out] Data used to manage lists of wave bank usage */ + public uint streaminstance; /* [out] Stream objects and internals */ + public uint sounddefclass; /* [out] Sound definition objects */ + public uint sounddefdefclass; /* [out] Sound definition static data objects */ + public uint sounddefpool; /* [out] Sound definition pool data */ + public uint reverbdef; /* [out] Reverb definition objects */ + public uint eventreverb; /* [out] Reverb objects */ + public uint userproperty; /* [out] User property objects */ + public uint eventinstance; /* [out] Event instance base objects */ + public uint eventinstance_complex; /* [out] Complex event instance objects */ + public uint eventinstance_simple; /* [out] Simple event instance objects */ + public uint eventinstance_layer; /* [out] Event layer instance objects */ + public uint eventinstance_sound; /* [out] Event sound instance objects */ + public uint eventenvelope; /* [out] Event envelope objects */ + public uint eventenvelopedef; /* [out] Event envelope definition objects */ + public uint eventparameter; /* [out] Event parameter objects */ + public uint eventcategory; /* [out] Event category objects */ + public uint eventenvelopepoint; /* [out] Event envelope point objects */ + public uint eventinstancepool; /* [out] Event instance pool memory */ + } + + + /* + [DEFINE] + [ + [NAME] + FMOD_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Ex class.
    + Use with the "memorybits" parameter of getMemoryInfo to get information on FMOD Ex memory usage. + + [REMARKS] + Every public FMOD class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See System::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii, Solaris + + [SEE_ALSO] + FMOD_EVENT_MEMBITS + EventSystem::getMemoryInfo + ] + */ + public enum MEMBITS :uint + { + OTHER = 0x00000001, /* Memory not accounted for by other types */ + STRING = 0x00000002, /* String data */ + + SYSTEM = 0x00000004, /* System object and various internals */ + PLUGINS = 0x00000008, /* Plugin objects and internals */ + OUTPUT = 0x00000010, /* Output module object and internals */ + CHANNEL = 0x00000020, /* Channel related memory */ + CHANNELGROUP = 0x00000040, /* ChannelGroup objects and internals */ + CODEC = 0x00000080, /* Codecs allocated for streaming */ + FILE = 0x00000100, /* Codecs allocated for streaming */ + SOUND = 0x00000200, /* Sound objects and internals */ + SOUND_SECONDARYRAM = 0x00000400, /* Sound data stored in secondary RAM */ + SOUNDGROUP = 0x00000800, /* SoundGroup objects and internals */ + STREAMBUFFER = 0x00001000, /* Stream buffer memory */ + DSPCONNECTION = 0x00002000, /* DSPConnection objects and internals */ + DSP = 0x00004000, /* DSP implementation objects */ + DSPCODEC = 0x00008000, /* Realtime file format decoding DSP objects */ + PROFILE = 0x00010000, /* Profiler memory footprint. */ + RECORDBUFFER = 0x00020000, /* Buffer used to store recorded data from microphone */ + REVERB = 0x00040000, /* Reverb implementation objects */ + REVERBCHANNELPROPS = 0x00080000, /* Reverb channel properties structs */ + GEOMETRY = 0x00100000, /* Geometry objects and internals */ + SYNCPOINT = 0x00200000, /* Sync point memory. */ + ALL = 0xffffffff /* All memory used by FMOD Ex */ + } + + /* + [DEFINE] + [ + [NAME] + FMOD_EVENT_MEMBITS + + [DESCRIPTION] + Bitfield used to request specific memory usage information from the getMemoryInfo function of every public FMOD Event System class.
    + Use with the "event_memorybits" parameter of getMemoryInfo to get information on FMOD Event System memory usage. + + [REMARKS] + Every public FMOD Event System class has a getMemoryInfo function which can be used to get detailed information on what memory resources are associated with the object in question. + The FMOD_EVENT_MEMBITS defines can be OR'd together to specify precisely what memory usage you'd like to get information on. See EventSystem::getMemoryInfo for an example. + + [PLATFORMS] + Win32, Win64, Linux, Linux64, Macintosh, Xbox, Xbox360, PlayStation 2, GameCube, PlayStation Portable, PlayStation 3, Wii, Solaris + + [SEE_ALSO] + FMOD_MEMBITS + System::getMemoryInfo + ] + */ + public enum EVENT_MEMBITS :uint + { + EVENTSYSTEM = 0x00000001, /* EventSystem and various internals */ + MUSICSYSTEM = 0x00000002, /* MusicSystem and various internals */ + FEV = 0x00000004, /* Definition of objects contained in all loaded projects e.g. events, groups, categories */ + MEMORYFSB = 0x00000008, /* Data loaded with registerMemoryFSB */ + EVENTPROJECT = 0x00000010, /* EventProject objects and internals */ + EVENTGROUPI = 0x00000020, /* EventGroup objects and internals */ + SOUNDBANKCLASS = 0x00000040, /* Objects used to manage wave banks */ + SOUNDBANKLIST = 0x00000080, /* Data used to manage lists of wave bank usage */ + STREAMINSTANCE = 0x00000100, /* Stream objects and internals */ + SOUNDDEFCLASS = 0x00000200, /* Sound definition objects */ + SOUNDDEFDEFCLASS = 0x00000400, /* Sound definition static data objects */ + SOUNDDEFPOOL = 0x00000800, /* Sound definition pool data */ + REVERBDEF = 0x00001000, /* Reverb definition objects */ + EVENTREVERB = 0x00002000, /* Reverb objects */ + USERPROPERTY = 0x00004000, /* User property objects */ + EVENTINSTANCE = 0x00008000, /* Event instance base objects */ + EVENTINSTANCE_COMPLEX = 0x00010000, /* Complex event instance objects */ + EVENTINSTANCE_SIMPLE = 0x00020000, /* Simple event instance objects */ + EVENTINSTANCE_LAYER = 0x00040000, /* Event layer instance objects */ + EVENTINSTANCE_SOUND = 0x00080000, /* Event sound instance objects */ + EVENTENVELOPE = 0x00100000, /* Event envelope objects */ + EVENTENVELOPEDEF = 0x00200000, /* Event envelope definition objects */ + EVENTPARAMETER = 0x00400000, /* Event parameter objects */ + EVENTCATEGORY = 0x00800000, /* Event category objects */ + EVENTENVELOPEPOINT = 0x01000000, /* Event envelope point objects */ + EVENTINSTANCEPOOL = 0x02000000, /* Event instance pool data */ + ALL = 0xffffffff, /* All memory used by FMOD Event System */ + + /* All event instance memory */ + EVENTINSTANCE_GROUP = (EVENTINSTANCE | EVENTINSTANCE_COMPLEX | EVENTINSTANCE_SIMPLE | EVENTINSTANCE_LAYER | EVENTINSTANCE_SOUND), + + /* All sound definition memory */ + SOUNDDEF_GROUP = (SOUNDDEFCLASS | SOUNDDEFDEFCLASS | SOUNDDEFPOOL) + } +} diff --git a/Unity Studio/Font.cs b/Unity Studio/Font.cs new file mode 100644 index 0000000..e8042a8 --- /dev/null +++ b/Unity Studio/Font.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class unityFont + { + public string m_Name; + public byte[] m_FontData; + public string extension; + + public unityFont(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + + int m_AsciiStartOffset = a_Stream.ReadInt32(); + + if (sourceFile.version[0] <= 3) + { + int m_FontCountX = a_Stream.ReadInt32(); + int m_FontCountY = a_Stream.ReadInt32(); + } + + float m_Kerning = a_Stream.ReadSingle(); + float m_LineSpacing = a_Stream.ReadSingle(); + + if (sourceFile.version[0] <= 3) + { + int m_PerCharacterKerning_size = a_Stream.ReadInt32(); + for (int i = 0; i < m_PerCharacterKerning_size; i++) + { + int first = a_Stream.ReadInt32(); + float second = a_Stream.ReadSingle(); + } + } + else + { + int m_CharacterSpacing = a_Stream.ReadInt32(); + int m_CharacterPadding = a_Stream.ReadInt32(); + } + + int m_ConvertCase = a_Stream.ReadInt32(); + PPtr m_DefaultMaterial = sourceFile.ReadPPtr(); + + int m_CharacterRects_size = a_Stream.ReadInt32(); + for (int i = 0; i < m_CharacterRects_size; i++) + { + int index = a_Stream.ReadInt32(); + //Rectf uv + float uvx = a_Stream.ReadSingle(); + float uvy = a_Stream.ReadSingle(); + float uvwidth = a_Stream.ReadSingle(); + float uvheight = a_Stream.ReadSingle(); + //Rectf vert + float vertx = a_Stream.ReadSingle(); + float verty = a_Stream.ReadSingle(); + float vertwidth = a_Stream.ReadSingle(); + float vertheight = a_Stream.ReadSingle(); + float width = a_Stream.ReadSingle(); + + if (sourceFile.version[0] >= 4) + { + bool flipped = a_Stream.ReadBoolean(); + a_Stream.Position += 3; + } + } + + PPtr m_Texture = sourceFile.ReadPPtr(); + + int m_KerningValues_size = a_Stream.ReadInt32(); + for (int i = 0; i < m_KerningValues_size; i++) + { + int pairfirst = a_Stream.ReadInt16(); + int pairsecond = a_Stream.ReadInt16(); + float second = a_Stream.ReadSingle(); + } + + if (sourceFile.version[0] <= 3) + { + bool m_GridFont = a_Stream.ReadBoolean(); + a_Stream.Position += 3; //4 byte alignment + } + else { float m_PixelScale = a_Stream.ReadSingle(); } + + int m_FontData_size = a_Stream.ReadInt32(); + if (m_FontData_size > 0) + { + m_FontData = new byte[m_FontData_size]; + a_Stream.Read(m_FontData, 0, m_FontData_size); + + if (m_FontData[0] == 79 && m_FontData[1] == 84 && m_FontData[2] == 84 && m_FontData[3] == 79) + { extension = ".otf"; } + else { extension = ".ttf"; } + + } + + float m_FontSize = a_Stream.ReadSingle();//problem here in minifootball + float m_Ascent = a_Stream.ReadSingle(); + uint m_DefaultStyle = a_Stream.ReadUInt32(); + + int m_FontNames = a_Stream.ReadInt32(); + for (int i = 0; i < m_FontNames; i++) + { + string m_FontName = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + } + + if (sourceFile.version[0] >= 4) + { + int m_FallbackFonts = a_Stream.ReadInt32(); + for (int i = 0; i < m_FallbackFonts; i++) + { + PPtr m_FallbackFont = sourceFile.ReadPPtr(); + } + + int m_FontRenderingMode = a_Stream.ReadInt32(); + } + } + } +} diff --git a/Unity Studio/GOHierarchy.cs b/Unity Studio/GOHierarchy.cs new file mode 100644 index 0000000..c5dc883 --- /dev/null +++ b/Unity Studio/GOHierarchy.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Unity_Studio +{ + public class GOHierarchy : TreeView + { + protected override void WndProc(ref Message m) + { + // Filter WM_LBUTTONDBLCLK + if (m.Msg != 0x203) base.WndProc(ref m); + } + } +} diff --git a/Unity Studio/GameObject.cs b/Unity Studio/GameObject.cs new file mode 100644 index 0000000..de4259d --- /dev/null +++ b/Unity Studio/GameObject.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Unity_Studio +{ + public class GameObject : TreeNode + { + public PPtr m_Transform; + public PPtr m_Renderer; + public PPtr m_MeshFilter; + public PPtr m_SkinnedMeshRenderer; + public int m_Layer; + public string m_Name; + public ushort m_Tag; + public bool m_IsActive; + + public string uniqueID = "0";//this way file and folder TreeNodes will be treated as FBX scene + + public GameObject(AssetPreloadData preloadData) + { + if (preloadData != null) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + uniqueID = preloadData.uniqueID; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + int m_Component_size = a_Stream.ReadInt32(); + for (int j = 0; j < m_Component_size; j++) + { + int m_Component_type = a_Stream.ReadInt32(); + + switch (m_Component_type) + { + case 4: + m_Transform = sourceFile.ReadPPtr(); + break; + case 23: + m_Renderer = sourceFile.ReadPPtr(); + break; + case 33: + m_MeshFilter = sourceFile.ReadPPtr(); + break; + case 137: + m_SkinnedMeshRenderer = sourceFile.ReadPPtr(); + break; + default: + PPtr m_Component = sourceFile.ReadPPtr(); + break; + } + } + + m_Layer = a_Stream.ReadInt32(); + int namesize = a_Stream.ReadInt32(); + m_Name = a_Stream.ReadAlignedString(namesize); + if (m_Name == "") { m_Name = "GameObject #" + uniqueID; } + m_Tag = a_Stream.ReadUInt16(); + m_IsActive = a_Stream.ReadBoolean(); + + base.Text = m_Name; + //name should be unique + base.Name = uniqueID; + } + } + } +} diff --git a/Unity Studio/Lz4DecoderStream.cs b/Unity Studio/Lz4DecoderStream.cs new file mode 100644 index 0000000..6c22838 --- /dev/null +++ b/Unity Studio/Lz4DecoderStream.cs @@ -0,0 +1,544 @@ +#define CHECK_ARGS +#define CHECK_EOF +//#define LOCAL_SHADOW + +using System; +using System.IO; + +namespace Lz4 +{ + public class Lz4DecoderStream : Stream + { + public Lz4DecoderStream() + { + } + + public Lz4DecoderStream( Stream input, long inputLength = long.MaxValue ) + { + Reset( input, inputLength ); + } + + public void Reset( Stream input, long inputLength = long.MaxValue ) + { + this.inputLength = inputLength; + this.input = input; + + phase = DecodePhase.ReadToken; + + decodeBufferPos = 0; + + litLen = 0; + matLen = 0; + matDst = 0; + + inBufPos = DecBufLen; + inBufEnd = DecBufLen; + } + + public override void Close() + { + this.input = null; + } + + private long inputLength; + private Stream input; + + //because we might not be able to match back across invocations, + //we have to keep the last window's worth of bytes around for reuse + //we use a circular buffer for this - every time we write into this + //buffer, we also write the same into our output buffer + + private const int DecBufLen = 0x10000; + private const int DecBufMask = 0xFFFF; + + private const int InBufLen = 128; + + private byte[] decodeBuffer = new byte[DecBufLen + InBufLen]; + private int decodeBufferPos, inBufPos, inBufEnd; + + //we keep track of which phase we're in so that we can jump right back + //into the correct part of decoding + + private DecodePhase phase; + + private enum DecodePhase + { + ReadToken, + ReadExLiteralLength, + CopyLiteral, + ReadOffset, + ReadExMatchLength, + CopyMatch, + } + + //state within interruptable phases and across phase boundaries is + //kept here - again, so that we can punt out and restart freely + + private int litLen, matLen, matDst; + + public override int Read( byte[] buffer, int offset, int count ) + { +#if CHECK_ARGS + if( buffer == null ) + throw new ArgumentNullException( "buffer" ); + if( offset < 0 || count < 0 || buffer.Length - count < offset ) + throw new ArgumentOutOfRangeException(); + + if( input == null ) + throw new InvalidOperationException(); +#endif + int nRead, nToRead = count; + + var decBuf = decodeBuffer; + + //the stringy gotos are obnoxious, but their purpose is to + //make it *blindingly* obvious how the state machine transitions + //back and forth as it reads - remember, we can yield out of + //this routine in several places, and we must be able to re-enter + //and pick up where we left off! + +#if LOCAL_SHADOW + var phase = this.phase; + var inBufPos = this.inBufPos; + var inBufEnd = this.inBufEnd; +#endif + switch( phase ) + { + case DecodePhase.ReadToken: + goto readToken; + + case DecodePhase.ReadExLiteralLength: + goto readExLiteralLength; + + case DecodePhase.CopyLiteral: + goto copyLiteral; + + case DecodePhase.ReadOffset: + goto readOffset; + + case DecodePhase.ReadExMatchLength: + goto readExMatchLength; + + case DecodePhase.CopyMatch: + goto copyMatch; + } + + readToken: + int tok; + if( inBufPos < inBufEnd ) + { + tok = decBuf[inBufPos++]; + } + else + { +#if LOCAL_SHADOW + this.inBufPos = inBufPos; +#endif + + tok = ReadByteCore(); +#if LOCAL_SHADOW + inBufPos = this.inBufPos; + inBufEnd = this.inBufEnd; +#endif +#if CHECK_EOF + if( tok == -1 ) + goto finish; +#endif + } + + litLen = tok >> 4; + matLen = (tok & 0xF) + 4; + + switch( litLen ) + { + case 0: + phase = DecodePhase.ReadOffset; + goto readOffset; + + case 0xF: + phase = DecodePhase.ReadExLiteralLength; + goto readExLiteralLength; + + default: + phase = DecodePhase.CopyLiteral; + goto copyLiteral; + } + + readExLiteralLength: + int exLitLen; + if( inBufPos < inBufEnd ) + { + exLitLen = decBuf[inBufPos++]; + } + else + { +#if LOCAL_SHADOW + this.inBufPos = inBufPos; +#endif + exLitLen = ReadByteCore(); +#if LOCAL_SHADOW + inBufPos = this.inBufPos; + inBufEnd = this.inBufEnd; +#endif + +#if CHECK_EOF + if( exLitLen == -1 ) + goto finish; +#endif + } + + litLen += exLitLen; + if( exLitLen == 255 ) + goto readExLiteralLength; + + phase = DecodePhase.CopyLiteral; + goto copyLiteral; + + copyLiteral: + int nReadLit = litLen < nToRead ? litLen : nToRead; + if( nReadLit != 0 ) + { + if( inBufPos + nReadLit <= inBufEnd ) + { + int ofs = offset; + + for( int c = nReadLit; c-- != 0; ) + buffer[ofs++] = decBuf[inBufPos++]; + + nRead = nReadLit; + } + else + { +#if LOCAL_SHADOW + this.inBufPos = inBufPos; +#endif + nRead = ReadCore( buffer, offset, nReadLit ); +#if LOCAL_SHADOW + inBufPos = this.inBufPos; + inBufEnd = this.inBufEnd; +#endif +#if CHECK_EOF + if( nRead == 0 ) + goto finish; +#endif + } + + offset += nRead; + nToRead -= nRead; + + litLen -= nRead; + + if( litLen != 0 ) + goto copyLiteral; + } + + if( nToRead == 0 ) + goto finish; + + phase = DecodePhase.ReadOffset; + goto readOffset; + + readOffset: + if( inBufPos + 1 < inBufEnd ) + { + matDst = (decBuf[inBufPos + 1] << 8) | decBuf[inBufPos]; + inBufPos += 2; + } + else + { +#if LOCAL_SHADOW + this.inBufPos = inBufPos; +#endif + matDst = ReadOffsetCore(); +#if LOCAL_SHADOW + inBufPos = this.inBufPos; + inBufEnd = this.inBufEnd; +#endif +#if CHECK_EOF + if( matDst == -1 ) + goto finish; +#endif + } + + if( matLen == 15 + 4 ) + { + phase = DecodePhase.ReadExMatchLength; + goto readExMatchLength; + } + else + { + phase = DecodePhase.CopyMatch; + goto copyMatch; + } + + readExMatchLength: + int exMatLen; + if( inBufPos < inBufEnd ) + { + exMatLen = decBuf[inBufPos++]; + } + else + { +#if LOCAL_SHADOW + this.inBufPos = inBufPos; +#endif + exMatLen = ReadByteCore(); +#if LOCAL_SHADOW + inBufPos = this.inBufPos; + inBufEnd = this.inBufEnd; +#endif +#if CHECK_EOF + if( exMatLen == -1 ) + goto finish; +#endif + } + + matLen += exMatLen; + if( exMatLen == 255 ) + goto readExMatchLength; + + phase = DecodePhase.CopyMatch; + goto copyMatch; + + copyMatch: + int nCpyMat = matLen < nToRead ? matLen : nToRead; + if( nCpyMat != 0 ) + { + nRead = count - nToRead; + + int bufDst = matDst - nRead; + if( bufDst > 0 ) + { + //offset is fairly far back, we need to pull from the buffer + + int bufSrc = decodeBufferPos - bufDst; + if( bufSrc < 0 ) + bufSrc += DecBufLen; + int bufCnt = bufDst < nCpyMat ? bufDst : nCpyMat; + + for( int c = bufCnt; c-- != 0; ) + buffer[offset++] = decBuf[bufSrc++ & DecBufMask]; + } + else + { + bufDst = 0; + } + + int sOfs = offset - matDst; + for( int i = bufDst; i < nCpyMat; i++ ) + buffer[offset++] = buffer[sOfs++]; + + nToRead -= nCpyMat; + matLen -= nCpyMat; + } + + if( nToRead == 0 ) + goto finish; + + phase = DecodePhase.ReadToken; + goto readToken; + + finish: + nRead = count - nToRead; + + int nToBuf = nRead < DecBufLen ? nRead : DecBufLen; + int repPos = offset - nToBuf; + + if( nToBuf == DecBufLen ) + { + Buffer.BlockCopy( buffer, repPos, decBuf, 0, DecBufLen ); + decodeBufferPos = 0; + } + else + { + int decPos = decodeBufferPos; + + while( nToBuf-- != 0 ) + decBuf[decPos++ & DecBufMask] = buffer[repPos++]; + + decodeBufferPos = decPos & DecBufMask; + } + +#if LOCAL_SHADOW + this.phase = phase; + this.inBufPos = inBufPos; +#endif + return nRead; + } + + private int ReadByteCore() + { + var buf = decodeBuffer; + + if( inBufPos == inBufEnd ) + { + int nRead = input.Read( buf, DecBufLen, + InBufLen < inputLength ? InBufLen : (int)inputLength ); + +#if CHECK_EOF + if( nRead == 0 ) + return -1; +#endif + + inputLength -= nRead; + + inBufPos = DecBufLen; + inBufEnd = DecBufLen + nRead; + } + + return buf[inBufPos++]; + } + + private int ReadOffsetCore() + { + var buf = decodeBuffer; + + if( inBufPos == inBufEnd ) + { + int nRead = input.Read( buf, DecBufLen, + InBufLen < inputLength ? InBufLen : (int)inputLength ); + +#if CHECK_EOF + if( nRead == 0 ) + return -1; +#endif + + inputLength -= nRead; + + inBufPos = DecBufLen; + inBufEnd = DecBufLen + nRead; + } + + if( inBufEnd - inBufPos == 1 ) + { + buf[DecBufLen] = buf[inBufPos]; + + int nRead = input.Read( buf, DecBufLen + 1, + InBufLen - 1 < inputLength ? InBufLen - 1 : (int)inputLength ); + +#if CHECK_EOF + if( nRead == 0 ) + { + inBufPos = DecBufLen; + inBufEnd = DecBufLen + 1; + + return -1; + } +#endif + + inputLength -= nRead; + + inBufPos = DecBufLen; + inBufEnd = DecBufLen + nRead + 1; + } + + int ret = (buf[inBufPos + 1] << 8) | buf[inBufPos]; + inBufPos += 2; + + return ret; + } + + private int ReadCore( byte[] buffer, int offset, int count ) + { + int nToRead = count; + + var buf = decodeBuffer; + int inBufLen = inBufEnd - inBufPos; + + int fromBuf = nToRead < inBufLen ? nToRead : inBufLen; + if( fromBuf != 0 ) + { + var bufPos = inBufPos; + + for( int c = fromBuf; c-- != 0; ) + buffer[offset++] = buf[bufPos++]; + + inBufPos = bufPos; + nToRead -= fromBuf; + } + + if( nToRead != 0 ) + { + int nRead; + + if( nToRead >= InBufLen ) + { + nRead = input.Read( buffer, offset, + nToRead < inputLength ? nToRead : (int)inputLength ); + nToRead -= nRead; + } + else + { + nRead = input.Read( buf, DecBufLen, + InBufLen < inputLength ? InBufLen : (int)inputLength ); + + inBufPos = DecBufLen; + inBufEnd = DecBufLen + nRead; + + fromBuf = nToRead < nRead ? nToRead : nRead; + + var bufPos = inBufPos; + + for( int c = fromBuf; c-- != 0; ) + buffer[offset++] = buf[bufPos++]; + + inBufPos = bufPos; + nToRead -= fromBuf; + } + + inputLength -= nRead; + } + + return count - nToRead; + } + + #region Stream internals + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return false; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + } + + public override long Length + { + get { throw new NotSupportedException(); } + } + + public override long Position + { + get { throw new NotSupportedException(); } + set { throw new NotSupportedException(); } + } + + public override long Seek( long offset, SeekOrigin origin ) + { + throw new NotSupportedException(); + } + + public override void SetLength( long value ) + { + throw new NotSupportedException(); + } + + public override void Write( byte[] buffer, int offset, int count ) + { + throw new NotSupportedException(); + } + + #endregion + } +} diff --git a/Unity Studio/Material.cs b/Unity Studio/Material.cs new file mode 100644 index 0000000..77cf5ca --- /dev/null +++ b/Unity Studio/Material.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class Material + { + + public string m_Name; + public PPtr m_Shader; + public string[] m_ShaderKeywords; + public int m_CustomRenderQueue; + public TexEnv[] m_TexEnvs; + public strFloatPair[] m_Floats; + public strColorPair[] m_Colors; + + public Material(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + m_Shader = sourceFile.ReadPPtr(); + + if (sourceFile.version[0] == 4 && (sourceFile.version[1] >= 2 || (sourceFile.version[1] == 1 && sourceFile.buildType[0] != "a"))) + { + m_ShaderKeywords = new string[a_Stream.ReadInt32()]; + for (int i = 0; i < m_ShaderKeywords.Length; i++) + { + m_ShaderKeywords[i] = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + } + } + else if (sourceFile.version[0] == 5) + { + m_ShaderKeywords = new string[1] { a_Stream.ReadAlignedString(a_Stream.ReadInt32()) }; + uint m_LightmapFlags = a_Stream.ReadUInt32(); + } + + if (sourceFile.version[0] > 4 || (sourceFile.version[0] == 4 && sourceFile.version[1] >= 3)) { m_CustomRenderQueue = a_Stream.ReadInt32(); } + + //m_SavedProperties + m_TexEnvs = new TexEnv[a_Stream.ReadInt32()]; + for (int i = 0; i < m_TexEnvs.Length; i++) + { + TexEnv m_TexEnv = new TexEnv() + { + name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()), + m_Texture = sourceFile.ReadPPtr(), + m_Scale = new float[2] { a_Stream.ReadSingle(), a_Stream.ReadSingle() }, + m_Offset = new float[2] { a_Stream.ReadSingle(), a_Stream.ReadSingle() } + }; + m_TexEnvs[i] = m_TexEnv; + } + + m_Floats = new strFloatPair[a_Stream.ReadInt32()]; + for (int i = 0; i < m_Floats.Length; i++) + { + strFloatPair m_Float = new strFloatPair() + { + first = a_Stream.ReadAlignedString(a_Stream.ReadInt32()), + second = a_Stream.ReadSingle() + }; + m_Floats[i] = m_Float; + } + + m_Colors = new strColorPair[a_Stream.ReadInt32()]; + for (int i = 0; i < m_Colors.Length; i++) + { + strColorPair m_Color = new strColorPair() + { + first = a_Stream.ReadAlignedString(a_Stream.ReadInt32()), + second = new float[4] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() } + }; + m_Colors[i] = m_Color; + } + } + } +} diff --git a/Unity Studio/Mesh.cs b/Unity Studio/Mesh.cs new file mode 100644 index 0000000..683a247 --- /dev/null +++ b/Unity Studio/Mesh.cs @@ -0,0 +1,1040 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Collections; + +/*Notes about handedness +Converting from left-handed to right-handed and vice versa requires either: +a) swapping any 2 axes +b) flipping any 1 axis +c) any odd combinations of a&b + +An even number of combinations will result in the same handedness, but in a different perspective. +Also, rotating the axes is just that, the same handedness in a different system. + +Y-up or Z-up are not requirements OR defining characteristics of a handedness, they are just common that way. + +Unity is left-handed with Y-up +Aircraft View +Y Top Y Up +| | +| Z Nose | +| / | +| / | ++--------X X--------+ + Right to the \ + left \ + Z towards viewer + +3ds Max is right-handed with Z up +Aircraft View +Z Top Z Up (Viewcube Top) +| | +| (-Y) Nose away Y | +| / from \ | +| / viewer \ | ++--------(-X) (VC Back) +--------X to the right + Right (Viewcube Right) + + + +FBX and Maya are both right-handed but with Y up! (90 degree rotation on X = samme handedness) +Aircraft View +Y Top Y Up (Viewcube Top) +| | +| Z Nose | +| / | +| / | ++--------(-X) +--------X to the right + Right \ (Viewcube Right) + \ + Z towards viewer + (Viewcube Front) + +Exporting FBX from Max, vertex components are ALWAYS written as they are in max: X Y Z. +The Axis option only affects GlobalSettings and PreRotation in the FBX file. +"Z-up" option: +UpAxis=2,Sign=1 <=> ViewCube Up = FBX vertex[2] <=> Max Z = FBX Z <=> Maya Y = FBX Z +FrontAxis=1,Sign=-1 <=> ViewCube -Front = FBX v[1] <=> Max -(-Y) = FBX Y <=> Maya -Z = FBX Y +CoordAxis=0,Sign=1 <=> ViewCube Right = FBX v[0] <=> Max X = FBX X <=> Maya X = FBX X +no PreRotation + +"Y-up" option: +UpAxis=1,Sign=1 <=> ViewCube Up = FBX vertex[1] <=> Max Z = FBX Y <=> Maya Y = FBX Y +FrontAxis=2,Sign=1 <=> ViewCube Front = FBX v[2] <=> Max -Y = FBX Z <=> Maya Z = FBX Z +CoordAxis=0,Sign=1 <=> ViewCube Right = FBX v[0] <=> Max X = FBX X <=> Maya X = FBX X +PreRotation -90,0,0 to bring Original Up (FBX Z) to ViewCube Up when importing +PreRotation means only the geometry is rotated locally around pivot before applying other modifiers. It is "invisible" to the user. + + +Importing FBX in Unity, Axis settings and PreRotations are ignored. +They probably ignore them because the order of vertex components is always the same in FBX, and Unity axes never change orientation (as opposed to Max-Maya). +Vertex components are loaded as follows: +Unity Up(Y) = FBX Y +Unity Front(Z) = FBX Z +Unity Left(X) = FBX -X + +Technically, this is a correct handedness conversion, but to a different system, because the model is not properly oriented (plane nose is down). +So Unity adds a -90 degree rotation, similar to the FBX PreRotation, to bring the nose to Front(Z). +Except it does it as a regular rotation, and combines it with any other rotations in the Transform asset. + +Converting from Unity back to FBX, the same vertex conversion cannot be applied because we have to take into account the rotation. +Option 0: convert vertices and transformations as -X,Y,Z and set FBX option to Y-up without PreRotation! +the result will be Max Z = FBX Y, Max -Y = FBX Z, Max X = FBX X => final order -X -Z Y +Option 1: convert vertices and transformations as -X,-Z,Y and set FBX options as "Z-up". +The -90 rotation exported from Unity will bring the model in correct orientation. +Option 2: convert vertices and transformations as -X,-Y,-Z, add -90 PreRotation to every Mesh Node and set FBX options as "Y-up". +The -90 rotation from Unity plus the -90 PreRotation will bring the model in correct orientation. +Remember though that the PreRotation is baked into the Geometry. + +But since the -90 rotation from Unity is a regular type, it will show up in the modifier in both cases. +Also, re-importing this FBX in Unity will now produce a (-90)+(-90)=-180 rotation. +This is an unfortunate eyesore, but nothing more, the orientation will be fine. + +In theory, one could add +90 degrees rotation to GameObjects that link to Mesh assets (but not other types) and use a different conversion for vertex components. +The problem is you can never know where the Unity mesh originated from. If it came from a left-handed format such as OBJ, there wouldn't have been any conversion and it wouldn't have that -90 degree adjustment. +So it would "fix" meshes that were originally sourced form FBX, but would still have the "extra" rotation in mehses sourced from left-handed formats. +*/ + +namespace Unity_Studio +{ + public class Mesh + { + private EndianStream a_Stream; + public string m_Name; + public List m_SubMeshes = new List(); + public List m_Indices = new List(); //use a list because I don't always know the facecount for triangle strips + public List m_materialIDs = new List(); + public uint m_VertexCount; + private ChannelInfo[] m_Channels; + private StreamInfo[] m_Streams; + private uint[] m_IndexBuffer; + public float[] m_Vertices; + public float[] m_Normals; + public float[] m_Colors; + public float[] m_UV1; + public float[] m_UV2; + public float[] m_Tangents; + + public class SubMesh + { + public uint firstByte; + public uint indexCount; + public int topology; + public uint triangleCount; + public uint firstVertex; + public uint vertexCount; + } + + public class ChannelInfo + { + public byte stream; + public byte offset; + public byte format; + public byte dimension; + } + + public class StreamInfo + { + public BitArray channelMask; + public int offset; + public int stride; + public uint align; //3.5.0 - 3.5.7 + public byte dividerOp; //4.0.0 and later + public ushort frequency; + } + + public class PackedBitVector + { + public uint m_NumItems; + public float m_Range = 1.0f; + public float m_Start = 0.0f; + public byte[] m_Data; + public byte m_BitSize; + } + + public float bytesToFloat (byte[] inputBytes) + { + float result = 0; + if (a_Stream.endian == EndianType.BigEndian) { Array.Reverse(inputBytes); } + + switch (inputBytes.Length) + { + case 1: + result = (float)inputBytes[0] / 255.0f; + break; + case 2: + result = Half.ToHalf(inputBytes, 0); + break; + case 4: + result = BitConverter.ToSingle(inputBytes, 0); + break; + } + + return result; + } + + public uint[] UnpackBitVector (PackedBitVector pakData) + { + uint[] unpackedVectors = new uint[pakData.m_NumItems]; + //int bitmax = 0;//used to convert int value to float + //for (int b = 0; b < pakData.m_BitSize; b++) { bitmax |= (1 << b); } + + //the lazy way + //split data into groups of "aligned" bytes i.e. 8 packed values per group + //I could calculate optimized group size based on BitSize, but this is the lazy way + + if (pakData.m_BitSize == 0) + { + pakData.m_BitSize = (byte)((pakData.m_Data.Length * 8) / pakData.m_NumItems); + //don't know, don't care + } + int groupSize = pakData.m_BitSize; //bitSize * 8 values / 8 bits + byte[] group = new byte[groupSize]; + int groupCount = (int)(pakData.m_NumItems / 8); + + for (int g = 0; g < groupCount; g++) + { + Buffer.BlockCopy(pakData.m_Data, g * groupSize, group, 0, groupSize); + BitArray groupBits = new BitArray(group); + + for (int v = 0; v < 8; v++) + { + BitArray valueBits = new BitArray(new Boolean[pakData.m_BitSize]); + for (int b = 0; b < pakData.m_BitSize; b++) + { + valueBits.Set(b, groupBits.Get(b + v * pakData.m_BitSize)); + } + + var valueArr = new int[1]; + valueBits.CopyTo(valueArr, 0); + //unpackedVectors[v + g * 8] = (float)(valueArr[0] / bitmax) * pakData.m_Range + pakData.m_Start; + //valueBits.CopyTo(unpackedVectors, v + g * 8);//doesn't work with uint[] + unpackedVectors[v + g * 8] = (uint)valueArr[0]; + } + } + + //m_NumItems is not necessarily a multiple of 8, so there can be one extra group with fewer values + int endBytes = pakData.m_Data.Length - groupCount * groupSize; + int endVal = (int)(pakData.m_NumItems - groupCount * 8); + + if (endBytes > 0) + { + Buffer.BlockCopy(pakData.m_Data, groupCount * groupSize, group, 0, endBytes); + BitArray groupBits = new BitArray(group); + + for (int v = 0; v < endVal; v++) + { + BitArray valueBits = new BitArray(new Boolean[pakData.m_BitSize]); + for (int b = 0; b < pakData.m_BitSize; b++) + { + valueBits.Set(b, groupBits.Get(b + v * pakData.m_BitSize)); + } + + var valueArr = new int[1]; + valueBits.CopyTo(valueArr, 0); + //unpackedVectors[v + groupCount * 8] = (float)(valueArr[0] / bitmax) * pakData.m_Range + pakData.m_Start; + //valueBits.CopyTo(unpackedVectors, v + groupCount * 8); + unpackedVectors[v + groupCount * 8] = (uint)valueArr[0]; + } + } + + + //the hard way + //compute bit position in m_Data for each value + /*byte[] value = new byte[4] { 0, 0, 0, 0 }; + + int byteCount = pakData.m_BitSize / 8;//bytes in single value + int bitCount = pakData.m_BitSize % 8; + + for (int v = 0; v < pakData.m_NumItems; v++) + { + if ((bitCount * v) % 8 == 0) //bitstream is "aligned" + {//does this make sense if I'm gonna compute unaligned anywhay? + for (int b = 0; b < byteCount; b++) + { + value[b] = pakData.m_Data[b + v * (byteCount+1)]; + } + + if (byteCount < 4) //shouldn't it be always? + { + byte lastByte = pakData.m_Data[bitCount * v / 8]; + + for (int b = 0; b < bitCount; b++)//no + { + //set bit in val[byteCount+1] + } + } + } + else + { + //god knows + } + + unpackedVectors[v] = BitConverter.ToSingle(value, 0); + }*/ + + + //first I split the data into byte-aligned arrays + //too complicated to calculate group size each time + //then no point in dividing? + /*int groupSize = byteCount + (bitCount + 7)/8; + + int groups = pakData.m_Data.Length / groupSize; + int valPerGr = (int)(pakData.m_NumItems / groups); + byte[] group = new byte[groupSize]; + + for (int g = 0; g < groups; g++) + { + Buffer.BlockCopy(pakData.m_Data, g * groupSize, group, 0, groupSize); + + for (int v = 0; v < valPerGr; v++) + { + + unpackedVectors[v + g * valPerGr] = BitConverter.ToSingle(value, 0); + } + } + + //m_Data size is not necessarily a multiple of align, so there can be one extra group with fewer values + int lastBytes = pakData.m_Data.Length % groupSize; + int lastVal = (int)(pakData.m_NumItems - groups * valPerGr); + + if (lastBytes > 0) + { + Buffer.BlockCopy(pakData.m_Data, groups * groupSize, group, 0, lastBytes); + + for (int v = 0; v < lastVal; v++) + { + + unpackedVectors[v + groups * valPerGr] = BitConverter.ToSingle(value, 0); + } + }*/ + + return unpackedVectors; + } + + public Mesh(AssetPreloadData MeshPD) + { + //Stream = new EndianStream(File.OpenRead(sourceFile.filePath), sourceFile.endianType); + //Stream.endian = sourceFile.endianType; + var version = MeshPD.sourceFile.version; + a_Stream = MeshPD.sourceFile.a_Stream; + a_Stream.Position = MeshPD.Offset; + + bool m_Use16BitIndices = true; //3.5.0 and newer always uses 16bit indices + uint m_MeshCompression = 0; + + if (MeshPD.sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = MeshPD.sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = MeshPD.sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) + { + m_Use16BitIndices = a_Stream.ReadBoolean(); + a_Stream.Position += 3; + } + + #region Index Buffer for 2.5.1 and earlier + if (version[0] == 2 && version[1] <= 5) + { + int m_IndexBuffer_size = a_Stream.ReadInt32(); + + if (m_Use16BitIndices) + { + m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; + for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } + a_Stream.AlignStream(4); + } + else + { + m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; + for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } + } + } + #endregion + + int m_SubMeshes_size = a_Stream.ReadInt32(); + for (int s = 0; s < m_SubMeshes_size; s++) + { + m_SubMeshes.Add(new SubMesh()); + m_SubMeshes[s].firstByte = a_Stream.ReadUInt32(); + m_SubMeshes[s].indexCount = a_Stream.ReadUInt32(); //what is this in case of triangle strips? + m_SubMeshes[s].topology = a_Stream.ReadInt32(); //isTriStrip + if (version[0] < 4) + { + m_SubMeshes[s].triangleCount = a_Stream.ReadUInt32(); + } + if (version[0] >= 3) + { + m_SubMeshes[s].firstVertex = a_Stream.ReadUInt32(); + m_SubMeshes[s].vertexCount = a_Stream.ReadUInt32(); + a_Stream.Position += 24; //Axis-Aligned Bounding Box + } + } + + #region m_Shapes for 4.1.0 and later, excluding 4.1.0 alpha + if (version [0] >= 5 || (version[0] == 4 && (version[1] > 1 || (version[1] == 1 && MeshPD.sourceFile.buildType[0] != "a")))) + { + if (version[0] == 4 && version[1] <= 2) //4.1.0f4 - 4.2.2f1 + { + int m_Shapes_size = a_Stream.ReadInt32(); + if (m_Shapes_size > 0) + { + bool stop = true; + } + for (int s = 0; s < m_Shapes_size; s++) //untested + { + string shape_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + a_Stream.Position += 36; //uint firstVertex, vertexCount; Vector3f aabbMinDelta, aabbMaxDelta; bool hasNormals, hasTangents + } + + int m_ShapeVertices_size = a_Stream.ReadInt32(); + a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index + } + else //4.3.0 and later + { + int m_ShapeVertices_size = a_Stream.ReadInt32(); + a_Stream.Position += m_ShapeVertices_size * 40; //vertex positions, normals, tangents & uint index + + int shapes_size = a_Stream.ReadInt32(); + a_Stream.Position += shapes_size * 12; //uint firstVertex, vertexCount; bool hasNormals, hasTangents + + int channels_size = a_Stream.ReadInt32(); + for (int c = 0; c < channels_size; c++) + { + string channel_name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + a_Stream.Position += 12; //uint nameHash; int frameIndex, frameCount + } + + int fullWeights_size = a_Stream.ReadInt32(); + a_Stream.Position += fullWeights_size * 4; //floats + + int m_BindPose_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 + + int m_BoneNameHashes_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BoneNameHashes_size * 4; //uints + + uint m_RootBoneNameHash = a_Stream.ReadUInt32(); + } + } + #endregion + + #region Index Buffer for 2.6.0 and later + if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) + { + m_MeshCompression = a_Stream.ReadByte(); + if (version[0] >= 4) + { + if (version[0] < 5) { uint m_StreamCompression = a_Stream.ReadByte(); } + bool m_IsReadable = a_Stream.ReadBoolean(); + bool m_KeepVertices = a_Stream.ReadBoolean(); + bool m_KeepIndices = a_Stream.ReadBoolean(); + } + a_Stream.AlignStream(4); + + int m_IndexBuffer_size = a_Stream.ReadInt32(); + + if (m_Use16BitIndices) + { + m_IndexBuffer = new uint[m_IndexBuffer_size / 2]; + for (int i = 0; i < m_IndexBuffer_size / 2; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt16(); } + a_Stream.AlignStream(4); + } + else + { + m_IndexBuffer = new uint[m_IndexBuffer_size / 4]; + for (int i = 0; i < m_IndexBuffer_size / 4; i++) { m_IndexBuffer[i] = a_Stream.ReadUInt32(); } + //align?? + } + } + #endregion + + #region Vertex Buffer for 3.4.2 and earlier + if (version[0] < 3 || (version[0] == 3 && version[1] < 5)) + { + m_VertexCount = a_Stream.ReadUInt32(); + m_Vertices = new float[m_VertexCount * 3]; + for (int v = 0; v < m_VertexCount * 3; v++) { m_Vertices[v] = a_Stream.ReadSingle(); } + + int m_Skin_size = a_Stream.ReadInt32(); + a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices + + int m_BindPose_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 + + int m_UV1_size = a_Stream.ReadInt32(); + m_UV1 = new float[m_UV1_size * 2]; + for (int v = 0; v < m_UV1_size * 2; v++) { m_UV1[v] = a_Stream.ReadSingle(); } + + int m_UV2_size = a_Stream.ReadInt32(); + m_UV2 = new float[m_UV2_size * 2]; + for (int v = 0; v < m_UV2_size * 2; v++) { m_UV2[v] = a_Stream.ReadSingle(); } + + if (version[0] == 2 && version[1] <= 5) + { + int m_TangentSpace_size = a_Stream.ReadInt32(); + m_Normals = new float[m_TangentSpace_size * 3]; + for (int v = 0; v < m_TangentSpace_size; v++) + { + m_Normals[v * 3] = a_Stream.ReadSingle(); + m_Normals[v * 3 + 1] = a_Stream.ReadSingle(); + m_Normals[v * 3 + 2] = a_Stream.ReadSingle(); + a_Stream.Position += 16; //Vector3f tangent & float handedness + } + } + else //2.6.0 and later + { + int m_Tangents_size = a_Stream.ReadInt32(); + a_Stream.Position += m_Tangents_size * 16; //Vector4f + + int m_Normals_size = a_Stream.ReadInt32(); + m_Normals = new float[m_Normals_size * 3]; + for (int v = 0; v < m_Normals_size * 3; v++) { m_Normals[v] = a_Stream.ReadSingle(); } + } + } + #endregion + #region Vertex Buffer for 3.5.0 and later + else + { + #region read vertex stream + int m_Skin_size = a_Stream.ReadInt32(); + a_Stream.Position += m_Skin_size * 32; //4x float weights & 4x int boneIndices + + if (version[0] <= 3 || (version[0] == 4 && version[1] <= 2)) + { + int m_BindPose_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BindPose_size * 16 * 4; //matrix 4x4 + } + + int m_CurrentChannels = a_Stream.ReadInt32();//defined as uint in Unity + m_VertexCount = a_Stream.ReadUInt32(); + + #region 3.5.0 - 3.5.7 + if (version[0] < 4) + { + if (m_MeshCompression != 0 && version[2] == 0) //special case not just on platform 9 + { + a_Stream.Position += 12; + } + else + { + m_Streams = new StreamInfo[4]; + for (int s = 0; s < 4; s++) + { + m_Streams[s] = new StreamInfo(); + m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); + m_Streams[s].offset = a_Stream.ReadInt32(); + m_Streams[s].stride = a_Stream.ReadInt32(); + m_Streams[s].align = a_Stream.ReadUInt32(); + } + } + } + #endregion + #region 4.0.0 and later + else + { + int singleStreamStride = 0;//used tor unity 5 + + m_Channels = new ChannelInfo[a_Stream.ReadInt32()]; + for (int c = 0; c < m_Channels.Length; c++) + { + m_Channels[c] = new ChannelInfo(); + m_Channels[c].stream = a_Stream.ReadByte(); + m_Channels[c].offset = a_Stream.ReadByte(); + m_Channels[c].format = a_Stream.ReadByte(); + m_Channels[c].dimension = a_Stream.ReadByte(); + + //calculate stride for Unity 5 + singleStreamStride += m_Channels[c].dimension * (m_Channels[c].format % 2 == 0 ? 4 : 2);//fingers crossed! + } + + if (version[0] < 5) + { + m_Streams = new StreamInfo[a_Stream.ReadInt32()]; + for (int s = 0; s < m_Streams.Length; s++) + { + m_Streams[s] = new StreamInfo(); + m_Streams[s].channelMask = new BitArray(new int[1] { a_Stream.ReadInt32() }); + m_Streams[s].offset = a_Stream.ReadInt32(); + m_Streams[s].stride = a_Stream.ReadByte(); + m_Streams[s].dividerOp = a_Stream.ReadByte(); + m_Streams[s].frequency = a_Stream.ReadUInt16(); + } + } + else //it's just easier to create my own stream here + { + m_Streams = new StreamInfo[1]; + m_Streams[0] = new StreamInfo(); + m_Streams[0].channelMask = new BitArray(new int[1] { m_CurrentChannels }); + m_Streams[0].offset = 0; + m_Streams[0].stride = singleStreamStride; + } + } + #endregion + + //actual Vertex Buffer + byte[] m_DataSize = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_DataSize, 0, m_DataSize.Length); + #endregion + + #region compute FvF + byte valueBufferSize = 0; + byte[] valueBuffer; + float[] dstArray; + + if (m_Channels != null) + { + //it is better to loop channels instead of streams + //because channels are likely to be sorted by vertex property + #region 4.0.0 and later + foreach (var m_Channel in m_Channels) + { + if (m_Channel.dimension > 0) + { + var m_Stream = m_Streams[m_Channel.stream]; + + for (int b = 0; b < 6; b++) + { + if (m_Stream.channelMask.Get(b)) + { + switch (m_Channel.format) + { + case 0: //32bit + valueBufferSize = 4; + break; + case 1: //16bit + valueBufferSize = 2; + break; + case 2: //8bit + valueBufferSize = 1; + m_Channel.dimension = 4;//these are actually groups of 4 components + break; + } + + valueBuffer = new byte[valueBufferSize]; + dstArray = new float[m_VertexCount * m_Channel.dimension]; + + for (int v = 0; v < m_VertexCount; v++) + { + for (int d = 0; d < m_Channel.dimension; d++) + { + int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; + Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); + dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); + } + } + + switch (b) + { + case 0://1 + m_Vertices = dstArray; + break; + case 1://2 + m_Normals = dstArray; + break; + case 2://4 + m_Colors = dstArray; + break; + case 3://8 + m_UV1 = dstArray; + break; + case 4://16 + m_UV2 = dstArray; + break; + case 5://32 + m_Tangents = dstArray; + break; + } + + m_Stream.channelMask.Set(b, false); //is this needed? + valueBuffer = null; + dstArray = null; + break; //go to next channel + } + } + } + } + } + #endregion + #region 3.5.0 - 3.5.7 + else if (m_Streams != null) + { + foreach (var m_Stream in m_Streams) + { + //a stream may have multiple vertex components but without channels there are no offsets, so I assume all vertex properties are in order + //Unity 3.5.x only uses floats, and that's probably why channels were introduced in Unity 4 + + ChannelInfo m_Channel = new ChannelInfo();//create my own channel so I can use the same methods + m_Channel.offset = 0; + + for (int b = 0; b < 6; b++) + { + if (m_Stream.channelMask.Get(b)) + { + switch (b) + { + case 0: + case 1: + valueBufferSize = 4; + m_Channel.dimension = 3; + break; + case 2: + valueBufferSize = 1; + m_Channel.dimension = 4; + break; + case 3: + case 4: + valueBufferSize = 4; + m_Channel.dimension = 2; + break; + case 5: + valueBufferSize = 4; + m_Channel.dimension = 4; + break; + } + + valueBuffer = new byte[valueBufferSize]; + dstArray = new float[m_VertexCount * m_Channel.dimension]; + + for (int v = 0; v < m_VertexCount; v++) + { + for (int d = 0; d < m_Channel.dimension; d++) + { + int m_DataSizeOffset = m_Stream.offset + m_Channel.offset + m_Stream.stride * v + valueBufferSize * d; + Buffer.BlockCopy(m_DataSize, m_DataSizeOffset, valueBuffer, 0, valueBufferSize); + dstArray[v * m_Channel.dimension + d] = bytesToFloat(valueBuffer); + } + } + + switch (b) + { + case 0: + m_Vertices = dstArray; + break; + case 1: + m_Normals = dstArray; + break; + case 2: + m_Colors = dstArray; + break; + case 3: + m_UV1 = dstArray; + break; + case 4: + m_UV2 = dstArray; + break; + case 5: + m_Tangents = dstArray; + break; + } + + m_Channel.offset += (byte)(m_Channel.dimension * valueBufferSize); //strides larger than 255 are unlikely + m_Stream.channelMask.Set(b, false); //is this needed? + valueBuffer = null; + dstArray = null; + } + } + } + } + #endregion + #endregion + } + #endregion + + #region Compressed Mesh data for 2.6.0 and later - 160 bytes + if (version[0] >= 3 || (version[0] == 2 && version[1] >= 6)) + { + //remember there can be combinations of packed and regular vertex properties + PackedBitVector m_Vertices_Packed = new PackedBitVector(); + m_Vertices_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Vertices_Packed.m_Range = a_Stream.ReadSingle(); + m_Vertices_Packed.m_Start = a_Stream.ReadSingle(); + m_Vertices_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Vertices_Packed.m_Data, 0, m_Vertices_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_Vertices_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_Vertices_Packed.m_NumItems > 0) + { + m_VertexCount = m_Vertices_Packed.m_NumItems / 3; + uint[] m_Vertices_Unpacked = UnpackBitVector(m_Vertices_Packed); + int bitmax = 0;//used to convert int value to float + for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + m_Vertices = new float[m_Vertices_Packed.m_NumItems]; + for (int v = 0; v < m_Vertices_Packed.m_NumItems; v++) + { + m_Vertices[v] = (float)m_Vertices_Unpacked[v] / bitmax * m_Vertices_Packed.m_Range + m_Vertices_Packed.m_Start; + } + } + + PackedBitVector m_UV_Packed = new PackedBitVector(); //contains both channels + m_UV_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_UV_Packed.m_Range = a_Stream.ReadSingle(); + m_UV_Packed.m_Start = a_Stream.ReadSingle(); + m_UV_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_UV_Packed.m_Data, 0, m_UV_Packed.m_Data.Length); + m_UV_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_UV_Packed.m_NumItems > 0) + { + uint[] m_UV_Unpacked = UnpackBitVector(m_UV_Packed); + int bitmax = 0; + for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + + m_UV1 = new float[m_VertexCount * 2]; + + for (int v = 0; v < m_VertexCount * 2; v++) + { + m_UV1[v] = (float)m_UV_Unpacked[v] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + } + + if (m_UV_Packed.m_NumItems == m_VertexCount * 4) + { + m_UV2 = new float[m_VertexCount * 2]; + for (uint v = 0; v < m_VertexCount * 2; v++) + { + m_UV2[v] = (float)m_UV_Unpacked[v + m_VertexCount * 2] / bitmax * m_UV_Packed.m_Range + m_UV_Packed.m_Start; + } + } + } + + if (version[0] < 5) + { + PackedBitVector m_BindPoses_Packed = new PackedBitVector(); + m_BindPoses_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_BindPoses_Packed.m_Range = a_Stream.ReadSingle(); + m_BindPoses_Packed.m_Start = a_Stream.ReadSingle(); + m_BindPoses_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_BindPoses_Packed.m_Data, 0, m_BindPoses_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_BindPoses_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + } + + PackedBitVector m_Normals_Packed = new PackedBitVector(); + m_Normals_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Normals_Packed.m_Range = a_Stream.ReadSingle(); + m_Normals_Packed.m_Start = a_Stream.ReadSingle(); + m_Normals_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Normals_Packed.m_Data, 0, m_Normals_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_Normals_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + PackedBitVector m_Tangents_Packed = new PackedBitVector(); + m_Tangents_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Tangents_Packed.m_Range = a_Stream.ReadSingle(); + m_Tangents_Packed.m_Start = a_Stream.ReadSingle(); + m_Tangents_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Tangents_Packed.m_Data, 0, m_Tangents_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_Tangents_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + PackedBitVector m_Weights_Packed = new PackedBitVector(); + m_Weights_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Weights_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Weights_Packed.m_Data, 0, m_Weights_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_Weights_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + PackedBitVector m_NormalSigns_packed = new PackedBitVector(); + m_NormalSigns_packed.m_NumItems = a_Stream.ReadUInt32(); + m_NormalSigns_packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_NormalSigns_packed.m_Data, 0, m_NormalSigns_packed.m_Data.Length); + a_Stream.AlignStream(4); + m_NormalSigns_packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_Normals_Packed.m_NumItems > 0) + { + uint[] m_Normals_Unpacked = UnpackBitVector(m_Normals_Packed); + uint[] m_NormalSigns = UnpackBitVector(m_NormalSigns_packed); + int bitmax = 0; + for (int b = 0; b < m_Normals_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + m_Normals = new float[m_Normals_Packed.m_NumItems / 2 * 3]; + for (int v = 0; v < m_Normals_Packed.m_NumItems / 2; v++) + { + m_Normals[v * 3] = (float)((double)m_Normals_Unpacked[v * 2] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; + m_Normals[v * 3 + 1] = (float)((double)m_Normals_Unpacked[v * 2 + 1] / bitmax) * m_Normals_Packed.m_Range + m_Normals_Packed.m_Start; + m_Normals[v * 3 + 2] = (float)Math.Sqrt(1 - m_Normals[v * 3] * m_Normals[v * 3] - m_Normals[v * 3 + 1] * m_Normals[v * 3 + 1]); + if (m_NormalSigns[v] == 0) { m_Normals[v * 3 + 2] *= -1; } + } + } + + PackedBitVector m_TangentSigns = new PackedBitVector(); + m_TangentSigns.m_NumItems = a_Stream.ReadUInt32(); + m_TangentSigns.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_TangentSigns.m_Data, 0, m_TangentSigns.m_Data.Length); + a_Stream.AlignStream(4); + m_TangentSigns.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (version[0] >= 5) + { + PackedBitVector m_FloatColors = new PackedBitVector(); + m_FloatColors.m_NumItems = a_Stream.ReadUInt32(); + m_FloatColors.m_Range = a_Stream.ReadSingle(); + m_FloatColors.m_Start = a_Stream.ReadSingle(); + m_FloatColors.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_FloatColors.m_Data, 0, m_FloatColors.m_Data.Length); + a_Stream.AlignStream(4); + m_FloatColors.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_FloatColors.m_NumItems > 0) + { + uint[] m_FloatColors_Unpacked = UnpackBitVector(m_FloatColors); + int bitmax = 0; + for (int b = 0; b < m_Vertices_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + + m_Colors = new float[m_FloatColors.m_NumItems]; + + for (int v = 0; v < m_FloatColors.m_NumItems; v++) + { + m_Colors[v] = (float)m_FloatColors_Unpacked[v] / bitmax * m_FloatColors.m_Range + m_FloatColors.m_Start; + } + } + } + + PackedBitVector m_BoneIndices = new PackedBitVector(); + m_BoneIndices.m_NumItems = a_Stream.ReadUInt32(); + m_BoneIndices.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_BoneIndices.m_Data, 0, m_BoneIndices.m_Data.Length); + a_Stream.AlignStream(4); + m_BoneIndices.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + PackedBitVector m_Triangles = new PackedBitVector(); + m_Triangles.m_NumItems = a_Stream.ReadUInt32(); + m_Triangles.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Triangles.m_Data, 0, m_Triangles.m_Data.Length); + a_Stream.AlignStream(4); + m_Triangles.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_Triangles.m_NumItems > 0) { m_IndexBuffer = UnpackBitVector(m_Triangles); } + } + #endregion + + #region Colors & Collision triangles for 3.4.2 and earlier + if (version[0] <= 2 || (version[0] == 3 && version[1] <= 4)) // + { + a_Stream.Position += 24; //Axis-Aligned Bounding Box + int m_Colors_size = a_Stream.ReadInt32(); + m_Colors = new float[m_Colors_size * 4]; + for (int v = 0; v < m_Colors_size * 4; v++) { m_Colors[v] = (float)(a_Stream.ReadByte()) / 0xFF; } + + int m_CollisionTriangles_size = a_Stream.ReadInt32(); + a_Stream.Position += m_CollisionTriangles_size * 4; //UInt32 indices + int m_CollisionVertexCount = a_Stream.ReadInt32(); + } + #endregion + #region Compressed colors & Local AABB for 3.5.0 to 4.x.x + else //vertex colors are either in streams or packed bits + { + if (version[0] < 5) + { + PackedBitVector m_Colors_Packed = new PackedBitVector(); + m_Colors_Packed.m_NumItems = a_Stream.ReadUInt32(); + m_Colors_Packed.m_Data = new byte[a_Stream.ReadInt32()]; + a_Stream.Read(m_Colors_Packed.m_Data, 0, m_Colors_Packed.m_Data.Length); + a_Stream.AlignStream(4); + m_Colors_Packed.m_BitSize = a_Stream.ReadByte(); + a_Stream.Position += 3; //4 byte alignment + + if (m_Colors_Packed.m_NumItems > 0) + { + if (m_Colors_Packed.m_BitSize == 32) + { + //4 x 8bit color channels + m_Colors = new float[m_Colors_Packed.m_Data.Length]; + for (int v = 0; v < m_Colors_Packed.m_Data.Length; v++) + { + m_Colors[v] = (float)m_Colors_Packed.m_Data[v] / 0xFF; + } + } + else //not tested + { + uint[] m_Colors_Unpacked = UnpackBitVector(m_Colors_Packed); + int bitmax = 0;//used to convert int value to float + for (int b = 0; b < m_Colors_Packed.m_BitSize; b++) { bitmax |= (1 << b); } + m_Colors = new float[m_Colors_Packed.m_NumItems]; + for (int v = 0; v < m_Colors_Packed.m_NumItems; v++) + { + m_Colors[v] = (float)m_Colors_Unpacked[v] / bitmax; + } + } + } + } + + a_Stream.Position += 24; //Axis-Aligned Bounding Box + } + #endregion + + int m_MeshUsageFlags = a_Stream.ReadInt32(); + + if (version[0] >= 5) + { + //int m_BakedConvexCollisionMesh = a_Stream.ReadInt32(); + //a_Stream.Position += m_BakedConvexCollisionMesh; + //int m_BakedTriangleCollisionMesh = a_Stream.ReadInt32(); + //a_Stream.Position += m_BakedConvexCollisionMesh; + } + + #region Build face indices + for (int s = 0; s < m_SubMeshes_size; s++) + { + uint firstIndex = m_SubMeshes[s].firstByte / 2; + if (!m_Use16BitIndices) { firstIndex /= 2; } + + if (m_SubMeshes[s].topology == 0) + { + for (int i = 0; i < m_SubMeshes[s].indexCount / 3; i++) + { + m_Indices.Add(m_IndexBuffer[firstIndex + i * 3]); + m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 1]); + m_Indices.Add(m_IndexBuffer[firstIndex + i * 3 + 2]); + m_materialIDs.Add(s); + } + } + else + { + for (int i = 0; i < m_SubMeshes[s].indexCount - 2; i++) + { + uint fa = m_IndexBuffer[firstIndex + i]; + uint fb = m_IndexBuffer[firstIndex + i + 1]; + uint fc = m_IndexBuffer[firstIndex + i + 2]; + + if ((fa!=fb) && (fa!=fc) && (fc!=fb)) + { + m_Indices.Add(fa); + if ((i % 2) == 0) + { + m_Indices.Add(fb); + m_Indices.Add(fc); + } + else + { + m_Indices.Add(fc); + m_Indices.Add(fb); + } + m_materialIDs.Add(s); + } + } + } + } + #endregion + } + } +} diff --git a/Unity Studio/MeshFilter.cs b/Unity Studio/MeshFilter.cs new file mode 100644 index 0000000..d5013fd --- /dev/null +++ b/Unity Studio/MeshFilter.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class MeshFilter + { + public long preloadIndex; + public PPtr m_GameObject = new PPtr(); + public PPtr m_Mesh = new PPtr(); + + public MeshFilter(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_GameObject = sourceFile.ReadPPtr(); + m_Mesh = sourceFile.ReadPPtr(); + } + } +} diff --git a/Unity Studio/PlayerSettings.cs b/Unity Studio/PlayerSettings.cs new file mode 100644 index 0000000..0c5c6f0 --- /dev/null +++ b/Unity Studio/PlayerSettings.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class PlayerSettings + { + public string companyName = ""; + public string productName = ""; + + public PlayerSettings(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.version[0] >= 3) + { + if (sourceFile.version[0] == 3 && sourceFile.version[1] <2) { string AndroidLicensePublicKey = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); } + else { bool AndroidProfiler = a_Stream.ReadBoolean(); a_Stream.AlignStream(4); } + + int defaultScreenOrientation = a_Stream.ReadInt32(); + int targetDevice = a_Stream.ReadInt32(); + int targetGlesGraphics = a_Stream.ReadInt32(); + if (sourceFile.version[0] == 5 || (sourceFile.version[0] == 4 && sourceFile.version[1] == 6 && sourceFile.version[2] >= 3)) + { int targetIOSGraphics = a_Stream.ReadInt32(); } + int targetResolution = a_Stream.ReadInt32(); + + if (sourceFile.version[0] == 3 && sourceFile.version[1] <= 1) { bool OverrideIPodMusic = a_Stream.ReadBoolean(); a_Stream.AlignStream(4); } + else if (sourceFile.version[0] == 3 && sourceFile.version[1] <= 4) { } + else { int accelerometerFrequency = a_Stream.ReadInt32(); }//3.5.0 and up + } + + companyName = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + productName = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + } + } +} diff --git a/Unity Studio/Program.cs b/Unity Studio/Program.cs new file mode 100644 index 0000000..c035b16 --- /dev/null +++ b/Unity Studio/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; + +namespace Unity_Studio +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new UnityStudioForm()); + } + } +} diff --git a/Unity Studio/Properties/AssemblyInfo.cs b/Unity Studio/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..307fb66 --- /dev/null +++ b/Unity Studio/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Unity Studio")] +[assembly: AssemblyDescription("- Compatible with all Unity versions from 2.5.0 to 4.6.9\r\n- Compatible with Web, PC, iOS, Android, PS3, Xbox 360, OSX and Linux games/apps\r\n- Automatically merges .split\r\n- 3D objets exported to FBX\r\n- Able to load audio streams from .resS files\r\n- Real-time preview window and export function for textures, audio clips, shaders and fonts\r\n - Textures: DDS (Alpha8bpp, ARGB16bpp, RGB24bpp, ARGB32bpp, BGRA32bpp, RGB565, DXT1, DXT5, RGBA16bpp)\r\n PVR (PVRTC_RGB2, PVRTC_RGBA2, PVRTC_RGBA4, PVRTC_RGB4, ETC_RGB4)\r\n - Audio clips: mp3, ogg, wav, xbox wav\r\n - Shader files are exported in plain-text\r\n - Fonts: ttf, otf")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Unity Studio")] +[assembly: AssemblyCopyright("Copyright © 2014 Chipicao")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("05c04c20-dd89-4895-9f06-33d5cfbfe925")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.4.6.9")] +[assembly: AssemblyFileVersion("0.4.6.9")] diff --git a/Unity Studio/Properties/Resources.Designer.cs b/Unity Studio/Properties/Resources.Designer.cs new file mode 100644 index 0000000..cc5a6dc --- /dev/null +++ b/Unity Studio/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Unity_Studio.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Unity_Studio.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap preview { + get { + object obj = ResourceManager.GetObject("preview", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/Unity Studio/Properties/Resources.resx b/Unity Studio/Properties/Resources.resx new file mode 100644 index 0000000..2d8bbcc --- /dev/null +++ b/Unity Studio/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\preview.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/Unity Studio/Properties/Settings.Designer.cs b/Unity Studio/Properties/Settings.Designer.cs new file mode 100644 index 0000000..2dd45cc --- /dev/null +++ b/Unity Studio/Properties/Settings.Designer.cs @@ -0,0 +1,170 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Unity_Studio.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool uniqueNames { + get { + return ((bool)(this["uniqueNames"])); + } + set { + this["uniqueNames"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool enablePreview { + get { + return ((bool)(this["enablePreview"])); + } + set { + this["enablePreview"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool displayInfo { + get { + return ((bool)(this["displayInfo"])); + } + set { + this["displayInfo"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool openAfterExport { + get { + return ((bool)(this["openAfterExport"])); + } + set { + this["openAfterExport"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int assetGroupOption { + get { + return ((int)(this["assetGroupOption"])); + } + set { + this["assetGroupOption"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool exportNormals { + get { + return ((bool)(this["exportNormals"])); + } + set { + this["exportNormals"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool exportTangents { + get { + return ((bool)(this["exportTangents"])); + } + set { + this["exportTangents"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool exportUVs { + get { + return ((bool)(this["exportUVs"])); + } + set { + this["exportUVs"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool exportColors { + get { + return ((bool)(this["exportColors"])); + } + set { + this["exportColors"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2.54")] + public decimal scaleFactor { + get { + return ((decimal)(this["scaleFactor"])); + } + set { + this["scaleFactor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int upAxis { + get { + return ((int)(this["upAxis"])); + } + set { + this["upAxis"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool showExpOpt { + get { + return ((bool)(this["showExpOpt"])); + } + set { + this["showExpOpt"] = value; + } + } + } +} diff --git a/Unity Studio/Properties/Settings.settings b/Unity Studio/Properties/Settings.settings new file mode 100644 index 0000000..0f60053 --- /dev/null +++ b/Unity Studio/Properties/Settings.settings @@ -0,0 +1,42 @@ + + + + + + True + + + True + + + True + + + True + + + 0 + + + True + + + False + + + True + + + True + + + 2.54 + + + 0 + + + False + + + \ No newline at end of file diff --git a/Unity Studio/RectTransform.cs b/Unity Studio/RectTransform.cs new file mode 100644 index 0000000..cedff78 --- /dev/null +++ b/Unity Studio/RectTransform.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class RectTransform + { + public Transform m_Transform; + + public RectTransform(AssetPreloadData preloadData) + { + m_Transform = new Transform(preloadData); + + //var sourceFile = preloadData.sourceFile; + //var a_Stream = preloadData.sourceFile.a_Stream; + + /* + float[2] AnchorsMin + float[2] AnchorsMax + float[2] Pivod + float Width + float Height + float[2] ? + */ + + } + } +} diff --git a/Unity Studio/Renderer.cs b/Unity Studio/Renderer.cs new file mode 100644 index 0000000..457d7cf --- /dev/null +++ b/Unity Studio/Renderer.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class Renderer + { + public PPtr m_GameObject; + public bool m_Enabled; + public byte m_CastShadows; //bool prior to Unity 5 + public bool m_ReceiveShadows; + public ushort m_LightmapIndex; + public ushort m_LightmapIndexDynamic; + public PPtr[] m_Materials; + + public Renderer(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_GameObject = sourceFile.ReadPPtr(); + m_Enabled = a_Stream.ReadBoolean(); + m_CastShadows = a_Stream.ReadByte(); + m_ReceiveShadows = a_Stream.ReadBoolean(); + if (sourceFile.version[0] < 5) { m_LightmapIndex = a_Stream.ReadByte(); } + else + { + a_Stream.Position += 5; //suspicious alignment, could be 2 alignments between bools + m_LightmapIndex = a_Stream.ReadUInt16(); + m_LightmapIndexDynamic = a_Stream.ReadUInt16(); + } + + if (sourceFile.version[0] >= 3) { a_Stream.Position += 16; } //Vector4f m_LightmapTilingOffset + if (sourceFile.version[0] >= 5) { a_Stream.Position += 16; } //Vector4f m_LightmapTilingOffsetDynamic + + m_Materials = new PPtr[a_Stream.ReadInt32()]; + for (int m = 0; m < m_Materials.Length; m++) + { + m_Materials[m] = sourceFile.ReadPPtr(); + } + + } + } +} diff --git a/Unity Studio/Resources/preview.png b/Unity Studio/Resources/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..6e5ee329fe1b8973c773454306723432f0e3e97d GIT binary patch literal 280460 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 literal 0 HcmV?d00001 diff --git a/Unity Studio/SkinnedMeshRenderer.cs b/Unity Studio/SkinnedMeshRenderer.cs new file mode 100644 index 0000000..2ef25d9 --- /dev/null +++ b/Unity Studio/SkinnedMeshRenderer.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class SkinnedMeshRenderer + { + public PPtr m_GameObject; + public bool m_Enabled; + public bool m_CastShadows; + public bool m_ReceiveShadows; + public ushort m_LightmapIndex; + public ushort m_LightmapIndexDynamic; + public PPtr[] m_Materials; + public PPtr m_Mesh; + + public SkinnedMeshRenderer(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var version = preloadData.sourceFile.version; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_GameObject = sourceFile.ReadPPtr(); + m_Enabled = a_Stream.ReadBoolean(); + m_CastShadows = a_Stream.ReadBoolean(); + m_ReceiveShadows = a_Stream.ReadBoolean(); + if (sourceFile.version[0] < 5) { m_LightmapIndex = a_Stream.ReadByte(); } + else + { + a_Stream.Position += 5; //suspicious alignment, could be 2 alignments between bools + m_LightmapIndex = a_Stream.ReadUInt16(); + m_LightmapIndexDynamic = a_Stream.ReadUInt16(); + } + + if (version[0] >= 3) { a_Stream.Position += 16; } //m_LightmapTilingOffset vector4d + + m_Materials = new PPtr[a_Stream.ReadInt32()]; + for (int m = 0; m < m_Materials.Length; m++) + { + m_Materials[m] = sourceFile.ReadPPtr(); + } + + if (version[0] < 3) { a_Stream.Position += 16; } //m_LightmapTilingOffset vector4d + else + { + int m_SubsetIndices_size = a_Stream.ReadInt32(); + a_Stream.Position += m_SubsetIndices_size * 4; + PPtr m_StaticBatchRoot = sourceFile.ReadPPtr(); + + if ((version[0] == 3 && version[1] >= 5) || version[0] >= 4) + { + bool m_UseLightProbes = a_Stream.ReadBoolean(); + a_Stream.Position += 3; //alignment + if (version[0] == 5) { int m_ReflectionProbeUsage = a_Stream.ReadInt32(); } + //did I ever check if the anchor is conditioned by the bool? + PPtr m_LightProbeAnchor = sourceFile.ReadPPtr(); + } + + if (version[0] >= 4 && version[1] >= 3) + { + if (version[1] >= 5) { int m_SortingLayer = a_Stream.ReadInt32(); } + else { int m_SortingLayer = a_Stream.ReadInt16(); } + int m_SortingOrder = a_Stream.ReadInt16(); + a_Stream.AlignStream(4); + } + } + + int m_Quality = a_Stream.ReadInt32(); + bool m_UpdateWhenOffscreen = a_Stream.ReadBoolean(); + bool m_SkinNormals = a_Stream.ReadBoolean(); //3.1.0 and below + a_Stream.Position += 2; + + if (version[0] == 2 && version[1] < 6) + { + //this would be the only error if mainVersion is not read in time for a unity 2.x game + PPtr m_DisableAnimationWhenOffscreen = sourceFile.ReadPPtr(); + } + + m_Mesh = sourceFile.ReadPPtr(); + + int m_Bones_size = a_Stream.ReadInt32(); + for (int b = 0; b < m_Bones_size; b++) + { + PPtr aBone = sourceFile.ReadPPtr(); + } + + if (version[0] < 3) + { + int m_BindPose_size = a_Stream.ReadInt32(); + a_Stream.Position += m_BindPose_size * 16 * 4;//Matrix4x4f + } + else if (version[0] >= 3 && version[1] >= 4) + { + if (version[1] >= 5) + { + PPtr m_RootBone = sourceFile.ReadPPtr(); + } + //AABB + float[] m_Center = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + float[] m_Extent = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + bool m_DirtyAABB = a_Stream.ReadBoolean(); + } + } + } +} diff --git a/Unity Studio/TextAsset.cs b/Unity Studio/TextAsset.cs new file mode 100644 index 0000000..44e25e4 --- /dev/null +++ b/Unity Studio/TextAsset.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class TextAsset + { + public string m_Name; + public byte[] m_Script; + public string m_PathName; + + public int exportSize; + public string extension = ".txt"; + + public TextAsset(AssetPreloadData preloadData, bool readSwitch) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + + int m_Script_size = a_Stream.ReadInt32(); + + if (readSwitch) //asset is read for preview or export + { + m_Script = new byte[m_Script_size]; + a_Stream.Read(m_Script, 0, m_Script_size); + + if (m_Script[0] == 93) { m_Script = SevenZip.Compression.LZMA.SevenZipHelper.Decompress(m_Script); } + if (m_Script[0] == 60 || (m_Script[0] == 239 && m_Script[1] == 187 && m_Script[2] == 191 && m_Script[3] == 60)) { extension = ".xml"; } + } + else + { + byte lzmaTest = a_Stream.ReadByte(); + if (lzmaTest == 93) + { + a_Stream.Position += 4; + exportSize = a_Stream.ReadInt32(); //actualy int64 + a_Stream.Position -= 8; + } + else { exportSize = m_Script_size; } + + a_Stream.Position += m_Script_size - 1; + } + a_Stream.AlignStream(4); + + m_PathName = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + } + } +} diff --git a/Unity Studio/Texture2D.cs b/Unity Studio/Texture2D.cs new file mode 100644 index 0000000..86dde3e --- /dev/null +++ b/Unity Studio/Texture2D.cs @@ -0,0 +1,328 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + class Texture2D + { + public string m_Name; + public int m_Width; + public int m_Height; + public int m_CompleteImageSize; + public int m_TextureFormat; + public bool m_MipMap; + public bool m_IsReadable; + public bool m_ReadAllowed; + public int m_ImageCount; + public int m_TextureDimension; + //m_TextureSettings + public int m_FilterMode; + public int m_Aniso; + public float m_MipBias; + public int m_WrapMode; + public int m_LightmapFormat; + public int m_ColorSpace; + public byte[] image_data; + + public int dwFlags = 0x1 + 0x2 + 0x4 + 0x1000; + //public int dwHeight; + //public int dwWidth; + public int dwPitchOrLinearSize = 0x0; + public int dwMipMapCount = 0x1; + public int dwSize = 0x20; + public int dwFlags2; + public int dwFourCC = 0x0; + public int dwRGBBitCount; + public int dwRBitMask; + public int dwGBitMask; + public int dwBBitMask; + public int dwABitMask; + public int dwCaps = 0x1000; + public int dwCaps2 = 0x0; + + public int pvrVersion = 0x03525650; + public int pvrFlags = 0x0; + public long pvrPixelFormat; + public int pvrColourSpace = 0x0; + public int pvrChannelType = 0x0; + //public int pvrHeight; + //public int pvrWidth; + public int pvrDepth = 0x1; + public int pvrNumSurfaces = 0x1; //For texture arrays + public int pvrNumFaces = 0x1; //For cube maps + //public int pvrMIPMapCount; + public int pvrMetaDataSize = 0x0; + + public int image_data_size; + string extension; + + public Texture2D(AssetPreloadData preloadData, bool readSwitch) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_Name = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + m_Width = a_Stream.ReadInt32(); + m_Height = a_Stream.ReadInt32(); + m_CompleteImageSize = a_Stream.ReadInt32(); + m_TextureFormat = a_Stream.ReadInt32(); + + if (m_TextureFormat < 30) { extension = ".dds"; } + else if (m_TextureFormat < 35) { extension = ".pvr"; } + else { extension = "_" + m_Width.ToString() + "x" + m_Height.ToString() + "." + m_TextureFormat.ToString() + ".tex"; } + + m_MipMap = a_Stream.ReadBoolean(); + m_IsReadable = a_Stream.ReadBoolean(); //2.6.0 and up + m_ReadAllowed = a_Stream.ReadBoolean(); //3.0.0 and up + a_Stream.Position += 1; //4 byte alignment + m_ImageCount = a_Stream.ReadInt32(); + m_TextureDimension = a_Stream.ReadInt32(); + //m_TextureSettings + m_FilterMode = a_Stream.ReadInt32(); + m_Aniso = a_Stream.ReadInt32(); + m_MipBias = a_Stream.ReadSingle(); + m_WrapMode = a_Stream.ReadInt32(); + + if (sourceFile.version[0] >= 3) + { + m_LightmapFormat = a_Stream.ReadInt32(); + if (sourceFile.version[0] >= 4 || sourceFile.version[1] >= 5) { m_ColorSpace = a_Stream.ReadInt32(); } //3.5.0 and up + } + + image_data_size = a_Stream.ReadInt32(); + + if (m_MipMap) + { + dwFlags += 0x20000; + dwMipMapCount = Convert.ToInt32(Math.Log(Math.Max(m_Width, m_Height)) / Math.Log(2)); + dwCaps += 0x400008; + } + + if (readSwitch) + { + + image_data = new byte[image_data_size]; + a_Stream.Read(image_data, 0, image_data_size); + + switch (m_TextureFormat) + { + case 1: //Alpha8 + { + dwFlags2 = 0x2; + dwRGBBitCount = 0x8; + dwRBitMask = 0x0; + dwGBitMask = 0x0; + dwBBitMask = 0x0; + dwABitMask = 0xFF; + break; + } + case 2: //A4R4G4B4 + { + if (sourceFile.platform == 11) //swap bytes for Xbox confirmed, PS3 not encountered + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte b0 = image_data[i * 2]; + image_data[i * 2] = image_data[i * 2 + 1]; + image_data[i * 2 + 1] = b0; + } + } + else if (sourceFile.platform == 13) //swap bits for android + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte[] argb = BitConverter.GetBytes((BitConverter.ToInt32((new byte[4] { image_data[i * 2], image_data[i * 2 + 1], image_data[i * 2], image_data[i * 2 + 1] }), 0)) >> 4); + image_data[i * 2] = argb[0]; + image_data[i * 2 + 1] = argb[1]; + } + } + + dwFlags2 = 0x41; + dwRGBBitCount = 0x10; + dwRBitMask = 0xF00; + dwGBitMask = 0xF0; + dwBBitMask = 0xF; + dwABitMask = 0xF000; + break; + } + case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure + { + for (int i = 0; i < (image_data_size / 3); i++) + { + byte b0 = image_data[i * 3]; + image_data[i * 3] = image_data[i * 3 + 2]; + //image_data[i * 3 + 1] stays the same + image_data[i * 3 + 2] = b0; + + } + + dwFlags2 = 0x40; + dwRGBBitCount = 0x18; + dwRBitMask = 0xFF0000; + dwGBitMask = 0xFF00; + dwBBitMask = 0xFF; + dwABitMask = 0x0; + break; + } + case 4: //G8R8A8B8 //confirmed on X360, iOS + { + for (int i = 0; i < (image_data_size / 4); i++) + { + byte b0 = image_data[i * 4]; + image_data[i * 4] = image_data[i * 4 + 2]; + //image_data[i * 4 + 1] stays the same + image_data[i * 4 + 2] = b0; + //image_data[i * 4 + 3] stays the same + + } + + dwFlags2 = 0x41; + dwRGBBitCount = 0x20; + dwRBitMask = 0xFF0000; + dwGBitMask = 0xFF00; + dwBBitMask = 0xFF; + dwABitMask = -16777216; + break; + } + case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS + { + for (int i = 0; i < (image_data_size / 4); i++) + { + byte b0 = image_data[i * 4]; + byte b1 = image_data[i * 4 + 1]; + image_data[i * 4] = image_data[i * 4 + 3]; + image_data[i * 4 + 1] = image_data[i * 4 + 2]; + image_data[i * 4 + 2] = b1; + image_data[i * 4 + 3] = b0; + + } + + dwFlags2 = 0x41; + dwRGBBitCount = 0x20; + dwRBitMask = 0xFF0000; + dwGBitMask = 0xFF00; + dwBBitMask = 0xFF; + dwABitMask = -16777216; + break; + } + case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS + { + if (sourceFile.platform == 11) + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte b0 = image_data[i * 2]; + image_data[i * 2] = image_data[i * 2 + 1]; + image_data[i * 2 + 1] = b0; + } + } + + dwFlags2 = 0x40; + dwRGBBitCount = 0x10; + dwRBitMask = 0xF800; + dwGBitMask = 0x7E0; + dwBBitMask = 0x1F; + dwABitMask = 0x0; + break; + } + case 10: //DXT1 + { + if (sourceFile.platform == 11) //X360 only, PS3 not + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte b0 = image_data[i * 2]; + image_data[i * 2] = image_data[i * 2 + 1]; + image_data[i * 2 + 1] = b0; + } + } + + if (m_MipMap) { dwPitchOrLinearSize = m_Height * m_Width / 2; } + dwFlags2 = 0x4; + dwFourCC = 0x31545844; + dwRGBBitCount = 0x0; + dwRBitMask = 0x0; + dwGBitMask = 0x0; + dwBBitMask = 0x0; + dwABitMask = 0x0; + break; + } + case 12: //DXT5 + { + if (sourceFile.platform == 11) //X360, PS3 not + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte b0 = image_data[i * 2]; + image_data[i * 2] = image_data[i * 2 + 1]; + image_data[i * 2 + 1] = b0; + } + } + + if (m_MipMap) { dwPitchOrLinearSize = m_Height * m_Width / 2; } + dwFlags2 = 0x4; + dwFourCC = 0x35545844; + dwRGBBitCount = 0x0; + dwRBitMask = 0x0; + dwGBitMask = 0x0; + dwBBitMask = 0x0; + dwABitMask = 0x0; + break; + } + case 13: //R4G4B4A4, iOS (only?) + { + for (int i = 0; i < (image_data_size / 2); i++) + { + byte[] argb = BitConverter.GetBytes((BitConverter.ToInt32((new byte[4] { image_data[i * 2], image_data[i * 2 + 1], image_data[i * 2], image_data[i * 2 + 1] }), 0)) >> 4); + image_data[i * 2] = argb[0]; + image_data[i * 2 + 1] = argb[1]; + } + + dwFlags2 = 0x41; + dwRGBBitCount = 0x10; + dwRBitMask = 0xF00; + dwGBitMask = 0xF0; + dwBBitMask = 0xF; + dwABitMask = 0xF000; + break; + } + case 30: //PVRTC_RGB2 + { + pvrPixelFormat = 0x0; + break; + } + case 31: //PVRTC_RGBA2 + { + pvrPixelFormat = 0x1; + break; + } + case 32: //PVRTC_RGB4 + { + pvrPixelFormat = 0x2; + break; + } + case 33: //PVRTC_RGBA4 + { + pvrPixelFormat = 0x3; + break; + } + case 34: //ETC_RGB4 + { + pvrPixelFormat = 0x16; + break; + } + } + } + } + } +} diff --git a/Unity Studio/Transform.cs b/Unity Studio/Transform.cs new file mode 100644 index 0000000..13e91ec --- /dev/null +++ b/Unity Studio/Transform.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Unity_Studio +{ + public class Transform + { + public PPtr m_GameObject = new PPtr(); + public float[] m_LocalRotation; + public float[] m_LocalPosition; + public float[] m_LocalScale; + public List m_Children = new List(); + public PPtr m_Father = new PPtr();//can be transform or type 224 (as seen in Minions) + + public Transform(AssetPreloadData preloadData) + { + var sourceFile = preloadData.sourceFile; + var a_Stream = preloadData.sourceFile.a_Stream; + a_Stream.Position = preloadData.Offset; + + if (sourceFile.platform == -2) + { + uint m_ObjectHideFlags = a_Stream.ReadUInt32(); + PPtr m_PrefabParentObject = sourceFile.ReadPPtr(); + PPtr m_PrefabInternal = sourceFile.ReadPPtr(); + } + + m_GameObject = sourceFile.ReadPPtr(); + m_LocalRotation = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + m_LocalPosition = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + m_LocalScale = new float[] { a_Stream.ReadSingle(), a_Stream.ReadSingle(), a_Stream.ReadSingle() }; + int m_ChildrenCount = a_Stream.ReadInt32(); + for (int j = 0; j < m_ChildrenCount; j++) + { + m_Children.Add(sourceFile.ReadPPtr()); + } + m_Father = sourceFile.ReadPPtr(); + } + } +} diff --git a/Unity Studio/Unity Studio.csproj b/Unity Studio/Unity Studio.csproj new file mode 100644 index 0000000..a250a5d --- /dev/null +++ b/Unity Studio/Unity Studio.csproj @@ -0,0 +1,233 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {24551E2D-E9B6-4CD6-8F2A-D9F4A13E7853} + WinExe + Properties + Unity_Studio + Unity Studio + v4.0 + + + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + unity.ico + + + + + + ..\..\..\..\..\Tools\LIBRARIES\csharp-half-code-2\System.Half\bin\Release\System.Half.dll + + + + + + + + + + + + False + ..\..\..\..\..\Tools\SDK\taoframework-2.1.0\taoframework-2.1.0\bin\Tao.DevIl.dll + + + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Code + + + Form + + + AboutBox.cs + + + + + + + + + Form + + + FBXExport.cs + + + + Component + + + + + + + + + + + + + + + + + + + + Form + + + UnityStudioForm.cs + + + + + + AboutBox.cs + Designer + + + FBXExport.cs + + + UnityStudioForm.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + False + Microsoft .NET Framework 4 Client Profile %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + False + Windows Installer 4.5 + true + + + + + + + + \ No newline at end of file diff --git a/Unity Studio/UnityStudioForm.Designer.cs b/Unity Studio/UnityStudioForm.Designer.cs new file mode 100644 index 0000000..0dd3498 --- /dev/null +++ b/Unity Studio/UnityStudioForm.Designer.cs @@ -0,0 +1,782 @@ +namespace Unity_Studio +{ + partial class UnityStudioForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UnityStudioForm)); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.loadFileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.loadFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.extractBundleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.extractFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.uniqueNames = new System.Windows.Forms.ToolStripMenuItem(); + this.enablePreview = new System.Windows.Forms.ToolStripMenuItem(); + this.displayInfo = new System.Windows.Forms.ToolStripMenuItem(); + this.openAfterExport = new System.Windows.Forms.ToolStripMenuItem(); + this.assetGroupOptions = new System.Windows.Forms.ToolStripComboBox(); + this.showExpOpt = new System.Windows.Forms.ToolStripMenuItem(); + this.exportToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportAll3DMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportSelected3DMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.exportAllAssetsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportSelectedAssetsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.exportFilteredAssetsMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.helpToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.aboutToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.treeSearch = new System.Windows.Forms.TextBox(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.assetListView = new System.Windows.Forms.ListView(); + this.columnHeaderName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeaderSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.listSearch = new System.Windows.Forms.TextBox(); + this.progressbarPanel = new System.Windows.Forms.Panel(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.previewPanel = new System.Windows.Forms.Panel(); + this.assetInfoLabel = new System.Windows.Forms.Label(); + this.FMODpanel = new System.Windows.Forms.Panel(); + this.FMODinfoLabel = new System.Windows.Forms.Label(); + this.FMODtimerLabel = new System.Windows.Forms.Label(); + this.FMODstatusLabel = new System.Windows.Forms.Label(); + this.FMODprogressBar = new System.Windows.Forms.TrackBar(); + this.FMODvolumeBar = new System.Windows.Forms.TrackBar(); + this.FMODloopButton = new System.Windows.Forms.CheckBox(); + this.FMODstopButton = new System.Windows.Forms.Button(); + this.FMODpauseButton = new System.Windows.Forms.Button(); + this.FMODplayButton = new System.Windows.Forms.Button(); + this.fontPreviewBox = new System.Windows.Forms.RichTextBox(); + this.textPreviewBox = new System.Windows.Forms.TextBox(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.timer = new System.Windows.Forms.Timer(this.components); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.openFolderDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.saveFolderDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.treeTip = new System.Windows.Forms.ToolTip(this.components); + this.sceneTreeView = new Unity_Studio.GOHierarchy(); + this.menuStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.progressbarPanel.SuspendLayout(); + this.previewPanel.SuspendLayout(); + this.FMODpanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).BeginInit(); + this.statusStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem, + this.optionsToolStripMenuItem, + this.exportToolStripMenuItem, + this.helpToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(1264, 24); + this.menuStrip1.TabIndex = 0; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.loadFileToolStripMenuItem, + this.loadFolderToolStripMenuItem, + this.toolStripMenuItem1, + this.extractBundleToolStripMenuItem, + this.extractFolderToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // loadFileToolStripMenuItem + // + this.loadFileToolStripMenuItem.Name = "loadFileToolStripMenuItem"; + this.loadFileToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.loadFileToolStripMenuItem.Text = "Load file..."; + this.loadFileToolStripMenuItem.Click += new System.EventHandler(this.loadFile_Click); + // + // loadFolderToolStripMenuItem + // + this.loadFolderToolStripMenuItem.Name = "loadFolderToolStripMenuItem"; + this.loadFolderToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.loadFolderToolStripMenuItem.Text = "Load folder..."; + this.loadFolderToolStripMenuItem.Click += new System.EventHandler(this.loadFolder_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(155, 6); + // + // extractBundleToolStripMenuItem + // + this.extractBundleToolStripMenuItem.Name = "extractBundleToolStripMenuItem"; + this.extractBundleToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.extractBundleToolStripMenuItem.Text = "Extract bundle..."; + this.extractBundleToolStripMenuItem.Click += new System.EventHandler(this.extractBundleToolStripMenuItem_Click); + // + // extractFolderToolStripMenuItem + // + this.extractFolderToolStripMenuItem.Name = "extractFolderToolStripMenuItem"; + this.extractFolderToolStripMenuItem.Size = new System.Drawing.Size(158, 22); + this.extractFolderToolStripMenuItem.Text = "Extract folder..."; + this.extractFolderToolStripMenuItem.Click += new System.EventHandler(this.extractFolderToolStripMenuItem_Click); + // + // optionsToolStripMenuItem + // + this.optionsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.uniqueNames, + this.enablePreview, + this.displayInfo, + this.openAfterExport, + this.assetGroupOptions, + this.showExpOpt}); + this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; + this.optionsToolStripMenuItem.Size = new System.Drawing.Size(61, 20); + this.optionsToolStripMenuItem.Text = "Options"; + // + // uniqueNames + // + this.uniqueNames.Checked = true; + this.uniqueNames.CheckOnClick = true; + this.uniqueNames.CheckState = System.Windows.Forms.CheckState.Checked; + this.uniqueNames.Name = "uniqueNames"; + this.uniqueNames.Size = new System.Drawing.Size(252, 22); + this.uniqueNames.Text = "Unique exported filenames"; + this.uniqueNames.ToolTipText = resources.GetString("uniqueNames.ToolTipText"); + this.uniqueNames.CheckedChanged += new System.EventHandler(this.MenuItem_CheckedChanged); + // + // enablePreview + // + this.enablePreview.Checked = true; + this.enablePreview.CheckOnClick = true; + this.enablePreview.CheckState = System.Windows.Forms.CheckState.Checked; + this.enablePreview.Name = "enablePreview"; + this.enablePreview.Size = new System.Drawing.Size(252, 22); + this.enablePreview.Text = "Enable preview"; + this.enablePreview.ToolTipText = "Toggle the loading and preview of readable assets, such as images, sounds, text, " + + "etc.\r\nDisable preview if you have performance or compatibility issues."; + this.enablePreview.CheckedChanged += new System.EventHandler(this.enablePreview_Check); + // + // displayInfo + // + this.displayInfo.Checked = true; + this.displayInfo.CheckOnClick = true; + this.displayInfo.CheckState = System.Windows.Forms.CheckState.Checked; + this.displayInfo.Name = "displayInfo"; + this.displayInfo.Size = new System.Drawing.Size(252, 22); + this.displayInfo.Text = "Display asset infromation"; + this.displayInfo.ToolTipText = "Toggle the overlay that shows information about each asset, eg. image size, forma" + + "t, audio bitrate, etc."; + this.displayInfo.CheckedChanged += new System.EventHandler(this.displayAssetInfo_Check); + // + // openAfterExport + // + this.openAfterExport.Checked = true; + this.openAfterExport.CheckOnClick = true; + this.openAfterExport.CheckState = System.Windows.Forms.CheckState.Checked; + this.openAfterExport.Name = "openAfterExport"; + this.openAfterExport.Size = new System.Drawing.Size(252, 22); + this.openAfterExport.Text = "Open file/folder after export"; + this.openAfterExport.CheckedChanged += new System.EventHandler(this.MenuItem_CheckedChanged); + // + // assetGroupOptions + // + this.assetGroupOptions.Items.AddRange(new object[] { + "Group exported assets by type", + "Group exported assets by source file", + "Do not group exported assets"}); + this.assetGroupOptions.Name = "assetGroupOptions"; + this.assetGroupOptions.Size = new System.Drawing.Size(192, 23); + this.assetGroupOptions.SelectedIndexChanged += new System.EventHandler(this.assetGroupOptions_SelectedIndexChanged); + // + // showExpOpt + // + this.showExpOpt.Name = "showExpOpt"; + this.showExpOpt.Size = new System.Drawing.Size(252, 22); + this.showExpOpt.Text = "Export options..."; + this.showExpOpt.Click += new System.EventHandler(this.showExpOpt_Click); + // + // exportToolStripMenuItem + // + this.exportToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.exportAll3DMenuItem, + this.exportSelected3DMenuItem, + this.toolStripSeparator1, + this.exportAllAssetsMenuItem, + this.exportSelectedAssetsMenuItem, + this.exportFilteredAssetsMenuItem}); + this.exportToolStripMenuItem.Name = "exportToolStripMenuItem"; + this.exportToolStripMenuItem.Size = new System.Drawing.Size(52, 20); + this.exportToolStripMenuItem.Text = "Export"; + // + // exportAll3DMenuItem + // + this.exportAll3DMenuItem.Name = "exportAll3DMenuItem"; + this.exportAll3DMenuItem.Size = new System.Drawing.Size(176, 22); + this.exportAll3DMenuItem.Text = "All 3D objects"; + this.exportAll3DMenuItem.Click += new System.EventHandler(this.Export3DObjects_Click); + // + // exportSelected3DMenuItem + // + this.exportSelected3DMenuItem.Name = "exportSelected3DMenuItem"; + this.exportSelected3DMenuItem.Size = new System.Drawing.Size(176, 22); + this.exportSelected3DMenuItem.Text = "Selected 3D objects"; + this.exportSelected3DMenuItem.Click += new System.EventHandler(this.Export3DObjects_Click); + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(173, 6); + // + // exportAllAssetsMenuItem + // + this.exportAllAssetsMenuItem.Name = "exportAllAssetsMenuItem"; + this.exportAllAssetsMenuItem.Size = new System.Drawing.Size(176, 22); + this.exportAllAssetsMenuItem.Text = "All assets"; + this.exportAllAssetsMenuItem.Click += new System.EventHandler(this.ExportAssets_Click); + // + // exportSelectedAssetsMenuItem + // + this.exportSelectedAssetsMenuItem.Name = "exportSelectedAssetsMenuItem"; + this.exportSelectedAssetsMenuItem.Size = new System.Drawing.Size(176, 22); + this.exportSelectedAssetsMenuItem.Text = "Selected assets"; + this.exportSelectedAssetsMenuItem.Click += new System.EventHandler(this.ExportAssets_Click); + // + // exportFilteredAssetsMenuItem + // + this.exportFilteredAssetsMenuItem.Name = "exportFilteredAssetsMenuItem"; + this.exportFilteredAssetsMenuItem.Size = new System.Drawing.Size(176, 22); + this.exportFilteredAssetsMenuItem.Text = "Filtered assets"; + this.exportFilteredAssetsMenuItem.Click += new System.EventHandler(this.ExportAssets_Click); + // + // helpToolStripMenuItem + // + this.helpToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.aboutToolStripMenuItem}); + this.helpToolStripMenuItem.Name = "helpToolStripMenuItem"; + this.helpToolStripMenuItem.Size = new System.Drawing.Size(44, 20); + this.helpToolStripMenuItem.Text = "Help"; + // + // aboutToolStripMenuItem + // + this.aboutToolStripMenuItem.Name = "aboutToolStripMenuItem"; + this.aboutToolStripMenuItem.Size = new System.Drawing.Size(107, 22); + this.aboutToolStripMenuItem.Text = "About"; + this.aboutToolStripMenuItem.Click += new System.EventHandler(this.aboutToolStripMenuItem_Click); + // + // splitContainer1 + // + this.splitContainer1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 24); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.tabControl1); + this.splitContainer1.Panel1.Controls.Add(this.progressbarPanel); + this.splitContainer1.Panel1MinSize = 200; + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.previewPanel); + this.splitContainer1.Panel2.Controls.Add(this.statusStrip1); + this.splitContainer1.Panel2MinSize = 400; + this.splitContainer1.Size = new System.Drawing.Size(1264, 658); + this.splitContainer1.SplitterDistance = 420; + this.splitContainer1.TabIndex = 2; + this.splitContainer1.TabStop = false; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + this.splitContainer1.Resize += new System.EventHandler(this.splitContainer1_Resize); + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 0); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.Padding = new System.Drawing.Point(17, 3); + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(418, 634); + this.tabControl1.SizeMode = System.Windows.Forms.TabSizeMode.Fixed; + this.tabControl1.TabIndex = 0; + this.tabControl1.Selected += new System.Windows.Forms.TabControlEventHandler(this.tabPageSelected); + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.sceneTreeView); + this.tabPage1.Controls.Add(this.treeSearch); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Size = new System.Drawing.Size(410, 608); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Scene Hierarchy"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // treeSearch + // + this.treeSearch.Dock = System.Windows.Forms.DockStyle.Top; + this.treeSearch.ForeColor = System.Drawing.SystemColors.GrayText; + this.treeSearch.Location = new System.Drawing.Point(0, 0); + this.treeSearch.Name = "treeSearch"; + this.treeSearch.Size = new System.Drawing.Size(410, 20); + this.treeSearch.TabIndex = 0; + this.treeSearch.Text = " Search "; + this.treeSearch.Enter += new System.EventHandler(this.treeSearch_Enter); + this.treeSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeSearch_KeyDown); + this.treeSearch.Leave += new System.EventHandler(this.treeSearch_Leave); + this.treeSearch.MouseEnter += new System.EventHandler(this.treeSearch_MouseEnter); + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.assetListView); + this.tabPage2.Controls.Add(this.listSearch); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Size = new System.Drawing.Size(410, 608); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Asset List"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // assetListView + // + this.assetListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeaderName, + this.columnHeaderType, + this.columnHeaderSize}); + this.assetListView.Dock = System.Windows.Forms.DockStyle.Fill; + this.assetListView.FullRowSelect = true; + this.assetListView.GridLines = true; + this.assetListView.HideSelection = false; + this.assetListView.LabelEdit = true; + this.assetListView.Location = new System.Drawing.Point(0, 20); + this.assetListView.Name = "assetListView"; + this.assetListView.Size = new System.Drawing.Size(410, 588); + this.assetListView.TabIndex = 1; + this.assetListView.UseCompatibleStateImageBehavior = false; + this.assetListView.View = System.Windows.Forms.View.Details; + this.assetListView.VirtualMode = true; + this.assetListView.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.assetListView_ColumnClick); + this.assetListView.ItemSelectionChanged += new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(this.selectAsset); + this.assetListView.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.assetListView_RetrieveVirtualItem); + // + // columnHeaderName + // + this.columnHeaderName.Text = "Name"; + this.columnHeaderName.Width = 240; + // + // columnHeaderType + // + this.columnHeaderType.Text = "Type"; + this.columnHeaderType.Width = 88; + // + // columnHeaderSize + // + this.columnHeaderSize.Text = "Size"; + // + // listSearch + // + this.listSearch.Dock = System.Windows.Forms.DockStyle.Top; + this.listSearch.ForeColor = System.Drawing.SystemColors.GrayText; + this.listSearch.Location = new System.Drawing.Point(0, 0); + this.listSearch.Name = "listSearch"; + this.listSearch.Size = new System.Drawing.Size(410, 20); + this.listSearch.TabIndex = 0; + this.listSearch.Text = " Filter "; + this.listSearch.TextChanged += new System.EventHandler(this.ListSearchTextChanged); + this.listSearch.Enter += new System.EventHandler(this.listSearch_Enter); + this.listSearch.Leave += new System.EventHandler(this.listSearch_Leave); + // + // progressbarPanel + // + this.progressbarPanel.Controls.Add(this.progressBar1); + this.progressbarPanel.Dock = System.Windows.Forms.DockStyle.Bottom; + this.progressbarPanel.Location = new System.Drawing.Point(0, 634); + this.progressbarPanel.Name = "progressbarPanel"; + this.progressbarPanel.Padding = new System.Windows.Forms.Padding(1, 3, 1, 1); + this.progressbarPanel.Size = new System.Drawing.Size(418, 22); + this.progressbarPanel.TabIndex = 2; + // + // progressBar1 + // + this.progressBar1.Dock = System.Windows.Forms.DockStyle.Fill; + this.progressBar1.Location = new System.Drawing.Point(1, 3); + this.progressBar1.Name = "progressBar1"; + this.progressBar1.Size = new System.Drawing.Size(416, 18); + this.progressBar1.Step = 1; + this.progressBar1.TabIndex = 1; + // + // previewPanel + // + this.previewPanel.BackColor = System.Drawing.SystemColors.ControlDark; + this.previewPanel.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("previewPanel.BackgroundImage"))); + this.previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + this.previewPanel.Controls.Add(this.assetInfoLabel); + this.previewPanel.Controls.Add(this.FMODpanel); + this.previewPanel.Controls.Add(this.fontPreviewBox); + this.previewPanel.Controls.Add(this.textPreviewBox); + this.previewPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.previewPanel.Location = new System.Drawing.Point(0, 0); + this.previewPanel.Name = "previewPanel"; + this.previewPanel.Size = new System.Drawing.Size(838, 634); + this.previewPanel.TabIndex = 1; + // + // assetInfoLabel + // + this.assetInfoLabel.AutoSize = true; + this.assetInfoLabel.BackColor = System.Drawing.Color.Transparent; + this.assetInfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.assetInfoLabel.Location = new System.Drawing.Point(4, 8); + this.assetInfoLabel.Name = "assetInfoLabel"; + this.assetInfoLabel.Size = new System.Drawing.Size(0, 13); + this.assetInfoLabel.TabIndex = 0; + // + // FMODpanel + // + this.FMODpanel.Anchor = System.Windows.Forms.AnchorStyles.None; + this.FMODpanel.BackColor = System.Drawing.SystemColors.ControlDark; + this.FMODpanel.Controls.Add(this.FMODinfoLabel); + this.FMODpanel.Controls.Add(this.FMODtimerLabel); + this.FMODpanel.Controls.Add(this.FMODstatusLabel); + this.FMODpanel.Controls.Add(this.FMODprogressBar); + this.FMODpanel.Controls.Add(this.FMODvolumeBar); + this.FMODpanel.Controls.Add(this.FMODloopButton); + this.FMODpanel.Controls.Add(this.FMODstopButton); + this.FMODpanel.Controls.Add(this.FMODpauseButton); + this.FMODpanel.Controls.Add(this.FMODplayButton); + this.FMODpanel.Location = new System.Drawing.Point(220, 209); + this.FMODpanel.Name = "FMODpanel"; + this.FMODpanel.Size = new System.Drawing.Size(400, 200); + this.FMODpanel.TabIndex = 2; + this.FMODpanel.Visible = false; + // + // FMODinfoLabel + // + this.FMODinfoLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.FMODinfoLabel.Location = new System.Drawing.Point(82, 54); + this.FMODinfoLabel.Name = "FMODinfoLabel"; + this.FMODinfoLabel.Size = new System.Drawing.Size(176, 13); + this.FMODinfoLabel.TabIndex = 8; + // + // FMODtimerLabel + // + this.FMODtimerLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.FMODtimerLabel.Location = new System.Drawing.Point(264, 54); + this.FMODtimerLabel.Name = "FMODtimerLabel"; + this.FMODtimerLabel.Size = new System.Drawing.Size(99, 13); + this.FMODtimerLabel.TabIndex = 7; + this.FMODtimerLabel.Text = "0:00.0 / 0:00.0"; + this.FMODtimerLabel.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // FMODstatusLabel + // + this.FMODstatusLabel.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.FMODstatusLabel.Location = new System.Drawing.Point(26, 54); + this.FMODstatusLabel.Name = "FMODstatusLabel"; + this.FMODstatusLabel.Size = new System.Drawing.Size(50, 13); + this.FMODstatusLabel.TabIndex = 6; + this.FMODstatusLabel.Text = "Stopped"; + // + // FMODprogressBar + // + this.FMODprogressBar.AutoSize = false; + this.FMODprogressBar.Location = new System.Drawing.Point(29, 73); + this.FMODprogressBar.Maximum = 1000; + this.FMODprogressBar.Name = "FMODprogressBar"; + this.FMODprogressBar.Size = new System.Drawing.Size(348, 24); + this.FMODprogressBar.TabIndex = 5; + this.FMODprogressBar.TickStyle = System.Windows.Forms.TickStyle.None; + this.FMODprogressBar.Scroll += new System.EventHandler(this.FMODprogressBar_Scroll); + this.FMODprogressBar.MouseDown += new System.Windows.Forms.MouseEventHandler(this.FMODprogressBar_MouseDown); + this.FMODprogressBar.MouseUp += new System.Windows.Forms.MouseEventHandler(this.FMODprogressBar_MouseUp); + // + // FMODvolumeBar + // + this.FMODvolumeBar.LargeChange = 2; + this.FMODvolumeBar.Location = new System.Drawing.Point(273, 103); + this.FMODvolumeBar.Name = "FMODvolumeBar"; + this.FMODvolumeBar.Size = new System.Drawing.Size(104, 45); + this.FMODvolumeBar.TabIndex = 4; + this.FMODvolumeBar.TickStyle = System.Windows.Forms.TickStyle.Both; + this.FMODvolumeBar.Value = 8; + this.FMODvolumeBar.ValueChanged += new System.EventHandler(this.FMODvolumeBar_ValueChanged); + // + // FMODloopButton + // + this.FMODloopButton.Appearance = System.Windows.Forms.Appearance.Button; + this.FMODloopButton.Location = new System.Drawing.Point(212, 103); + this.FMODloopButton.Name = "FMODloopButton"; + this.FMODloopButton.Size = new System.Drawing.Size(55, 45); + this.FMODloopButton.TabIndex = 3; + this.FMODloopButton.Text = "Loop"; + this.FMODloopButton.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + this.FMODloopButton.UseVisualStyleBackColor = true; + this.FMODloopButton.CheckedChanged += new System.EventHandler(this.FMODloopButton_CheckedChanged); + // + // FMODstopButton + // + this.FMODstopButton.Location = new System.Drawing.Point(151, 103); + this.FMODstopButton.Name = "FMODstopButton"; + this.FMODstopButton.Size = new System.Drawing.Size(55, 45); + this.FMODstopButton.TabIndex = 2; + this.FMODstopButton.Text = "Stop"; + this.FMODstopButton.UseVisualStyleBackColor = true; + this.FMODstopButton.Click += new System.EventHandler(this.FMODstopButton_Click); + // + // FMODpauseButton + // + this.FMODpauseButton.Location = new System.Drawing.Point(90, 103); + this.FMODpauseButton.Name = "FMODpauseButton"; + this.FMODpauseButton.Size = new System.Drawing.Size(55, 45); + this.FMODpauseButton.TabIndex = 1; + this.FMODpauseButton.Text = "Pause"; + this.FMODpauseButton.UseVisualStyleBackColor = true; + this.FMODpauseButton.Click += new System.EventHandler(this.FMODpauseButton_Click); + // + // FMODplayButton + // + this.FMODplayButton.Location = new System.Drawing.Point(29, 103); + this.FMODplayButton.Name = "FMODplayButton"; + this.FMODplayButton.Size = new System.Drawing.Size(55, 45); + this.FMODplayButton.TabIndex = 0; + this.FMODplayButton.Text = "Play"; + this.FMODplayButton.UseVisualStyleBackColor = true; + this.FMODplayButton.Click += new System.EventHandler(this.FMODplayButton_Click); + // + // fontPreviewBox + // + this.fontPreviewBox.BackColor = System.Drawing.SystemColors.ControlLightLight; + this.fontPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.fontPreviewBox.Location = new System.Drawing.Point(0, 0); + this.fontPreviewBox.Name = "fontPreviewBox"; + this.fontPreviewBox.ReadOnly = true; + this.fontPreviewBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + this.fontPreviewBox.Size = new System.Drawing.Size(838, 634); + this.fontPreviewBox.TabIndex = 0; + this.fontPreviewBox.Text = resources.GetString("fontPreviewBox.Text"); + this.fontPreviewBox.Visible = false; + this.fontPreviewBox.WordWrap = false; + // + // textPreviewBox + // + this.textPreviewBox.Dock = System.Windows.Forms.DockStyle.Fill; + this.textPreviewBox.Font = new System.Drawing.Font("Consolas", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textPreviewBox.Location = new System.Drawing.Point(0, 0); + this.textPreviewBox.Multiline = true; + this.textPreviewBox.Name = "textPreviewBox"; + this.textPreviewBox.ReadOnly = true; + this.textPreviewBox.ScrollBars = System.Windows.Forms.ScrollBars.Both; + this.textPreviewBox.Size = new System.Drawing.Size(838, 634); + this.textPreviewBox.TabIndex = 2; + this.textPreviewBox.Visible = false; + this.textPreviewBox.WordWrap = false; + // + // statusStrip1 + // + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1}); + this.statusStrip1.Location = new System.Drawing.Point(0, 634); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(838, 22); + this.statusStrip1.TabIndex = 2; + this.statusStrip1.Text = "statusStrip1"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text; + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(823, 17); + this.toolStripStatusLabel1.Spring = true; + this.toolStripStatusLabel1.Text = "Ready to go"; + this.toolStripStatusLabel1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // timer + // + this.timer.Interval = 10; + this.timer.Tick += new System.EventHandler(this.timer_Tick); + // + // openFileDialog1 + // + this.openFileDialog1.Filter = "Unity asset files|level*; mainData; CustomAssetBundle-*; CAB-*; BuildPlayer-*; *." + + "assets; *.sharedAssets|Unity bundle files|*.unity3d; *.unity3d.lz4; *.assetbundle; *.bundle; *." + + "bytes"; + this.openFileDialog1.Multiselect = true; + this.openFileDialog1.RestoreDirectory = true; + // + // openFolderDialog1 + // + this.openFolderDialog1.AddExtension = false; + this.openFolderDialog1.CheckFileExists = false; + this.openFolderDialog1.FileName = "Select folder"; + this.openFolderDialog1.Filter = "Folders|*."; + this.openFolderDialog1.RestoreDirectory = true; + this.openFolderDialog1.Title = "Browse for folder"; + // + // saveFileDialog1 + // + this.saveFileDialog1.Filter = "FBX file|*.fbx|Collada|*.dae"; + this.saveFileDialog1.RestoreDirectory = true; + // + // saveFolderDialog1 + // + this.saveFolderDialog1.AddExtension = false; + this.saveFolderDialog1.FileName = "Select folder or write folder name to create"; + this.saveFolderDialog1.Filter = "Folders|*."; + this.saveFolderDialog1.RestoreDirectory = true; + this.saveFolderDialog1.Title = "Browse for folder"; + // + // sceneTreeView + // + this.sceneTreeView.CheckBoxes = true; + this.sceneTreeView.Dock = System.Windows.Forms.DockStyle.Fill; + this.sceneTreeView.HideSelection = false; + this.sceneTreeView.Location = new System.Drawing.Point(0, 20); + this.sceneTreeView.Name = "sceneTreeView"; + this.sceneTreeView.Size = new System.Drawing.Size(410, 588); + this.sceneTreeView.TabIndex = 1; + this.sceneTreeView.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.sceneTreeView_AfterCheck); + // + // UnityStudioForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1264, 682); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.menuStrip1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip1; + this.MinimumSize = new System.Drawing.Size(620, 400); + this.Name = "UnityStudioForm"; + this.Text = "Unity Studio"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.UnityStudioForm_FormClosing); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.tabPage2.PerformLayout(); + this.progressbarPanel.ResumeLayout(false); + this.previewPanel.ResumeLayout(false); + this.previewPanel.PerformLayout(); + this.FMODpanel.ResumeLayout(false); + this.FMODpanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.FMODprogressBar)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.FMODvolumeBar)).EndInit(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.TextBox treeSearch; + private System.Windows.Forms.TextBox listSearch; + private System.Windows.Forms.ToolStripMenuItem loadFileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem loadFolderToolStripMenuItem; + private System.Windows.Forms.ListView assetListView; + private System.Windows.Forms.ColumnHeader columnHeaderName; + private System.Windows.Forms.ColumnHeader columnHeaderSize; + private System.Windows.Forms.ColumnHeader columnHeaderType; + private System.Windows.Forms.ToolStripMenuItem exportToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportAllAssetsMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportSelectedAssetsMenuItem; + private System.Windows.Forms.Panel previewPanel; + private System.Windows.Forms.ProgressBar progressBar1; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.Panel progressbarPanel; + private System.Windows.Forms.ToolStripMenuItem exportFilteredAssetsMenuItem; + private System.Windows.Forms.ToolStripMenuItem helpToolStripMenuItem; + private System.Windows.Forms.Label assetInfoLabel; + private System.Windows.Forms.TextBox textPreviewBox; + private System.Windows.Forms.RichTextBox fontPreviewBox; + private System.Windows.Forms.Panel FMODpanel; + private System.Windows.Forms.TrackBar FMODvolumeBar; + private System.Windows.Forms.CheckBox FMODloopButton; + private System.Windows.Forms.Button FMODstopButton; + private System.Windows.Forms.Button FMODpauseButton; + private System.Windows.Forms.Button FMODplayButton; + private System.Windows.Forms.TrackBar FMODprogressBar; + private System.Windows.Forms.Label FMODstatusLabel; + private System.Windows.Forms.Label FMODtimerLabel; + private System.Windows.Forms.Label FMODinfoLabel; + private System.Windows.Forms.Timer timer; + private System.Windows.Forms.ToolStripMenuItem aboutToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem uniqueNames; + private System.Windows.Forms.ToolStripMenuItem enablePreview; + private System.Windows.Forms.ToolStripMenuItem displayInfo; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem extractBundleToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem extractFolderToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportAll3DMenuItem; + private System.Windows.Forms.ToolStripMenuItem exportSelected3DMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.OpenFileDialog openFolderDialog1; + private System.Windows.Forms.SaveFileDialog saveFileDialog1; + private System.Windows.Forms.SaveFileDialog saveFolderDialog1; + private System.Windows.Forms.ToolStripComboBox assetGroupOptions; + private System.Windows.Forms.ToolStripMenuItem openAfterExport; + private System.Windows.Forms.ToolStripMenuItem showExpOpt; + private GOHierarchy sceneTreeView; + private System.Windows.Forms.ToolTip treeTip; + } +} + diff --git a/Unity Studio/UnityStudioForm.bak b/Unity Studio/UnityStudioForm.bak new file mode 100644 index 0000000..d2e0b63 --- /dev/null +++ b/Unity Studio/UnityStudioForm.bak @@ -0,0 +1,2817 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Drawing.Imaging; +using Tao.DevIl; + +//TODO: hashtable or dictionary instead of indices for assets +//when clicking a file show summary of asset contents +//create functions to parse exportable assets with bool switch to read data or not (for collect,p review and export) +//create custom ListViewItem class just like you did for TreeView and optimize loading, filtering and exporting +//Load parent nodes even if they are not selected to provide transformations? +//or at least connect to scene instead of missing node +//For extractign bundles, first check if file exists then decompress + +namespace Unity_Studio +{ + public partial class UnityStudioForm : Form + { + private List assetsfileList = new List(); + private List exportableAssets = new List(); //used to hold all listItems while the list is being filtered + private List visibleAssets = new List(); //used to build the listView + private AssetPreloadData lastSelectedItem = null; + private AssetPreloadData lastLoadedAsset = null; + //private AssetsFile mainDataFile = null; + private string mainPath = ""; + public string productName = ""; + + private FMOD.System system = null; + private FMOD.Sound sound = null; + private FMOD.Channel channel = null; + private FMOD.SoundGroup masterSoundGroup = null; + + private FMOD.MODE loopMode = FMOD.MODE.LOOP_OFF; + private uint FMODlenms = 0; + private float FMODVolume = 0.8f; + private float FMODfrequency; + + private Bitmap imageTexture = null; + + private bool isNameSorted = false; + private bool isTypeSorted = false; + private bool isSizeSorted = false; + + //return-to indices for tree search + private int lastAFile = 0; + private int lastGObject = 0; + private string defTSearch = "Search with ?* wildcards; Enter to expand each match, Ctrl+Enter to check all matches"; + + [DllImport("gdi32.dll")] + private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts); + + [DllImport("PVRTexLib.dll")] + private static extern void test(); + + + private void loadFile_Click(object sender, System.EventArgs e) + { + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + resetForm(); + mainPath = Path.GetDirectoryName(openFileDialog1.FileNames[0]); + + if (openFileDialog1.FilterIndex == 1) + { + MergeSplitAssets(mainPath); + + progressBar1.Value = 0; + progressBar1.Maximum = openFileDialog1.FileNames.Length; + + foreach (var filename in openFileDialog1.FileNames) + { + StatusStripUpdate("Loading " + Path.GetFileName(filename)); + LoadAssetsFile(filename); + } + } + else + { + progressBar1.Value = 0; + progressBar1.Maximum = openFileDialog1.FileNames.Length; + + foreach (var filename in openFileDialog1.FileNames) + { + LoadBundleFile(filename); + progressBar1.PerformStep(); + } + } + + BuildAssetStrucutres(); + } + } + + private void loadFolder_Click(object sender, System.EventArgs e) + { + List unityFiles = new List(); + /*FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog(); + + folderBrowserDialog1.Description = "Load all Unity assets from folder and subfolders"; + folderBrowserDialog1.ShowNewFolderButton = false; + //folderBrowserDialog1.SelectedPath = "E:\\Assets\\Unity"; + folderBrowserDialog1.SelectedPath = "E:\\Assets\\Unity\\WebPlayer\\Porsche\\92AAF1\\defaultGeometry";*/ + + if (openFolderDialog1.ShowDialog() == DialogResult.OK) + { + //mainPath = folderBrowserDialog1.SelectedPath; + mainPath = openFolderDialog1.FileName; + if (Path.GetFileName(mainPath) == "Select folder") + { mainPath = Path.GetDirectoryName(openFolderDialog1.FileName); } + + if (Directory.Exists(mainPath)) + { + resetForm(); + + //TODO find a way to read data directly instead of merging files + MergeSplitAssets(mainPath); + + string[] fileTypes = new string[7] { "maindata.", "level*.", "*.assets", "*.sharedAssets", "CustomAssetBundle-*.", "CAB-*.", "BuildPlayer-*." }; + foreach (var fileType in fileTypes) + { + string[] fileNames = Directory.GetFiles(mainPath, fileType, SearchOption.AllDirectories); + unityFiles.AddRange(fileNames); + } + + /*string[] levelFiles = Directory.GetFiles(mainPath, "level*", SearchOption.AllDirectories); + foreach (var fileName in levelFiles) + { + if (Path.GetExtension(fileName) == "") + { + unityFiles.Add(fileName); + } + }*/ + + progressBar1.Value = 0; + progressBar1.Maximum = unityFiles.Count; + + foreach (var fileName in unityFiles) + { + StatusStripUpdate("Loading " + Path.GetFileName(fileName)); + LoadAssetsFile(fileName); + } + + BuildAssetStrucutres(); + } + else { StatusStripUpdate("Selected path deos not exist."); } + } + } + + private void resetForm() + { + /*Properties.Settings.Default["uniqueNames"] = uniqueNamesMenuItem.Checked; + Properties.Settings.Default["enablePreview"] = enablePreviewMenuItem.Checked; + Properties.Settings.Default["displayInfo"] = displayAssetInfoMenuItem.Checked; + Properties.Settings.Default.Save();*/ + + assetsfileList.Clear(); + exportableAssets.Clear(); + visibleAssets.Clear(); + + sceneTreeView.Nodes.Clear(); + + assetListView.VirtualListSize = 0; + assetListView.Items.Clear(); + assetListView.Groups.Clear(); + + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + assetInfoLabel.Visible = false; + assetInfoLabel.Text = null; + textPreviewBox.Visible = false; + fontPreviewBox.Visible = false; + lastSelectedItem = null; + lastLoadedAsset = null; + + FMODinit(); + + } + + private void MergeSplitAssets(string dirPath) + { + string[] splitFiles = Directory.GetFiles(dirPath, "*.split0"); + foreach (var splitFile in splitFiles) + { + string destFile = Path.GetFileNameWithoutExtension(splitFile); + string destPath = Path.GetDirectoryName(splitFile) + "\\"; + if (!File.Exists(destPath + destFile)) + { + StatusStripUpdate("Merging " + destFile + " split files..."); + + string[] splitParts = Directory.GetFiles(destPath, destFile + ".split*"); + using (var destStream = File.Create(destPath + destFile)) + { + for (int i = 0; i < splitParts.Length; i++) + { + string splitPart = destPath + destFile + ".split" + i.ToString(); + using (var sourceStream = File.OpenRead(splitPart)) + sourceStream.CopyTo(destStream); // You can pass the buffer size as second argument. + } + } + } + } + } + + private void LoadAssetsFile(string fileName) + { + var loadedAssetsFile = assetsfileList.Find(aFile => aFile.filePath == fileName); + if (loadedAssetsFile == null) + { + //open file here and pass the stream to facilitate loading memory files + //also by keeping the stream as a property of AssetsFile, it can be used later on to read assets + AssetsFile assetsFile = new AssetsFile(fileName, new EndianStream(File.OpenRead(fileName), EndianType.BigEndian)); + //if (Path.GetFileName(fileName) == "mainData") { mainDataFile = assetsFile; } + + assetsfileList.Add(assetsFile); + #region for 2.6.x find mainData and get string version + if (assetsFile.fileGen == 6 && Path.GetFileName(fileName) != "mainData") + { + AssetsFile mainDataFile = assetsfileList.Find(aFile => aFile.filePath == Path.GetDirectoryName(fileName) + "\\mainData"); + if (mainDataFile != null) + { + assetsFile.m_Version = mainDataFile.m_Version; + assetsFile.version = mainDataFile.version; + assetsFile.buildType = mainDataFile.buildType; + } + else if (File.Exists(Path.GetDirectoryName(fileName) + "\\mainData")) + { + mainDataFile = new AssetsFile(Path.GetDirectoryName(fileName) + "\\mainData", new EndianStream(File.OpenRead(Path.GetDirectoryName(fileName) + "\\mainData"), EndianType.BigEndian)); + + assetsFile.m_Version = mainDataFile.m_Version; + assetsFile.version = mainDataFile.version; + assetsFile.buildType = mainDataFile.buildType; + } + } + #endregion + progressBar1.PerformStep(); + + foreach (var sharedFile in assetsFile.sharedAssetsList) + { + string sharedFilePath = Path.GetDirectoryName(fileName) + "\\" + sharedFile.fileName; + + //TODO add extra code to search for the shared file in case it doesn't exist in the main folder + //or if it exists or the path is incorrect + + //var loadedSharedFile = assetsfileList.Find(aFile => aFile.filePath == sharedFilePath); + var loadedSharedFile = assetsfileList.Find(aFile => aFile.filePath.EndsWith(Path.GetFileName(sharedFile.fileName))); + if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); } + else if (File.Exists(sharedFilePath)) + { + //progressBar1.Maximum += 1; + sharedFile.Index = assetsfileList.Count; + LoadAssetsFile(sharedFilePath); + } + } + + } + } + + private void LoadBundleFile(string bundleFileName) + { + StatusStripUpdate("Decompressing " + Path.GetFileName(bundleFileName) + "..."); + + using (BundleFile b_File = new BundleFile(bundleFileName)) + { + List b_assetsfileList = new List(); + + foreach (var memFile in b_File.MemoryAssetsFileList) //filter unity files + { + bool validAssetsFile = false; + switch (Path.GetExtension(memFile.fileName)) + { + case ".assets": + case ".sharedAssets": + validAssetsFile = true; + break; + case "": + if (memFile.fileName == "mainData" || Regex.IsMatch(memFile.fileName, "level.*?") || Regex.IsMatch(memFile.fileName, "CustomAssetBundle-.*?") || Regex.IsMatch(memFile.fileName, "CAB-.*?") || Regex.IsMatch(memFile.fileName, "BuildPlayer-.*?")) { validAssetsFile = true; } + break; + } + + if (validAssetsFile) + { + StatusStripUpdate("Loading " + memFile.fileName); + memFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + memFile.fileName; //add path for extract location + + AssetsFile assetsFile = new AssetsFile(memFile.fileName, new EndianStream(memFile.memStream, EndianType.BigEndian)); + if (assetsFile.fileGen == 6 && Path.GetFileName(bundleFileName) != "mainData") //2.6.x and earlier don't have a string version before the preload table + { + //make use of the bundle file version + assetsFile.m_Version = b_File.ver3; + assetsFile.version = Array.ConvertAll((b_File.ver3.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)), int.Parse); + assetsFile.buildType = b_File.ver3.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); + } + + b_assetsfileList.Add(assetsFile); + } + else + { + memFile.memStream.Close(); + } + } + + assetsfileList.AddRange(b_assetsfileList);//will the streams still be available for reading data? + + foreach (var assetsFile in b_assetsfileList) + { + foreach (var sharedFile in assetsFile.sharedAssetsList) + { + sharedFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + sharedFile.fileName; + var loadedSharedFile = b_assetsfileList.Find(aFile => aFile.filePath == sharedFile.fileName); + if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); } + } + } + } + } + + + private void extractBundleToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog openBundleDialog = new OpenFileDialog(); + openBundleDialog.Filter = "Unity bundle files|*.unity3d; *.assetbundle; *.bundle; *.bytes|All files (use at your own risk!)|*.*"; + openBundleDialog.FilterIndex = 1; + openBundleDialog.RestoreDirectory = true; + openBundleDialog.Multiselect = true; + + if (openBundleDialog.ShowDialog() == DialogResult.OK) + { + int extractedCount = extractBundleFile(openBundleDialog.FileName); + + StatusStripUpdate("Finished extracting " + extractedCount.ToString() + " files."); + } + } + + private void extractFolderToolStripMenuItem_Click(object sender, EventArgs e) + { + int extractedCount = 0; + List bundleFiles = new List(); + FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog(); + + folderBrowserDialog1.Description = "Extract all Unity bundles from folder and subfolders"; + folderBrowserDialog1.ShowNewFolderButton = false; + + if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) + { + string startPath = folderBrowserDialog1.SelectedPath; + + string[] fileTypes = new string[4] { "*.unity3d", "*.assetbundle-*", "*.bundle", "*.bytes" }; + foreach (var fileType in fileTypes) + { + string[] fileNames = Directory.GetFiles(startPath, fileType, SearchOption.AllDirectories); + bundleFiles.AddRange(fileNames); + } + + foreach (var fileName in bundleFiles) + { + extractedCount += extractBundleFile(fileName); + } + + StatusStripUpdate("Finished extracting " + extractedCount.ToString() + " files."); + } + } + + private int extractBundleFile(string bundleFileName) + { + int extractedCount = 0; + + StatusStripUpdate("Decompressing " + Path.GetFileName(bundleFileName) + " ,,,"); + + string extractPath = bundleFileName + "_unpacked\\"; + Directory.CreateDirectory(extractPath); + + using (BundleFile b_File = new BundleFile(bundleFileName)) + { + foreach (var memFile in b_File.MemoryAssetsFileList) + { + string filePath = extractPath + memFile.fileName.Replace('/','\\'); + if (!Directory.Exists(Path.GetDirectoryName(filePath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + + } + if (File.Exists(filePath)) + { + StatusStripUpdate("File " + memFile.fileName + " already exists"); + } + else + { + StatusStripUpdate("Extracting " + Path.GetFileName(memFile.fileName)); + extractedCount += 1; + + using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write)) + { + memFile.memStream.WriteTo(file); + } + } + } + } + + return extractedCount; + } + + + + private void enablePreview_Check(object sender, EventArgs e) + { + if (lastLoadedAsset != null) + { + switch (lastLoadedAsset.Type2) + { + case 28: + { + if (enablePreview.Checked && imageTexture != null) + { + previewPanel.BackgroundImage = imageTexture; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + } + else + { + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + } + } + break; + case 48: + case 49: + textPreviewBox.Visible = !textPreviewBox.Visible; + break; + case 128: + fontPreviewBox.Visible = !fontPreviewBox.Visible; + break; + case 83: + { + FMODpanel.Visible = !FMODpanel.Visible; + + FMOD.RESULT result; + + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + + //channel = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); ; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODpauseButton.Text = "Pause"; + //FMODinfoLabel.Text = ""; + } + else if (enablePreview.Checked) + { + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + timer.Start(); + FMODstatusLabel.Text = "Playing"; + //FMODinfoLabel.Text = FMODfrequency.ToString(); + } + } + + break; + } + + } + + } + else if (lastSelectedItem != null && enablePreview.Checked) + { + lastLoadedAsset = lastSelectedItem; + PreviewAsset(lastLoadedAsset); + } + + Properties.Settings.Default["enablePreview"] = enablePreview.Checked; + Properties.Settings.Default.Save(); + } + + private void displayAssetInfo_Check(object sender, EventArgs e) + { + if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } + else { assetInfoLabel.Visible = false; } + + Properties.Settings.Default["displayInfo"] = displayInfo.Checked; + Properties.Settings.Default.Save(); + } + + private void MenuItem_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default[((ToolStripMenuItem)sender).Name] = ((ToolStripMenuItem)sender).Checked; + Properties.Settings.Default.Save(); + } + + private void assetGroupOptions_SelectedIndexChanged(object sender, EventArgs e) + { + Properties.Settings.Default["assetGroupOption"] = ((ToolStripComboBox)sender).SelectedIndex; + Properties.Settings.Default.Save(); + } + + private void showExpOpt_Click(object sender, EventArgs e) + { + ExportOptions exportOpt = new ExportOptions(); + exportOpt.ShowDialog(); + } + + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) + { + AboutBox aboutWindow = new AboutBox(); + aboutWindow.ShowDialog(); + } + + + public class PreloadDataIComparer : IComparer + { + public int Compare(AssetPreloadData x, AssetPreloadData y) + { + return x.m_PathID.CompareTo(y.m_PathID); + } + } + private PreloadDataIComparer PreloadDataComparer = new PreloadDataIComparer(); + + private void BuildAssetStrucutres() + { + #region first loop - read asset data & create list + StatusStripUpdate("Building asset list..."); + assetListView.BeginUpdate(); + + string fileIDfmt = "D" + assetsfileList.Count.ToString().Length.ToString(); + + foreach (var assetsFile in assetsfileList) + { + var a_Stream = assetsFile.a_Stream; + var fileGen = assetsFile.fileGen; + //var m_version = assetsFile.m_version; + var version = assetsFile.version; + string fileID = "1" + assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); + + //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); + + foreach (var asset in assetsFile.preloadTable.Values) + { + asset.uniqueID = fileID + asset.uniqueID; + a_Stream.Position = asset.Offset; + + switch (asset.Type2) + { + case 1: //GameObject + { + GameObject m_GameObject = new GameObject(asset); + + //asset.Text = m_GameObject.m_Name; + asset.specificIndex = assetsFile.GameObjectList.Count; + assetsFile.GameObjectList.Add(m_GameObject); + break; + } + case 4: //Transform + { + Transform m_Transform = new Transform(asset); + + asset.specificIndex = assetsFile.TransformList.Count; + assetsFile.TransformList.Add(m_Transform); + break; + } + //case 21: //Material + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, false); + + asset.Text = m_Texture2D.m_Name; + asset.exportSize = 128 + m_Texture2D.image_data_size; + + #region Get Info Text + asset.InfoText = "Width: " + m_Texture2D.m_Width.ToString() + "\nHeight: " + m_Texture2D.m_Height.ToString() + "\nFormat: "; + + switch (m_Texture2D.m_TextureFormat) + { + case 1: + asset.InfoText += "Alpha8"; + break; + case 2: + asset.InfoText += "ARGB 4.4.4.4"; + break; + case 3: + asset.InfoText += "BGR 8.8.8"; + break; + case 4: + asset.InfoText += "GRAB 8.8.8.8"; + break; + case 5: + asset.InfoText += "BGRA 8.8.8.8"; + break; + case 7: + asset.InfoText += "RGB 5.6.5"; + break; + case 10: + asset.InfoText += "RGB DXT1"; + break; + case 12: + asset.InfoText += "ARGB DXT5"; + break; + case 13: + asset.InfoText += "RGBA 4.4.4.4"; + break; + case 30: + asset.InfoText += "PVRTC_RGB2"; + asset.exportSize -= 76; + break; + case 31: + asset.InfoText += "PVRTC_RGBA2"; + asset.exportSize -= 76; + break; + case 32: + asset.InfoText += "PVRTC_RGB4"; + asset.exportSize = 52; + break; + case 33: + asset.InfoText += "PVRTC_RGBA4"; + asset.exportSize -= 76; + break; + case 34: + asset.InfoText += "ETC_RGB4"; + asset.exportSize -= 76; + break; + default: + asset.InfoText += "unknown"; + asset.exportSize -= 128; + break; + } + + switch (m_Texture2D.m_FilterMode) + { + case 0: + asset.InfoText += "\nFilter Mode: Point "; + break; + case 1: + asset.InfoText += "\nFilter Mode: Bilinear "; + break; + case 2: + asset.InfoText += "\nFilter Mode: Trilinear "; + break; + + } + + asset.InfoText += "\nAnisotropic level: " + m_Texture2D.m_Aniso.ToString() + "\nMip map bias: " + m_Texture2D.m_MipBias.ToString(); + + switch (m_Texture2D.m_WrapMode) + { + case 0: + asset.InfoText += "\nWrap mode: Repeat"; + break; + case 1: + asset.InfoText += "\nWrap mode: Clamp"; + break; + } + #endregion + + assetsFile.exportableAssets.Add(asset); + break; + } + case 49: //TextAsset + { + TextAsset m_TextAsset = new TextAsset(asset, false); + + asset.Text = m_TextAsset.m_Name; + asset.exportSize = m_TextAsset.exportSize; + assetsFile.exportableAssets.Add(asset); + break; + } + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, false); + + asset.Text = m_AudioClip.m_Name; + asset.exportSize = m_AudioClip.exportSize; + assetsFile.exportableAssets.Add(asset); + + #region Info Text + asset.InfoText = "Format: " + m_AudioClip.m_Format.ToString() + "\nType: "; + + switch (m_AudioClip.m_Type) + { + case 13: + asset.InfoText += "MP3"; + break; + case 14: + asset.InfoText += "Ogg Vorbis"; + break; + case 20: + asset.InfoText += "WAV"; + break; + case 22: + asset.InfoText += "Xbox360 WAV"; //xbox compression? + break; + default: + asset.InfoText += "unknown"; + break; + } + + asset.InfoText += "\n3D: " + m_AudioClip.m_3D.ToString(); + #endregion + break; + } + case 48: //Shader + //case 74: //AnimationClip + case 89: //CubeMap + //case 115: //MonoScript + case 128: //Font + //case 134: //PhysicMaterial + //case 150: //PreloadData + asset.Text = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + assetsFile.exportableAssets.Add(asset); + break; + } + + if (asset.Text == "") { asset.Text = "Unnamed_" + asset.TypeString + "_#" + asset.uniqueID; } + asset.SubItems.AddRange(new string[] { asset.TypeString, asset.exportSize.ToString() }); + } + + exportableAssets.AddRange(assetsFile.exportableAssets); + //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } + } + + visibleAssets = exportableAssets; + assetListView.VirtualListSize = visibleAssets.Count; + + assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent); + assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); + resizeNameColumn(); + + assetListView.EndUpdate(); + #endregion + + #region second loop - build tree structure + StatusStripUpdate("Building tree structure..."); + sceneTreeView.BeginUpdate(); + foreach (var assetsFile in assetsfileList) + { + GameObject fileNode = new GameObject(null); + fileNode.Text = Path.GetFileName(assetsFile.filePath); + + foreach (var m_GameObject in assetsFile.GameObjectList) + { + var parentNode = fileNode; + + if (m_GameObject.m_Transform.m_FileID >= 0) + { + var TransformAF = assetsfileList[m_GameObject.m_Transform.m_FileID]; + + AssetPreloadData TransformPD; + if (TransformAF.preloadTable.TryGetValue(m_GameObject.m_Transform.m_PathID, out TransformPD)) + { + //this should be safe because m_PathID is 0 by default and PathID values range from 1 + //do they? + //consider using null? + Transform m_Transform = TransformAF.TransformList[TransformPD.specificIndex]; + + if (m_Transform.m_Father.m_FileID >= 0) + { + var FatherAF = assetsfileList[m_Transform.m_Father.m_FileID]; + AssetPreloadData FatherPD; + if (FatherAF.preloadTable.TryGetValue(m_Transform.m_Father.m_PathID, out FatherPD)) + { + Transform m_Father = FatherAF.TransformList[FatherPD.specificIndex]; + + if (m_Father.m_GameObject.m_FileID >= 0) + { + var parentAF = assetsfileList[m_Father.m_GameObject.m_FileID]; + AssetPreloadData parentPD; + if (parentAF.preloadTable.TryGetValue(m_Father.m_GameObject.m_PathID, out parentPD)) + { + parentNode = parentAF.GameObjectList[parentPD.specificIndex]; + } + } + } + } + } + } + + parentNode.Nodes.Add(m_GameObject); + } + + + if (fileNode.Nodes.Count == 0) { fileNode.Text += " (no children)"; } + sceneTreeView.Nodes.Add(fileNode); + } + sceneTreeView.EndUpdate(); + #endregion + + StatusStripUpdate("Finished loading " + assetsfileList.Count.ToString() + " files with " + (assetListView.Items.Count + sceneTreeView.Nodes.Count).ToString() + " exportable assets."); + + progressBar1.Value = 0; + treeSearch.Select(); + TexEnv dsd = new TexEnv(); + } + + private void assetListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + e.Item = visibleAssets[e.ItemIndex]; + } + + + + private void tabPageSelected(object sender, TabControlEventArgs e) + { + if (e.TabPageIndex == 0) { treeSearch.Select(); } + else if (e.TabPageIndex == 1) { listSearch.Select(); } + } + + private void treeSearch_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + if (e.Modifiers == Keys.Control) //toggle all matching nodes //skip children? + { + //loop assetsFileList or TreeView? + foreach (var AFile in assetsfileList) + { + foreach (var GObject in AFile.GameObjectList) + { + if (GObject.Text.Like(treeSearch.Text)) + { + GObject.Checked = true; + GObject.EnsureVisible(); + } + } + } + } + else //make visible one by one + { + bool foundNode = false; + + while (!foundNode && lastAFile < assetsfileList.Count) + { + var AFile = assetsfileList[lastAFile]; + + while (!foundNode && lastGObject < AFile.GameObjectList.Count) + { + var GObject = AFile.GameObjectList[lastGObject]; + if (GObject.Text.Like(treeSearch.Text)) + { + foundNode = true; + + GObject.EnsureVisible(); + sceneTreeView.SelectedNode = GObject; + + lastGObject++; + return; + } + + lastGObject++; + } + + lastAFile++; + lastGObject = 0; + } + lastAFile = 0; + } + } + } + + private void sceneTreeView_AfterCheck(object sender, TreeViewEventArgs e) + { + sceneTreeView.BeginUpdate(); + foreach (GameObject childNode in e.Node.Nodes) + { + childNode.Checked = e.Node.Checked; + } + sceneTreeView.EndUpdate(); + } + + + private void ListSearchTextChanged(object sender, EventArgs e) + { + assetListView.BeginUpdate(); + assetListView.SelectedIndices.Clear(); + //visibleListAssets = exportableAssets.FindAll(ListAsset => ListAsset.Text.StartsWith(ListSearch.Text, System.StringComparison.CurrentCultureIgnoreCase)); + visibleAssets = exportableAssets.FindAll(ListAsset => ListAsset.Text.IndexOf(listSearch.Text, System.StringComparison.CurrentCultureIgnoreCase) >= 0); + assetListView.VirtualListSize = visibleAssets.Count; + assetListView.EndUpdate(); + } + + private void assetListView_ColumnClick(object sender, ColumnClickEventArgs e) + { + assetListView.BeginUpdate(); + assetListView.SelectedIndices.Clear(); + switch (e.Column) + { + case 0: + if (isNameSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.Text.CompareTo(y.Text)); + isNameSorted = true; + } + + break; + case 1: + if (isTypeSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.TypeString.CompareTo(y.TypeString)); + isTypeSorted = true; + } + break; + case 2: + if (isSizeSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.exportSize.CompareTo(y.exportSize)); + isSizeSorted = true; + } + break; + } + assetListView.EndUpdate(); + } + + private void resizeNameColumn() + { + var vscroll = ((float)assetListView.VirtualListSize / (float)assetListView.Height) > 0.0567f; + columnHeaderName.Width = assetListView.Width - columnHeaderType.Width - columnHeaderSize.Width - (vscroll ? 25 : 5); + } + + private void selectAsset(object sender, ListViewItemSelectionChangedEventArgs e) + { + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + assetInfoLabel.Visible = false; + assetInfoLabel.Text = null; + textPreviewBox.Visible = false; + fontPreviewBox.Visible = false; + FMODpanel.Visible = false; + lastLoadedAsset = null; + + FMOD.RESULT result; + if (sound != null) + { + result = sound.release(); + ERRCHECK(result); + } + sound = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / 0:00.0"; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODinfoLabel.Text = ""; + + lastSelectedItem = (AssetPreloadData)e.Item; + + if (e.IsSelected) + { + assetInfoLabel.Text = lastSelectedItem.InfoText; + if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } //only display the label if asset has info text + + if (enablePreview.Checked) + { + lastLoadedAsset = lastSelectedItem; + PreviewAsset(lastLoadedAsset); + } + } + } + + + private void splitContainer1_Resize(object sender, EventArgs e) + { + resizeNameColumn(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + resizeNameColumn(); + } + + + private void PreviewAsset(AssetPreloadData asset) + { + switch (asset.Type2) + { + #region Texture2D + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, true); + + if (m_Texture2D.m_TextureFormat < 30) + { + byte[] imageBuffer = new byte[128 + m_Texture2D.image_data_size]; + + imageBuffer[0] = 0x44; + imageBuffer[1] = 0x44; + imageBuffer[2] = 0x53; + imageBuffer[3] = 0x20; + imageBuffer[4] = 0x7c; + + BitConverter.GetBytes(m_Texture2D.dwFlags).CopyTo(imageBuffer, 8); + BitConverter.GetBytes(m_Texture2D.m_Height).CopyTo(imageBuffer, 12); + BitConverter.GetBytes(m_Texture2D.m_Width).CopyTo(imageBuffer, 16); + BitConverter.GetBytes(m_Texture2D.dwPitchOrLinearSize).CopyTo(imageBuffer, 20); + BitConverter.GetBytes(m_Texture2D.dwMipMapCount).CopyTo(imageBuffer, 28); + BitConverter.GetBytes(m_Texture2D.dwSize).CopyTo(imageBuffer, 76); + BitConverter.GetBytes(m_Texture2D.dwFlags2).CopyTo(imageBuffer, 80); + BitConverter.GetBytes(m_Texture2D.dwFourCC).CopyTo(imageBuffer, 84); + BitConverter.GetBytes(m_Texture2D.dwRGBBitCount).CopyTo(imageBuffer, 88); + BitConverter.GetBytes(m_Texture2D.dwRBitMask).CopyTo(imageBuffer, 92); + BitConverter.GetBytes(m_Texture2D.dwGBitMask).CopyTo(imageBuffer, 96); + BitConverter.GetBytes(m_Texture2D.dwBBitMask).CopyTo(imageBuffer, 100); + BitConverter.GetBytes(m_Texture2D.dwABitMask).CopyTo(imageBuffer, 104); + BitConverter.GetBytes(m_Texture2D.dwCaps).CopyTo(imageBuffer, 108); + BitConverter.GetBytes(m_Texture2D.dwCaps2).CopyTo(imageBuffer, 112); + + m_Texture2D.image_data.CopyTo(imageBuffer, 128); + + imageTexture = DDSDataToBMP(imageBuffer); + imageTexture.RotateFlip(RotateFlipType.RotateNoneFlipY); + previewPanel.BackgroundImage = imageTexture; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + } + break; + } + #endregion + #region AudioClip + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, true); + + if (m_AudioClip.m_Type != 22) + { + //MemoryStream memoryStream = new MemoryStream(m_AudioData, true); + //System.Media.SoundPlayer soundPlayer = new System.Media.SoundPlayer(memoryStream); + //soundPlayer.Play(); + + //uint version = 0; + FMOD.RESULT result; + FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); + + /*result = FMOD.Factory.System_Create(ref system); + ERRCHECK(result); + + result = system.getVersion(ref version); + ERRCHECK(result); + if (version < FMOD.VERSION.number) + { + MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + "."); + Application.Exit(); + } + + result = system.init(1, FMOD.INITFLAGS.NORMAL, (IntPtr)null); + ERRCHECK(result);*/ + + exinfo.cbsize = Marshal.SizeOf(exinfo); + exinfo.length = (uint)m_AudioClip.exportSize; + + result = system.createSound(m_AudioClip.m_AudioData, (FMOD.MODE.HARDWARE | FMOD.MODE.OPENMEMORY | loopMode), ref exinfo, ref sound); + ERRCHECK(result); + + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + result = sound.getLength(ref FMODlenms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + timer.Start(); + FMODstatusLabel.Text = "Playing"; + FMODpanel.Visible = true; + + result = channel.getFrequency(ref FMODfrequency); + ERRCHECK(result); + FMODinfoLabel.Text = FMODfrequency.ToString() + " Hz"; + } + break; + } + #endregion + #region Shader & TextAsset + case 48: + case 49: + { + TextAsset m_TextAsset = new TextAsset(asset, true); + + string m_Script_Text = UnicodeEncoding.UTF8.GetString(m_TextAsset.m_Script); + m_Script_Text = Regex.Replace(m_Script_Text, "(? 0) + { + IntPtr data = Marshal.AllocCoTaskMem(m_Font.m_FontData.Length); + Marshal.Copy(m_Font.m_FontData, 0, data, m_Font.m_FontData.Length); + + System.Drawing.Text.PrivateFontCollection pfc = new System.Drawing.Text.PrivateFontCollection(); + // We HAVE to do this to register the font to the system (Weird .NET bug !) + uint cFonts = 0; + AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts); + + pfc.AddMemoryFont(data, m_Font.m_FontData.Length); + System.Runtime.InteropServices.Marshal.FreeCoTaskMem(data); + + //textPreviewBox.Font = new Font(pfc.Families[0], 16, FontStyle.Regular); + //textPreviewBox.Text = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ\r\n1234567890.:,;'\"(!?)+-*/=\r\nThe quick brown fox jumps over the lazy dog. 1234567890"; + fontPreviewBox.SelectionStart = 0; + fontPreviewBox.SelectionLength = 80; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 16, FontStyle.Regular); + fontPreviewBox.SelectionStart = 81; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 12, FontStyle.Regular); + fontPreviewBox.SelectionStart = 138; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 18, FontStyle.Regular); + fontPreviewBox.SelectionStart = 195; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 24, FontStyle.Regular); + fontPreviewBox.SelectionStart = 252; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 36, FontStyle.Regular); + fontPreviewBox.SelectionStart = 309; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 48, FontStyle.Regular); + fontPreviewBox.SelectionStart = 366; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 60, FontStyle.Regular); + fontPreviewBox.SelectionStart = 423; + fontPreviewBox.SelectionLength = 55; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 72, FontStyle.Regular); + fontPreviewBox.Visible = true; + } + + break; + } + #endregion + } + } + + public static Bitmap DDSDataToBMP(byte[] DDSData) + { + // Create a DevIL image "name" (which is actually a number) + int img_name; + Il.ilGenImages(1, out img_name); + Il.ilBindImage(img_name); + + // Load the DDS file into the bound DevIL image + Il.ilLoadL(Il.IL_DDS, DDSData, DDSData.Length); + + // Set a few size variables that will simplify later code + + int ImgWidth = Il.ilGetInteger(Il.IL_IMAGE_WIDTH); + int ImgHeight = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT); + Rectangle rect = new Rectangle(0, 0, ImgWidth, ImgHeight); + + // Convert the DevIL image to a pixel byte array to copy into Bitmap + Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE); + + // Create a Bitmap to copy the image into, and prepare it to get data + Bitmap bmp = new Bitmap(ImgWidth, ImgHeight); + BitmapData bmd = + bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + // Copy the pixel byte array from the DevIL image to the Bitmap + Il.ilCopyPixels(0, 0, 0, + Il.ilGetInteger(Il.IL_IMAGE_WIDTH), + Il.ilGetInteger(Il.IL_IMAGE_HEIGHT), + 1, Il.IL_BGRA, Il.IL_UNSIGNED_BYTE, + bmd.Scan0); + + // Clean up and return Bitmap + Il.ilDeleteImages(1, ref img_name); + bmp.UnlockBits(bmd); + return bmp; + } + + private void FMODinit() + { + FMOD.RESULT result; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / 0:00.0"; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + + if (sound != null) + { + result = sound.release(); + ERRCHECK(result); + sound = null; + } + + uint version = 0; + + result = FMOD.Factory.System_Create(ref system); + ERRCHECK(result); + + result = system.getVersion(ref version); + ERRCHECK(result); + if (version < FMOD.VERSION.number) + { + MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + "."); + Application.Exit(); + } + + result = system.init(1, FMOD.INITFLAGS.NORMAL, (IntPtr)null); + ERRCHECK(result); + + result = system.getMasterSoundGroup(ref masterSoundGroup); + ERRCHECK(result); + + result = masterSoundGroup.setVolume(FMODVolume); + ERRCHECK(result); + } + + /*protected override void Dispose(bool disposing) + { + if (disposing) + { + FMOD.RESULT result; + + + + + if (sound != null) + { + result = sound.release(); + ERRCHECK(result); + } + if (system != null) + { + result = system.close(); + ERRCHECK(result); + result = system.release(); + ERRCHECK(result); + } + + if (components != null) + { + components.Dispose(); + } + } + base.Dispose(disposing); + }*/ + + private void FMODplayButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + if (channel != null) + { + timer.Start(); + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + FMODpauseButton.Text = "Pause"; + } + else + { + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + FMODstatusLabel.Text = "Playing"; + //FMODinfoLabel.Text = FMODfrequency.ToString(); + + uint newms = 0; + + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + + result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + } + } + } + + private void FMODpauseButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + + if (channel != null) + { + bool playing = false; + bool paused = false; + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.getPaused(ref paused); + ERRCHECK(result); + result = channel.setPaused(!paused); + ERRCHECK(result); + + //FMODstatusLabel.Text = (!paused ? "Paused" : playing ? "Playing" : "Stopped"); + //FMODpauseButton.Text = (!paused ? "Resume" : playing ? "Pause" : "Pause"); + + if (paused) + { + FMODstatusLabel.Text = (playing ? "Playing" : "Stopped"); + FMODpauseButton.Text = "Pause"; + timer.Start(); + } + else + { + FMODstatusLabel.Text = "Paused"; + FMODpauseButton.Text = "Resume"; + timer.Stop(); + } + } + } + } + + private void FMODstopButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + //channel = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); ; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODpauseButton.Text = "Pause"; + //FMODinfoLabel.Text = ""; + } + } + } + + private void FMODloopButton_CheckedChanged(object sender, EventArgs e) + { + FMOD.RESULT result; + + if (FMODloopButton.Checked) + { + loopMode = FMOD.MODE.LOOP_NORMAL; + } + else + { + loopMode = FMOD.MODE.LOOP_OFF; + } + + if (sound != null) + { + result = sound.setMode(loopMode); + ERRCHECK(result); + } + + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool paused = false; + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing || paused) + { + result = channel.setMode(loopMode); + ERRCHECK(result); + } + /*else + { + /esult = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + result = channel.setMode(loopMode); + ERRCHECK(result); + }*/ + } + } + + private void FMODvolumeBar_ValueChanged(object sender, EventArgs e) + { + FMOD.RESULT result; + FMODVolume = Convert.ToSingle(FMODvolumeBar.Value) / 10; + + result = masterSoundGroup.setVolume(FMODVolume); + ERRCHECK(result); + + /*if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool paused = false; + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing || paused) + { + result = channel.setVolume(FMODVolume); + ERRCHECK(result); + } + }*/ + } + + private void FMODprogressBar_Scroll(object sender, EventArgs e) + { + uint newms = 0; + + if (channel != null) + { + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + FMODtimerLabel.Text = (newms / 1000 / 60) + ":" + (newms / 1000 % 60) + "." + (newms / 10 % 100) + "/" + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); + } + } + + private void FMODprogressBar_MouseDown(object sender, MouseEventArgs e) + { + timer.Stop(); + } + + private void FMODprogressBar_MouseUp(object sender, MouseEventArgs e) + { + FMOD.RESULT result; + uint newms = 0; + + if (channel != null) + { + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + + result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool playing = false; + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) { timer.Start(); } + } + } + + private void timer_Tick(object sender, EventArgs e) + { + FMOD.RESULT result; + uint ms = 0; + bool playing = false; + bool paused = false; + + if (channel != null) + { + result = channel.getPosition(ref ms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + } + + //statusBar.Text = "Time " + (ms / 1000 / 60) + ":" + (ms / 1000 % 60) + ":" + (ms / 10 % 100) + "/" + (lenms / 1000 / 60) + ":" + (lenms / 1000 % 60) + ":" + (lenms / 10 % 100) + " : " + (paused ? "Paused " : playing ? "Playing" : "Stopped"); + FMODtimerLabel.Text = (ms / 1000 / 60) + ":" + (ms / 1000 % 60) + "." + (ms / 10 % 100) + " / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); + FMODprogressBar.Value = (int)(ms * 1000 / FMODlenms); + FMODstatusLabel.Text = (paused ? "Paused " : playing ? "Playing" : "Stopped"); + + if (system != null) + { + system.update(); + } + } + + private void ERRCHECK(FMOD.RESULT result) + { + if (result != FMOD.RESULT.OK) + { + FMODinit(); + MessageBox.Show("FMOD error! " + result + " - " + FMOD.Error.String(result)); + //Environment.Exit(-1); + } + } + + + private void Export3DObjects_Click(object sender, EventArgs e) + { + if (sceneTreeView.Nodes.Count > 0) + { + bool exportSwitch = (((ToolStripItem)sender).Name == "allNodesToolStripMenuItem") ? true : false; + + + var timestamp = DateTime.Now; + saveFileDialog1.FileName = productName + timestamp.ToString("_yy_MM_dd__HH_mm_ss"); + //extension will be added by the file save dialog + + if (saveFileDialog1.ShowDialog() == DialogResult.OK) + { + switch ((bool)Properties.Settings.Default["showExpOpt"]) + { + case true: + ExportOptions exportOpt = new ExportOptions(); + if (exportOpt.ShowDialog() == DialogResult.OK) { goto case false; } + break; + case false: + switch (saveFileDialog1.FilterIndex) + { + case 1: + WriteFBX(saveFileDialog1.FileName, exportSwitch); + break; + case 2: + break; + } + + if (openAfterExport.Checked && File.Exists(saveFileDialog1.FileName)) { System.Diagnostics.Process.Start(saveFileDialog1.FileName); } + break; + } + } + + } + else { StatusStripUpdate("No Objects available for export"); } + } + + public void WriteFBX(string FBXfile, bool allNodes) + { + System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US"); + var timestamp = DateTime.Now; + + using (StreamWriter FBXwriter = new StreamWriter(FBXfile)) + { + StringBuilder fbx = new StringBuilder(); + StringBuilder ob = new StringBuilder(); //Objects builder + StringBuilder cb = new StringBuilder(); //Connections builder + cb.Append("\n}\n");//Objects end + cb.Append("\nConnections: {"); + + HashSet MeshList = new HashSet(); + HashSet MaterialList = new HashSet(); + HashSet TextureList = new HashSet(); + + int ModelCount = 0; + int GeometryCount = 0; + int MaterialCount = 0; + int TextureCount = 0; + + //using m_PathID as unique ID would fail because it could be a negative number (Hearthstone syndrome) + //consider using uint + //no, do something smarter + + #region write generic FBX data + fbx.Append("; FBX 7.1.0 project file"); + fbx.Append("\nFBXHeaderExtension: {\n\tFBXHeaderVersion: 1003\n\tFBXVersion: 7100\n\tCreationTimeStamp: {\n\t\tVersion: 1000"); + fbx.Append("\n\t\tYear: " + timestamp.Year); + fbx.Append("\n\t\tMonth: " + timestamp.Month); + fbx.Append("\n\t\tDay: " + timestamp.Day); + fbx.Append("\n\t\tHour: " + timestamp.Hour); + fbx.Append("\n\t\tMinute: " + timestamp.Minute); + fbx.Append("\n\t\tSecond: " + timestamp.Second); + fbx.Append("\n\t\tMillisecond: " + timestamp.Millisecond); + fbx.Append("\n\t}\n\tCreator: \"Unity Studio by Chipicao\"\n}\n"); + + fbx.Append("\nGlobalSettings: {"); + fbx.Append("\n\tVersion: 1000"); + fbx.Append("\n\tProperties70: {"); + fbx.Append("\n\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2"); + fbx.Append("\n\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0"); + fbx.Append("\n\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.AppendFormat("\n\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",{0}", Properties.Settings.Default["scaleFactor"]); + fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); + //sb.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); + //sb.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); + //sb.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); + //sb.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); + //sb.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); + //sb.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); + //sb.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); + //sb.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); + //sb.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); + //sb.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); + fbx.Append("\n\t}\n}\n"); + + fbx.Append("\nDocuments: {"); + fbx.Append("\n\tCount: 1"); + fbx.Append("\n\tDocument: 1234567890, \"\", \"Scene\" {"); + fbx.Append("\n\t\tProperties70: {"); + fbx.Append("\n\t\t\tP: \"SourceObject\", \"object\", \"\", \"\""); + fbx.Append("\n\t\t\tP: \"ActiveAnimStackName\", \"KString\", \"\", \"\", \"\""); + fbx.Append("\n\t\t}"); + fbx.Append("\n\t\tRootNode: 0"); + fbx.Append("\n\t}\n}\n"); + fbx.Append("\nReferences: {\n}\n"); + + fbx.Append("\nDefinitions: {"); + fbx.Append("\n\tVersion: 100"); + //fbx.AppendFormat("\n\tCount: {0}", 1 + srcModel.nodes.Count + FBXgeometryCount + srcModel.materials.Count + srcModel.usedTex.Count * 2); + + fbx.Append("\n\tObjectType: \"GlobalSettings\" {"); + fbx.Append("\n\t\tCount: 1"); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Model\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", ModelCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Geometry\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", GeometryCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Material\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", MaterialCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Texture\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Video\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.Append("\n\t}"); + fbx.Append("\n}\n"); + fbx.Append("\nObjects: {"); + + FBXwriter.Write(fbx); + fbx.Length = 0; + #endregion + + #region write Models, collect Mesh & Material objects + foreach (var assetsFile in assetsfileList) + { + foreach (var m_GameObject in assetsFile.GameObjectList) + { + if (m_GameObject.Checked || allNodes) + { + #region write Model and Transform + ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\"", m_GameObject.uniqueID, m_GameObject.m_Name); + + if (m_GameObject.m_MeshFilter != null || m_GameObject.m_SkinnedMeshRenderer != null) + { + ob.Append(", \"Mesh\" {"); + } + else { ob.Append(", \"Null\" {"); } + + ob.Append("\n\t\tVersion: 232"); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); + ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); + ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); + + //connect model to parent + GameObject parentObject = (GameObject)m_GameObject.Parent; + if (parentObject.Checked || allNodes) + { + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); + //if parentObject is a file or folder node, it will have uniqueID 0 + } + else { cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); }//connect to scene + + if (m_GameObject.m_Transform != null && m_GameObject.m_Transform.m_FileID >= 0) + { + var TransformAF = assetsfileList[m_GameObject.m_Transform.m_FileID]; + AssetPreloadData TransformPD; + if (TransformAF.preloadTable.TryGetValue(m_GameObject.m_Transform.m_PathID, out TransformPD)) + { + Transform m_Transform = TransformAF.TransformList[TransformPD.specificIndex]; + float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); + + ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); + ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat + ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); + } + } + + //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); + //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); + ob.Append("\n\t\t}"); + ob.Append("\n\t\tShading: T"); + ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); + #endregion + + #region get MeshFilter + if (m_GameObject.m_MeshFilter != null && m_GameObject.m_MeshFilter.m_FileID >= 0) + { + var MeshFilterAF = assetsfileList[m_GameObject.m_MeshFilter.m_FileID]; + AssetPreloadData MeshFilterPD; + if (MeshFilterAF.preloadTable.TryGetValue(m_GameObject.m_MeshFilter.m_PathID, out MeshFilterPD)) + { + MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); + + if (m_MeshFilter.m_Mesh.m_FileID >= 0) + { + var MeshAF = assetsfileList[m_MeshFilter.m_Mesh.m_FileID]; + AssetPreloadData MeshPD; + if (MeshAF.preloadTable.TryGetValue(m_MeshFilter.m_Mesh.m_PathID, out MeshPD)) + { + MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + } + } + #endregion + + #region get Renderer + if (m_GameObject.m_Renderer != null && m_GameObject.m_Renderer.m_FileID >= 0) + { + var RendererAF = assetsfileList[m_GameObject.m_Renderer.m_FileID]; + AssetPreloadData RendererPD; + if (RendererAF.preloadTable.TryGetValue(m_GameObject.m_Renderer.m_PathID, out RendererPD)) + { + Renderer m_Renderer = new Renderer(RendererPD); + foreach (var MaterialPPtr in m_Renderer.m_Materials) + { + if (MaterialPPtr.m_FileID >= 0) + { + var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; + AssetPreloadData MaterialPD; + if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + } + } + #endregion + + #region get SkinnedMeshRenderer + if (m_GameObject.m_SkinnedMeshRenderer != null && m_GameObject.m_SkinnedMeshRenderer.m_FileID >= 0) + { + var SkinnedMeshAF = assetsfileList[m_GameObject.m_SkinnedMeshRenderer.m_FileID]; + AssetPreloadData SkinnedMeshPD; + if (SkinnedMeshAF.preloadTable.TryGetValue(m_GameObject.m_SkinnedMeshRenderer.m_PathID, out SkinnedMeshPD)) + { + SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); + + foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) + { + if (MaterialPPtr.m_FileID >= 0) + { + var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; + AssetPreloadData MaterialPD; + if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + + if (m_SkinnedMeshRenderer.m_Mesh.m_FileID >= 0) + { + var MeshAF = assetsfileList[m_SkinnedMeshRenderer.m_Mesh.m_FileID]; + AssetPreloadData MeshPD; + if (MeshAF.preloadTable.TryGetValue(m_SkinnedMeshRenderer.m_Mesh.m_PathID, out MeshPD)) + { + MeshList.Add(MeshPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + } + } + #endregion + + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { + FBXwriter.Write(ob); + ob.Length = 0; + } + } + } + } + #endregion + + #region write Geometry + foreach (var MeshPD in MeshList) + { + Mesh m_Mesh = new Mesh(MeshPD); + + if (m_Mesh.m_VertexCount > 0)//general failsafe + { + StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); + + ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshPD.uniqueID); + ob.Append("\n\t\tProperties70: {"); + var randomColor = RandomColorGenerator(MeshPD.uniqueID); + ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255)); + ob.Append("\n\t\t}"); + + #region Vertices + ob.AppendFormat("\n\t\tVertices: *{0} {{\n\t\t\ta: ", m_Mesh.m_VertexCount * 3); + + int c = 3;//vertex components + //skip last value in half4 components + if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { c++; } //haha + + //split arrays in groups of 2040 chars + uint f3Lines = m_Mesh.m_VertexCount / 40;//40 verts * 3 components * 17 max chars per float including comma + uint remf3Verts = m_Mesh.m_VertexCount % 40; + + uint f2Lines = m_Mesh.m_VertexCount / 60;//60 UVs * 2 components * 17 max chars per float including comma + uint remf2Verts = m_Mesh.m_VertexCount % 60; + + //this is fast but line length is not optimal + for (int l = 0; l < f3Lines; l++) + { + for (int v = 0; v < 40; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[l * 120 + v * c], m_Mesh.m_Vertices[l * 120 + v * c + 1], m_Mesh.m_Vertices[l * 120 + v * c + 2]); + } + ob.Append("\n"); + } + + if (remf3Verts != 0) + { + for (int v = 0; v < remf3Verts; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[f3Lines * 120 + v * c], m_Mesh.m_Vertices[f3Lines * 120 + v * c + 1], m_Mesh.m_Vertices[f3Lines * 120 + v * c + 2]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t}"); + #endregion + + #region Indices + //in order to test topology for triangles/quads we need to store submeshes and write each one as geometry, then link to Mesh Node + ob.AppendFormat("\n\t\tPolygonVertexIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + int iLines = m_Mesh.m_Indices.Count / 180; + int remTris = (m_Mesh.m_Indices.Count % 180) / 3; + + for (int l = 0; l < iLines; l++) + { + for (int f = 0; f < 60; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], (-m_Mesh.m_Indices[l * 180 + f * 3 + 1] - 1)); + } + ob.Append("\n"); + } + + if (remTris != 0) + { + for (int f = 0; f < remTris; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], (-m_Mesh.m_Indices[iLines * 180 + f * 3 + 1] - 1)); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t}"); + ob.Append("\n\t\tGeometryVersion: 124"); + #endregion + + #region Normals + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\tLayerElementNormal: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tNormals: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); + + if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) { c = 3; } + else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) { c = 4; } + + for (int l = 0; l < f3Lines; l++) + { + for (int v = 0; v < 40; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[l * 120 + v * c], m_Mesh.m_Normals[l * 120 + v * c + 1], m_Mesh.m_Normals[l * 120 + v * c + 2]); + } + ob.Append("\n"); + } + + if (remf3Verts != 0) + { + for (int v = 0; v < remf3Verts; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[f3Lines * 120 + v * c], m_Mesh.m_Normals[f3Lines * 120 + v * c + 1], m_Mesh.m_Normals[f3Lines * 120 + v * c + 2]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Colors + + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\tLayerElementColor: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + //ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + //ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByPolygonVertex\""); + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tColors: *{0} {{\n\t\t\ta: ", m_Mesh.m_Colors.Length); + //ob.Append(string.Join(",", m_Mesh.m_Colors)); + + int cLines = m_Mesh.m_Colors.Length / 120; + int remCols = m_Mesh.m_Colors.Length % 120; + + for (int l = 0; l < cLines; l++) + { + for (int i = 0; i < 120; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_Colors[l * 120 + i]); + } + ob.Append("\n"); + } + + if (remCols > 0) + { + for (int i = 0; i < remCols; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_Colors[cLines * 120 + i]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}"); + ob.AppendFormat("\n\t\t\tColorIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + for (int l = 0; l < iLines; l++) + { + for (int f = 0; f < 60; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], m_Mesh.m_Indices[l * 180 + f * 3 + 1]); + } + ob.Append("\n"); + } + + if (remTris != 0) + { + for (int f = 0; f < remTris; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], m_Mesh.m_Indices[iLines * 180 + f * 3 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region UV + //does FBX support UVW coordinates? + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_1\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV1.Length); + + for (int l = 0; l < f2Lines; l++) + { + for (int v = 0; v < 60; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[l * 120 + v * 2], 1 - m_Mesh.m_UV1[l * 120 + v * 2 + 1]); + } + ob.Append("\n"); + } + + if (remf2Verts != 0) + { + for (int v = 0; v < remf2Verts; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV1[f2Lines * 120 + v * 2 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 1 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_2\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV2.Length); + + for (int l = 0; l < f2Lines; l++) + { + for (int v = 0; v < 60; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[l * 120 + v * 2], 1 - m_Mesh.m_UV2[l * 120 + v * 2 + 1]); + } + ob.Append("\n"); + } + + if (remf2Verts != 0) + { + for (int v = 0; v < remf2Verts; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV2[f2Lines * 120 + v * 2 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Material + ob.Append("\n\t\tLayerElementMaterial: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \""); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("AllSame\""); } + else { ob.Append("ByPolygon\""); } + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tMaterials: *{0} {{", m_Mesh.m_materialIDs.Count); + ob.Append("\n\t\t\t\t"); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("0"); } + else + { + int idLines = m_Mesh.m_materialIDs.Count / 500; + int remIds = m_Mesh.m_materialIDs.Count % 500; + + for (int l = 0; l < idLines; l++) + { + for (int i = 0; i < 500; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_materialIDs[l * 500 + i]); + } + ob.Append("\n"); + } + + if (remIds != 0) + { + for (int i = 0; i < remIds; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_materialIDs[idLines * 500 + i]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + } + ob.Append("\n\t\t\t}\n\t\t}"); + #endregion + + #region Layers + ob.Append("\n\t\tLayer: 0 {"); + ob.Append("\n\t\t\tVersion: 100"); + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementNormal\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementMaterial\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + // + /*ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementTexture\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementBumpTextures\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}");*/ + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementColor\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t}"); //Layer 0 end + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayer: 1 {"); + ob.Append("\n\t\t\tVersion: 100"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 1"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t}"); //Layer 1 end + } + #endregion + + ob.Append("\n\t}"); //Geometry end + + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { + FBXwriter.Write(ob); + ob.Length = 0; + } + } + } + #endregion + + #region write Materials, collect Texture objects + StatusStripUpdate("Writing Materials"); + foreach (var MaterialPD in MaterialList) + { + Material m_Material = new Material(MaterialPD); + + ob.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); + ob.Append("\n\t\tVersion: 102"); + ob.Append("\n\t\tShadingModel: \"phong\""); + ob.Append("\n\t\tMultiLayer: 0"); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); + + foreach (var m_Color in m_Material.m_Colors) + { + switch (m_Color.first) + { + case "_Color": + case "gSurfaceColor": + ob.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_SpecColor": + ob.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_ReflectColor": + ob.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + default: + ob.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out + break; + } + } + + foreach (var m_Float in m_Material.m_Floats) + { + switch (m_Float.first) + { + case "_Shininess": + ob.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); + break; + default: + ob.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); + break; + } + } + + //ob.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); + ob.Append("\n\t\t}"); + ob.Append("\n\t}"); + + foreach (var m_TexEnv in m_Material.m_TexEnvs) + { + if (m_TexEnv.m_Texture.m_FileID >= 0) + { + var TextureAF = assetsfileList[m_TexEnv.m_Texture.m_FileID]; + AssetPreloadData TexturePD; + if (TextureAF.preloadTable.TryGetValue(m_TexEnv.m_Texture.m_PathID, out TexturePD)) + { + TextureList.Add(TexturePD); + + cb.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); + switch (m_TexEnv.name) + { + case "_MainTex": + case "gDiffuseSampler": + cb.Append("DiffuseColor\""); + break; + case "_SpecularMap": + case "gSpecularSampler": + cb.Append("SpecularColor\""); + break; + case "_NormalMap": + case "_BumpMap": + case "gNormalSampler": + cb.Append("NormalMap\""); + break; + default: + cb.AppendFormat("{0}\"", m_TexEnv.name); + break; + } + } + } + } + } + #endregion + + #region write & extract Textures + Directory.CreateDirectory(Path.GetDirectoryName(FBXfile) + "\\Texture2D"); + + foreach (var TexturePD in TextureList) + { + Texture2D m_Texture2D = new Texture2D(TexturePD, true); + + #region extract texture + string texPath = Path.GetDirectoryName(FBXfile) + "\\Texture2D\\" + TexturePD.Text; +//TODO check texture type and set path accordingly; eg. CubeMap, Texture3D + if (uniqueNames.Checked) { texPath += " #" + TexturePD.uniqueID; } + if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } + else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } + else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } + + if (File.Exists(texPath)) + { + StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); + + switch (m_Texture2D.m_TextureFormat) + { + case 1: //Alpha8 + case 2: //A4R4G4B4 + case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure + case 4: //G8R8A8B8 //confirmed on X360, iOS + case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS + case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS + case 10: //DXT1 + case 12: //DXT5 + case 13: //R4G4B4A4, iOS (only?) + WriteDDS(texPath, m_Texture2D); + break; + case 30: //PVRTC_RGB2 + case 31: //PVRTC_RGBA2 + case 32: //PVRTC_RGB4 + case 33: //PVRTC_RGBA4 + case 34: //ETC_RGB4 + WritePVR(texPath, m_Texture2D); + break; + default: + { + using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) + { + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + break; + } + } + } + #endregion + + ob.AppendFormat("\n\tTexture: {0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.Append("\n\t\tType: \"TextureVideoClip\""); + ob.Append("\n\t\tVersion: 202"); + ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"UVChannel_0\""); + ob.Append("\n\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",1"); + ob.Append("\n\t\t}"); + ob.AppendFormat("\n\t\tMedia: \"Video::{0}\"", TexturePD.Text); + ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); + ob.AppendFormat("\n\t\tRelativeFilename: \"\\maps\\{0}\"", Path.GetFileName(texPath)); + ob.Append("\n\t}"); + + //Video ID is prefixed by 1 + ob.AppendFormat("\n\tVideo: 1{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.Append("\n\t\tType: \"Clip\""); + ob.Append("\n\t\tProperties70: {"); + ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); + ob.Append("\n\t\t}"); + ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); + ob.AppendFormat("\n\t\tRelativeFilename: \"\\maps\\{0}\"", Path.GetFileName(texPath)); + ob.Append("\n\t}"); + + //connect video to texture + cb.AppendFormat("\n\tC: \"OO\",1{0},{1}", TexturePD.uniqueID, TexturePD.uniqueID); + } + #endregion + + FBXwriter.Write(ob); + ob.Clear(); + + cb.Append("\n}");//Connections end + FBXwriter.Write(cb); + cb.Clear(); + + StatusStripUpdate("Finished exporting " + Path.GetFileName(FBXfile)); + } + } + + private static float[] QuatToEuler(float[] q) + { + double eax = 0; + double eay = 0; + double eaz = 0; + + float qx = q[0]; + float qy = q[1]; + float qz = q[2]; + float qw = q[3]; + + double[,] M = new double[4, 4]; + + double Nq = qx * qx + qy * qy + qz * qz + qw * qw; + double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0; + double xs = qx * s, ys = qy * s, zs = qz * s; + double wx = qw * xs, wy = qw * ys, wz = qw * zs; + double xx = qx * xs, xy = qx * ys, xz = qx * zs; + double yy = qy * ys, yz = qy * zs, zz = qz * zs; + + M[0, 0] = 1.0 - (yy + zz); M[0, 1] = xy - wz; M[0, 2] = xz + wy; + M[1, 0] = xy + wz; M[1, 1] = 1.0 - (xx + zz); M[1, 2] = yz - wx; + M[2, 0] = xz - wy; M[2, 1] = yz + wx; M[2, 2] = 1.0 - (xx + yy); + M[3, 0] = M[3, 1] = M[3, 2] = M[0, 3] = M[1, 3] = M[2, 3] = 0.0; M[3, 3] = 1.0; + + double test = Math.Sqrt(M[0, 0] * M[0, 0] + M[1, 0] * M[1, 0]); + if (test > 16 * 1.19209290E-07F)//FLT_EPSILON + { + eax = Math.Atan2(M[2, 1], M[2, 2]); + eay = Math.Atan2(-M[2, 0], test); + eaz = Math.Atan2(M[1, 0], M[0, 0]); + } + else + { + eax = Math.Atan2(-M[1, 2], M[1, 1]); + eay = Math.Atan2(-M[2, 0], test); + eaz = 0; + } + + return new float[3] { (float)(eax * 180 / Math.PI), (float)(eay * 180 / Math.PI), (float)(eaz * 180 / Math.PI) }; + } + + private static byte[] RandomColorGenerator(string name) + { + int nameHash = name.GetHashCode(); + Random r = new Random(nameHash); + //Random r = new Random(DateTime.Now.Millisecond); + + byte red = (byte)r.Next(0, 255); + byte green = (byte)r.Next(0, 255); + byte blue = (byte)r.Next(0, 255); + + return new byte[3] { red, green, blue }; + } + + + private void ExportAssets_Click(object sender, EventArgs e) + { + if (exportableAssets.Count > 0) + { + if (saveFolderDialog1.ShowDialog() == DialogResult.OK) + { + var savePath = saveFolderDialog1.FileName; + if (Path.GetFileName(savePath) == "Select folder or write folder name to create") + { savePath = Path.GetDirectoryName(saveFolderDialog1.FileName); } + //Directory.CreateDirectory(saveFolderDialog1.FileName);//this will be created later, when grouping is determined + + switch (((ToolStripItem)sender).Name) + { + case "allToolStripMenuItem": + ExportAll(savePath, assetGroupOptions.SelectedIndex); + break; + case "filteredToolStripMenuItem": + ExportFiltered(visibleAssets, savePath, assetGroupOptions.SelectedIndex); + break; + case "selectedToolStripMenuItem": + List selectedAssetList = new List(); + var selIndices = assetListView.SelectedIndices; + foreach (int index in selIndices) { selectedAssetList.Add((AssetPreloadData)assetListView.Items[index]); } + ExportFiltered(selectedAssetList, savePath, assetGroupOptions.SelectedIndex); + break; + } + + if (openAfterExport.Checked) { System.Diagnostics.Process.Start(savePath); } + } + + } + else + { + StatusStripUpdate("No exportable assets loaded"); + } + } + + private void ExportAll(string selectedPath, int groupFiles) + { + int exportedCount = 0; + + foreach (var assetsFile in assetsfileList) + { + if (assetsFile.exportableAssets.Count > 0) + { + string exportpath = selectedPath; + if (groupFiles == 1) { exportpath += "\\" + Path.GetFileNameWithoutExtension(assetsFile.filePath) + "_export"; } + Directory.CreateDirectory(exportpath); + + foreach (var asset in assetsFile.exportableAssets) + { + if (groupFiles == 0) + { + switch (asset.Type2) + { + case 28: + exportpath = selectedPath + "\\Texture2D"; + break; + case 83: + exportpath = selectedPath + "\\AudioClip"; + break; + case 48: + exportpath = selectedPath + "\\Shader"; + break; + case 49: + exportpath = selectedPath + "\\TextAsset"; + break; + case 128: + exportpath = selectedPath + "\\Font"; + break; + } + Directory.CreateDirectory(exportpath); + } + exportedCount += ExportAsset(assetsFile.a_Stream, assetsFile, asset, exportpath); + } + } + } + string statusText = "Finished exporting " + exportedCount.ToString() + " assets."; + if ((exportableAssets.Count - exportedCount) > 0) { statusText += " " + (exportableAssets.Count - exportedCount).ToString() + " assets skipped (not extractable or files already exist)"; } + StatusStripUpdate(statusText); + } + + private void ExportFiltered(List filteredAssetList, string selectedPath, int groupFiles) + { + if (filteredAssetList.Count > 0) + { + int exportedCount = 0; + + List toExportList = new List(filteredAssetList); //copy + + foreach (var assetsFile in assetsfileList) + { + if (assetsFile.exportableAssets.Count > 0) + { + string exportpath = selectedPath; + if (groupFiles == 1) { exportpath += "\\" + Path.GetFileNameWithoutExtension(assetsFile.filePath) + "_export"; } + + for (int i = 0; i < toExportList.Count; i++) + { + var listItem = toExportList[i]; + if (listItem.sourceFile == assetsFile) + { + if (groupFiles == 0) + { + switch (listItem.Type2) + { + case 28: + exportpath = selectedPath + "\\Texture2D"; + break; + case 83: + exportpath = selectedPath + "\\AudioClip"; + break; + case 48: + exportpath = selectedPath + "\\Shader"; + break; + case 49: + exportpath = selectedPath + "\\TextAsset"; + break; + case 128: + exportpath = selectedPath + "\\Font"; + break; + } + Directory.CreateDirectory(exportpath); + } + + AssetPreloadData dummyPreloadData = new AssetPreloadData(); + dummyPreloadData.m_PathID = listItem.m_PathID; + var exportableAssetIndex = assetsFile.exportableAssets.BinarySearch(dummyPreloadData, PreloadDataComparer); +//why am I doign this?? + if (exportableAssetIndex >= 0) + { + Directory.CreateDirectory(exportpath); + exportedCount += ExportAsset(assetsFile.a_Stream, assetsFile, assetsFile.exportableAssets[exportableAssetIndex], exportpath); + //toExportList.Remove(listItem); + toExportList.RemoveAt(i); + i--; + } + } + } + } + } + string statusText = "Finished exporting " + exportedCount.ToString() + " assets."; + if ((filteredAssetList.Count - exportedCount) > 0) { statusText += " " + (filteredAssetList.Count - exportedCount).ToString() + " assets skipped (not extractable or files already exist)"; } + StatusStripUpdate(statusText); + } + else + { + StatusStripUpdate("No exportable assets selected or filtered"); + } + } + + private int ExportAsset(EndianStream Stream, AssetsFile assetsFile, AssetPreloadData asset, string exportPath) + { + Stream.Position = asset.Offset; + int exportCount = 0; + + switch (asset.Type2) + { + #region Texture2D + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, true); + + string texPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { texPath += " #" + asset.uniqueID; } + if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } + else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } + else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } + + if (File.Exists(texPath)) + { + StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); + exportCount += 1; + + switch (m_Texture2D.m_TextureFormat) + { + case 1: //Alpha8 + case 2: //A4R4G4B4 + case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure + case 4: //G8R8A8B8 //confirmed on X360, iOS + case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS + case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS + case 10: //DXT1 + case 12: //DXT5 + case 13: //R4G4B4A4, iOS (only?) + WriteDDS(texPath, m_Texture2D); + break; + case 30: //PVRTC_RGB2 + case 31: //PVRTC_RGBA2 + case 32: //PVRTC_RGB4 + case 33: //PVRTC_RGBA4 + case 34: //ETC_RGB4 + WritePVR(texPath, m_Texture2D); + break; + default: + { + using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) + { + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + break; + } + } + } + break; + } + #endregion + #region AudioClip + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, true); + + string audPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { audPath += " #" + asset.uniqueID; } + audPath += m_AudioClip.extension; + + if (File.Exists(audPath)) + { + StatusStripUpdate("Audio file " + Path.GetFileName(audPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting AudioClip: " + Path.GetFileName(audPath)); + exportCount += 1; + + using (BinaryWriter writer = new BinaryWriter(File.Open(audPath, FileMode.Create))) + { + writer.Write(m_AudioClip.m_AudioData); + writer.Close(); + } + + } + break; + } + #endregion + #region Shader & TextAsset + case 48: //Shader + case 49: //TextAsset + { + TextAsset m_TextAsset = new TextAsset(asset, true); + + string m_Name = Stream.ReadAlignedString(Stream.ReadInt32()); + string textAssetPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { textAssetPath += " #" + asset.uniqueID; } + textAssetPath += m_TextAsset.extension; + + if (File.Exists(textAssetPath)) + { + StatusStripUpdate("TextAsset file " + Path.GetFileName(textAssetPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting TextAsset: " + Path.GetFileName(textAssetPath)); + exportCount += 1; + + using (BinaryWriter writer = new BinaryWriter(File.Open(textAssetPath, FileMode.Create))) + { + writer.Write(m_TextAsset.m_Script); + writer.Close(); + } + } + break; + } + #endregion + #region Font + case 128: //Font + { + unityFont m_Font = new unityFont(asset); + + string fontPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { fontPath += " #" + asset.uniqueID; } + fontPath += m_Font.extension; + + if (File.Exists(fontPath)) + { + StatusStripUpdate("Font file " + Path.GetFileName(fontPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Font: " + Path.GetFileName(fontPath)); + + using (BinaryWriter writer = new BinaryWriter(File.Open(fontPath, FileMode.Create))) + { + writer.Write(m_Font.m_FontData); + writer.Close(); + } + + exportCount += 1; + } + break; + } + #endregion + /*default: + { + string assetPath = exportPath + "\\" + asset.Name + "." + asset.TypeString; + byte[] assetData = new byte[asset.Size]; + Stream.Read(assetData, 0, asset.Size); + using (BinaryWriter writer = new BinaryWriter(File.Open(assetPath, FileMode.Create))) + { + writer.Write(assetData); + writer.Close(); + } + exportCount += 1; + break; + }*/ + } + return exportCount; + } + + private void WriteDDS(string DDSfile, Texture2D m_Texture2D) + { + using (BinaryWriter writer = new BinaryWriter(File.Open(DDSfile, FileMode.Create))) + { + writer.Write(0x20534444); + writer.Write(0x7C); + writer.Write(m_Texture2D.dwFlags); + writer.Write(m_Texture2D.m_Height); + writer.Write(m_Texture2D.m_Width); + writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); + writer.Write((int)0); //dwDepth not implemented + writer.Write(m_Texture2D.dwMipMapCount); + writer.Write(new byte[44]); //dwReserved1[11] + writer.Write(m_Texture2D.dwSize); + writer.Write(m_Texture2D.dwFlags2); + writer.Write(m_Texture2D.dwFourCC); + writer.Write(m_Texture2D.dwRGBBitCount); + writer.Write(m_Texture2D.dwRBitMask); + writer.Write(m_Texture2D.dwGBitMask); + writer.Write(m_Texture2D.dwBBitMask); + writer.Write(m_Texture2D.dwABitMask); + writer.Write(m_Texture2D.dwCaps); + writer.Write(m_Texture2D.dwCaps2); + writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 + + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + } + + private void WritePVR(string PVRfile, Texture2D m_Texture2D) + { + using (BinaryWriter writer = new BinaryWriter(File.Open(PVRfile, FileMode.Create))) + { + writer.Write(m_Texture2D.pvrVersion); + writer.Write(m_Texture2D.pvrFlags); + writer.Write(m_Texture2D.pvrPixelFormat); + writer.Write(m_Texture2D.pvrColourSpace); + writer.Write(m_Texture2D.pvrChannelType); + writer.Write(m_Texture2D.m_Height); + writer.Write(m_Texture2D.m_Width); + writer.Write(m_Texture2D.pvrDepth); + writer.Write(m_Texture2D.pvrNumSurfaces); + writer.Write(m_Texture2D.pvrNumFaces); + writer.Write(m_Texture2D.dwMipMapCount); + writer.Write(m_Texture2D.pvrMetaDataSize); + + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + } + + + public UnityStudioForm() + { + InitializeComponent(); + uniqueNames.Checked = (bool)Properties.Settings.Default["uniqueNames"]; + displayInfo.Checked = (bool)Properties.Settings.Default["displayInfo"]; + enablePreview.Checked = (bool)Properties.Settings.Default["enablePreview"]; + openAfterExport.Checked = (bool)Properties.Settings.Default["openAfterExport"]; + assetGroupOptions.SelectedIndex = (int)Properties.Settings.Default["assetGroupOption"]; + resizeNameColumn(); + } + + private void UnityStudioForm_FormClosing(object sender, FormClosingEventArgs e) + { + /*Properties.Settings.Default["uniqueNames"] = uniqueNamesMenuItem.Checked; + Properties.Settings.Default["enablePreview"] = enablePreviewMenuItem.Checked; + Properties.Settings.Default["displayInfo"] = displayAssetInfoMenuItem.Checked; + Properties.Settings.Default.Save(); + + foreach (var assetsFile in assetsfileList) { assetsFile.a_Stream.Dispose(); } //is this needed?*/ + } + + public void StatusStripUpdate(string statusText) + { + toolStripStatusLabel1.Text = statusText; + statusStrip1.Update(); + } + } +} diff --git a/Unity Studio/UnityStudioForm.cs b/Unity Studio/UnityStudioForm.cs new file mode 100644 index 0000000..872c240 --- /dev/null +++ b/Unity Studio/UnityStudioForm.cs @@ -0,0 +1,2853 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.IO; +using System.Threading; +using System.Globalization; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using System.Drawing.Imaging; +using Tao.DevIl; +using System.Web.Script.Serialization; + + +//Load parent nodes even if they are not selected to provide transformations? +//For extracting bundles, first check if file exists then decompress + +//rigurous search for search files; look into Path.Combine + +namespace Unity_Studio +{ + public partial class UnityStudioForm : Form + { + private List unityFiles = new List(); //files to load + public static List assetsfileList = new List(); //loaded files + private List exportableAssets = new List(); //used to hold all listItems while the list is being filtered + private List visibleAssets = new List(); //used to build the listView + private AssetPreloadData lastSelectedItem = null; + private AssetPreloadData lastLoadedAsset = null; + //private AssetsFile mainDataFile = null; + private string mainPath = ""; + private string productName = ""; + + Dictionary> jsonMats; + + private FMOD.System system = null; + private FMOD.Sound sound = null; + private FMOD.Channel channel = null; + private FMOD.SoundGroup masterSoundGroup = null; + + private FMOD.MODE loopMode = FMOD.MODE.LOOP_OFF; + private uint FMODlenms = 0; + private float FMODVolume = 0.8f; + private float FMODfrequency; + + private Bitmap imageTexture = null; + + private bool startFilter = false; + private bool isNameSorted = false; + private bool isTypeSorted = false; + private bool isSizeSorted = false; + + //return-to indices for tree search + private int lastAFile = 0; + private int lastGObject = 0; + + [DllImport("gdi32.dll")] + private static extern IntPtr AddFontMemResourceEx(IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts); + + [DllImport("PVRTexLib.dll")] + private static extern void test(); + + + private void loadFile_Click(object sender, System.EventArgs e) + { + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + resetForm(); + mainPath = Path.GetDirectoryName(openFileDialog1.FileNames[0]); + + if (openFileDialog1.FilterIndex == 1) + { + MergeSplitAssets(mainPath); + + unityFiles.AddRange(openFileDialog1.FileNames); + progressBar1.Value = 0; + progressBar1.Maximum = unityFiles.Count; + + foreach (var filename in openFileDialog1.FileNames) + { + StatusStripUpdate("Loading " + Path.GetFileName(filename)); + LoadAssetsFile(filename); + } + } + else + { + progressBar1.Value = 0; + progressBar1.Maximum = openFileDialog1.FileNames.Length; + + foreach (var filename in openFileDialog1.FileNames) + { + LoadBundleFile(filename); + progressBar1.PerformStep(); + } + } + + BuildAssetStrucutres(); + } + } + + private void loadFolder_Click(object sender, System.EventArgs e) + { + /*FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog(); + + folderBrowserDialog1.Description = "Load all Unity assets from folder and subfolders"; + folderBrowserDialog1.ShowNewFolderButton = false; + //folderBrowserDialog1.SelectedPath = "E:\\Assets\\Unity"; + folderBrowserDialog1.SelectedPath = "E:\\Assets\\Unity\\WebPlayer\\Porsche\\92AAF1\\defaultGeometry";*/ + + if (openFolderDialog1.ShowDialog() == DialogResult.OK) + { + //mainPath = folderBrowserDialog1.SelectedPath; + mainPath = openFolderDialog1.FileName; + if (Path.GetFileName(mainPath) == "Select folder") + { mainPath = Path.GetDirectoryName(mainPath); } + + if (Directory.Exists(mainPath)) + { + resetForm(); + + //TODO find a way to read data directly instead of merging files + MergeSplitAssets(mainPath); + + string[] fileTypes = new string[7] { "maindata.", "level*.", "*.assets", "*.sharedAssets", "CustomAssetBundle-*", "CAB-*", "BuildPlayer-*" }; + for (int t = 0; t < fileTypes.Length; t++) + { + string[] fileNames = Directory.GetFiles(mainPath, fileTypes[t], SearchOption.AllDirectories); + #region sort specific types alphanumerically + if (fileNames.Length > 0 && (t == 1 || t == 2)) + { + var sortedList = fileNames.ToList(); + sortedList.Sort((s1, s2) => + { + string pattern = "([A-Za-z\\s]*)([0-9]*)"; + string h1 = Regex.Match(Path.GetFileNameWithoutExtension(s1), pattern).Groups[1].Value; + string h2 = Regex.Match(Path.GetFileNameWithoutExtension(s2), pattern).Groups[1].Value; + if (h1 != h2) + return h1.CompareTo(h2); + string t1 = Regex.Match(Path.GetFileNameWithoutExtension(s1), pattern).Groups[2].Value; + string t2 = Regex.Match(Path.GetFileNameWithoutExtension(s2), pattern).Groups[2].Value; + if (t1 != "" && t2 != "") + return int.Parse(t1).CompareTo(int.Parse(t2)); + return 0; + }); + unityFiles.AddRange(sortedList); + } + #endregion + else { unityFiles.AddRange(fileNames); } + } + + unityFiles = unityFiles.Distinct().ToList(); + progressBar1.Value = 0; + progressBar1.Maximum = unityFiles.Count; + + //use a for loop because list size can change + for (int f = 0; f < unityFiles.Count; f++) + { + var fileName = unityFiles[f]; + StatusStripUpdate("Loading " + Path.GetFileName(fileName)); + LoadAssetsFile(fileName); + } + + BuildAssetStrucutres(); + } + else { StatusStripUpdate("Selected path deos not exist."); } + } + } + + private void MergeSplitAssets(string dirPath) + { + string[] splitFiles = Directory.GetFiles(dirPath, "*.split0"); + foreach (var splitFile in splitFiles) + { + string destFile = Path.GetFileNameWithoutExtension(splitFile); + string destPath = Path.GetDirectoryName(splitFile) + "\\"; + if (!File.Exists(destPath + destFile)) + { + StatusStripUpdate("Merging " + destFile + " split files..."); + + string[] splitParts = Directory.GetFiles(destPath, destFile + ".split*"); + using (var destStream = File.Create(destPath + destFile)) + { + for (int i = 0; i < splitParts.Length; i++) + { + string splitPart = destPath + destFile + ".split" + i.ToString(); + using (var sourceStream = File.OpenRead(splitPart)) + sourceStream.CopyTo(destStream); // You can pass the buffer size as second argument. + } + } + } + } + } + + private void LoadAssetsFile(string fileName) + { + var loadedAssetsFile = assetsfileList.Find(aFile => aFile.filePath == fileName); + if (loadedAssetsFile == null) + { + //open file here and pass the stream to facilitate loading memory files + //also by keeping the stream as a property of AssetsFile, it can be used later on to read assets + AssetsFile assetsFile = new AssetsFile(fileName, new EndianStream(File.OpenRead(fileName), EndianType.BigEndian)); + //if (Path.GetFileName(fileName) == "mainData") { mainDataFile = assetsFile; } + + assetsfileList.Add(assetsFile); + #region for 2.6.x find mainData and get string version + if (assetsFile.fileGen == 6 && Path.GetFileName(fileName) != "mainData") + { + AssetsFile mainDataFile = assetsfileList.Find(aFile => aFile.filePath == Path.GetDirectoryName(fileName) + "\\mainData"); + if (mainDataFile != null) + { + assetsFile.m_Version = mainDataFile.m_Version; + assetsFile.version = mainDataFile.version; + assetsFile.buildType = mainDataFile.buildType; + } + else if (File.Exists(Path.GetDirectoryName(fileName) + "\\mainData")) + { + mainDataFile = new AssetsFile(Path.GetDirectoryName(fileName) + "\\mainData", new EndianStream(File.OpenRead(Path.GetDirectoryName(fileName) + "\\mainData"), EndianType.BigEndian)); + + assetsFile.m_Version = mainDataFile.m_Version; + assetsFile.version = mainDataFile.version; + assetsFile.buildType = mainDataFile.buildType; + } + } + #endregion + progressBar1.PerformStep(); + + foreach (var sharedFile in assetsFile.sharedAssetsList) + { + string sharedFilePath = Path.GetDirectoryName(fileName) + "\\" + sharedFile.fileName; + + //TODO add extra code to search for the shared file in case it doesn't exist in the main folder + //or if it exists or the path is incorrect + + //var loadedSharedFile = assetsfileList.Find(aFile => aFile.filePath == sharedFilePath); + /*var loadedSharedFile = assetsfileList.Find(aFile => aFile.filePath.EndsWith(Path.GetFileName(sharedFile.fileName))); + if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); } + else if (File.Exists(sharedFilePath)) + { + //progressBar1.Maximum += 1; + sharedFile.Index = assetsfileList.Count; + LoadAssetsFile(sharedFilePath); + }*/ + + //searching in unityFiles would preserve desired order, but... + var quedSharedFile = unityFiles.Find(uFile => uFile.EndsWith(Path.GetFileName(sharedFile.fileName))); + if (quedSharedFile == null && File.Exists(sharedFilePath)) + { + sharedFile.Index = unityFiles.Count;//this would get screwed if the file fails to load + unityFiles.Add(sharedFilePath); + progressBar1.Maximum++; + } + else { sharedFile.Index = unityFiles.IndexOf(quedSharedFile); } + } + + } + } + + private void LoadBundleFile(string bundleFileName) + { + StatusStripUpdate("Decompressing " + Path.GetFileName(bundleFileName) + "..."); + + using (BundleFile b_File = new BundleFile(bundleFileName)) + { + List b_assetsfileList = new List(); + + foreach (var memFile in b_File.MemoryAssetsFileList) //filter unity files + { + bool validAssetsFile = false; + switch (Path.GetExtension(memFile.fileName)) + { + case ".assets": + case ".sharedAssets": + validAssetsFile = true; + break; + case "": + if (memFile.fileName == "mainData" || Regex.IsMatch(memFile.fileName, "level.*?") || Regex.IsMatch(memFile.fileName, "CustomAssetBundle-.*?") || Regex.IsMatch(memFile.fileName, "CAB-.*?") || Regex.IsMatch(memFile.fileName, "BuildPlayer-.*?")) { validAssetsFile = true; } + break; + } + + if (validAssetsFile) + { + StatusStripUpdate("Loading " + memFile.fileName); + memFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + memFile.fileName; //add path for extract location + + AssetsFile assetsFile = new AssetsFile(memFile.fileName, new EndianStream(memFile.memStream, EndianType.BigEndian)); + if (assetsFile.fileGen == 6 && Path.GetFileName(bundleFileName) != "mainData") //2.6.x and earlier don't have a string version before the preload table + { + //make use of the bundle file version + assetsFile.m_Version = b_File.ver3; + assetsFile.version = Array.ConvertAll((b_File.ver3.Split(new string[] { ".", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "\n" }, StringSplitOptions.RemoveEmptyEntries)), int.Parse); + assetsFile.buildType = b_File.ver3.Split(new string[] { ".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }, StringSplitOptions.RemoveEmptyEntries); + } + + b_assetsfileList.Add(assetsFile); + } + else + { + memFile.memStream.Close(); + } + } + + assetsfileList.AddRange(b_assetsfileList);//will the streams still be available for reading data? + + foreach (var assetsFile in b_assetsfileList) + { + foreach (var sharedFile in assetsFile.sharedAssetsList) + { + sharedFile.fileName = Path.GetDirectoryName(bundleFileName) + "\\" + sharedFile.fileName; + var loadedSharedFile = b_assetsfileList.Find(aFile => aFile.filePath == sharedFile.fileName); + if (loadedSharedFile != null) { sharedFile.Index = assetsfileList.IndexOf(loadedSharedFile); } + } + } + } + } + + + private void extractBundleToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog openBundleDialog = new OpenFileDialog(); + openBundleDialog.Filter = "Unity bundle files|*.unity3d; *.unity3d.lz4; *.assetbundle; *.bundle; *.bytes|All files (use at your own risk!)|*.*"; + openBundleDialog.FilterIndex = 1; + openBundleDialog.RestoreDirectory = true; + openBundleDialog.Multiselect = true; + + if (openBundleDialog.ShowDialog() == DialogResult.OK) + { + int extractedCount = extractBundleFile(openBundleDialog.FileName); + + StatusStripUpdate("Finished extracting " + extractedCount.ToString() + " files."); + } + } + + private void extractFolderToolStripMenuItem_Click(object sender, EventArgs e) + { + int extractedCount = 0; + List bundleFiles = new List(); + + /*FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog(); + folderBrowserDialog1.Description = "Extract all Unity bundles from folder and subfolders"; + folderBrowserDialog1.ShowNewFolderButton = false;*/ + + if (openFolderDialog1.ShowDialog() == DialogResult.OK) + { + string startPath = openFolderDialog1.FileName; + if (Path.GetFileName(startPath) == "Select folder") + { startPath = Path.GetDirectoryName(startPath); } + + string[] fileTypes = new string[6] { "*.unity3d", "*.unity3d.lz4", "*.assetbundle", "*.assetbundle-*", "*.bundle", "*.bytes" }; + foreach (var fileType in fileTypes) + { + string[] fileNames = Directory.GetFiles(startPath, fileType, SearchOption.AllDirectories); + bundleFiles.AddRange(fileNames); + } + + foreach (var fileName in bundleFiles) + { + extractedCount += extractBundleFile(fileName); + } + + StatusStripUpdate("Finished extracting " + extractedCount.ToString() + " files."); + } + } + + private int extractBundleFile(string bundleFileName) + { + int extractedCount = 0; + + StatusStripUpdate("Decompressing " + Path.GetFileName(bundleFileName) + " ,,,"); + + string extractPath = bundleFileName + "_unpacked\\"; + Directory.CreateDirectory(extractPath); + + using (BundleFile b_File = new BundleFile(bundleFileName)) + { + foreach (var memFile in b_File.MemoryAssetsFileList) + { + string filePath = extractPath + memFile.fileName.Replace('/','\\'); + if (!Directory.Exists(Path.GetDirectoryName(filePath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + + } + if (File.Exists(filePath)) + { + StatusStripUpdate("File " + memFile.fileName + " already exists"); + } + else + { + StatusStripUpdate("Extracting " + Path.GetFileName(memFile.fileName)); + extractedCount += 1; + + using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write)) + { + memFile.memStream.WriteTo(file); + } + } + } + } + + return extractedCount; + } + + + + private void enablePreview_Check(object sender, EventArgs e) + { + if (lastLoadedAsset != null) + { + switch (lastLoadedAsset.Type2) + { + case 28: + { + if (enablePreview.Checked && imageTexture != null) + { + previewPanel.BackgroundImage = imageTexture; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + } + else + { + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + } + } + break; + case 48: + case 49: + textPreviewBox.Visible = !textPreviewBox.Visible; + break; + case 128: + fontPreviewBox.Visible = !fontPreviewBox.Visible; + break; + case 83: + { + FMODpanel.Visible = !FMODpanel.Visible; + + FMOD.RESULT result; + + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + + //channel = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); ; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODpauseButton.Text = "Pause"; + //FMODinfoLabel.Text = ""; + } + else if (enablePreview.Checked) + { + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + timer.Start(); + FMODstatusLabel.Text = "Playing"; + //FMODinfoLabel.Text = FMODfrequency.ToString(); + } + } + + break; + } + + } + + } + else if (lastSelectedItem != null && enablePreview.Checked) + { + lastLoadedAsset = lastSelectedItem; + PreviewAsset(lastLoadedAsset); + } + + Properties.Settings.Default["enablePreview"] = enablePreview.Checked; + Properties.Settings.Default.Save(); + } + + private void displayAssetInfo_Check(object sender, EventArgs e) + { + if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } + else { assetInfoLabel.Visible = false; } + + Properties.Settings.Default["displayInfo"] = displayInfo.Checked; + Properties.Settings.Default.Save(); + } + + private void MenuItem_CheckedChanged(object sender, EventArgs e) + { + Properties.Settings.Default[((ToolStripMenuItem)sender).Name] = ((ToolStripMenuItem)sender).Checked; + Properties.Settings.Default.Save(); + } + + private void assetGroupOptions_SelectedIndexChanged(object sender, EventArgs e) + { + Properties.Settings.Default["assetGroupOption"] = ((ToolStripComboBox)sender).SelectedIndex; + Properties.Settings.Default.Save(); + } + + private void showExpOpt_Click(object sender, EventArgs e) + { + ExportOptions exportOpt = new ExportOptions(); + exportOpt.ShowDialog(); + } + + private void aboutToolStripMenuItem_Click(object sender, EventArgs e) + { + AboutBox aboutWindow = new AboutBox(); + aboutWindow.ShowDialog(); + } + + + private void BuildAssetStrucutres() + { + #region first loop - read asset data & create list + StatusStripUpdate("Building asset list..."); + assetListView.BeginUpdate(); + + string fileIDfmt = "D" + assetsfileList.Count.ToString().Length.ToString(); + + foreach (var assetsFile in assetsfileList) + { + var a_Stream = assetsFile.a_Stream; + var fileGen = assetsFile.fileGen; + //var m_version = assetsFile.m_version; + var version = assetsFile.version; + string fileID = "1" + assetsfileList.IndexOf(assetsFile).ToString(fileIDfmt); + + //ListViewGroup assetGroup = new ListViewGroup(Path.GetFileName(assetsFile.filePath)); + + foreach (var asset in assetsFile.preloadTable.Values) + { + asset.uniqueID = fileID + asset.uniqueID; + a_Stream.Position = asset.Offset; + + switch (asset.Type2) + { + case 1: //GameObject + { + GameObject m_GameObject = new GameObject(asset); + + //asset.Text = m_GameObject.m_Name; + asset.specificIndex = assetsFile.GameObjectList.Count; + assetsFile.GameObjectList.Add(m_GameObject); + break; + } + case 4: //Transform + { + Transform m_Transform = new Transform(asset); + + asset.specificIndex = assetsFile.TransformList.Count; + assetsFile.TransformList.Add(m_Transform); + break; + } + case 224: //RectTransform + { + RectTransform m_Rect = new RectTransform(asset); + + asset.specificIndex = assetsFile.TransformList.Count; + assetsFile.TransformList.Add(m_Rect.m_Transform); + break; + } + //case 21: //Material + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, false); + + asset.Text = m_Texture2D.m_Name; + asset.exportSize = 128 + m_Texture2D.image_data_size; + + #region Get Info Text + asset.InfoText = "Width: " + m_Texture2D.m_Width.ToString() + "\nHeight: " + m_Texture2D.m_Height.ToString() + "\nFormat: "; + + switch (m_Texture2D.m_TextureFormat) + { + case 1: asset.InfoText += "Alpha8"; break; + case 2: asset.InfoText += "ARGB 4.4.4.4"; break; + case 3: asset.InfoText += "BGR 8.8.8"; break; + case 4: asset.InfoText += "GRAB 8.8.8.8"; break; + case 5: asset.InfoText += "BGRA 8.8.8.8"; break; + case 7: asset.InfoText += "RGB 5.6.5"; break; + case 10: asset.InfoText += "RGB DXT1"; break; + case 12: asset.InfoText += "ARGB DXT5"; break; + case 13: asset.InfoText += "RGBA 4.4.4.4"; break; + case 30: asset.InfoText += "PVRTC_RGB2"; asset.exportSize -= 76; break; + case 31: asset.InfoText += "PVRTC_RGBA2"; asset.exportSize -= 76; break; + case 32: asset.InfoText += "PVRTC_RGB4"; asset.exportSize = 52; break; + case 33: asset.InfoText += "PVRTC_RGBA4"; asset.exportSize -= 76; break; + case 34: asset.InfoText += "ETC_RGB4"; asset.exportSize -= 76; break; + default: asset.InfoText += "unknown"; asset.exportSize -= 128; break; + } + + switch (m_Texture2D.m_FilterMode) + { + case 0: asset.InfoText += "\nFilter Mode: Point "; break; + case 1: asset.InfoText += "\nFilter Mode: Bilinear "; break; + case 2: asset.InfoText += "\nFilter Mode: Trilinear "; break; + + } + + asset.InfoText += "\nAnisotropic level: " + m_Texture2D.m_Aniso.ToString() + "\nMip map bias: " + m_Texture2D.m_MipBias.ToString(); + + switch (m_Texture2D.m_WrapMode) + { + case 0: asset.InfoText += "\nWrap mode: Repeat"; break; + case 1: asset.InfoText += "\nWrap mode: Clamp"; break; + } + #endregion + + assetsFile.exportableAssets.Add(asset); + break; + } + case 49: //TextAsset + { + TextAsset m_TextAsset = new TextAsset(asset, false); + + asset.Text = m_TextAsset.m_Name; + asset.exportSize = m_TextAsset.exportSize; + assetsFile.exportableAssets.Add(asset); + break; + } + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, false); + + asset.Text = m_AudioClip.m_Name; + asset.exportSize = (int)m_AudioClip.m_Size; + assetsFile.exportableAssets.Add(asset); + break; + } + case 48: //Shader + case 89: //CubeMap + case 128: //Font + { + asset.Text = a_Stream.ReadAlignedString(a_Stream.ReadInt32()); + assetsFile.exportableAssets.Add(asset); + break; + } + case 129: //PlayerSettings + { + PlayerSettings plSet = new PlayerSettings(asset); + productName = plSet.productName; + base.Text = "Unity Studio - " + productName + " - " + assetsFile.m_Version ; + break; + } + + } + + if (asset.Text == "") { asset.Text = asset.TypeString + " #" + asset.uniqueID; } + asset.SubItems.AddRange(new string[] { asset.TypeString, asset.exportSize.ToString() }); + } + + exportableAssets.AddRange(assetsFile.exportableAssets); + //if (assetGroup.Items.Count > 0) { listView1.Groups.Add(assetGroup); } + } + + visibleAssets = exportableAssets; + assetListView.VirtualListSize = visibleAssets.Count; + + assetListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.ColumnContent); + assetListView.AutoResizeColumn(2, ColumnHeaderAutoResizeStyle.ColumnContent); + resizeNameColumn(); + + assetListView.EndUpdate(); + #endregion + + #region second loop - build tree structure + StatusStripUpdate("Building tree structure..."); + sceneTreeView.BeginUpdate(); + foreach (var assetsFile in assetsfileList) + { + GameObject fileNode = new GameObject(null); + fileNode.Text = Path.GetFileName(assetsFile.filePath); + + foreach (var m_GameObject in assetsFile.GameObjectList) + { + var parentNode = fileNode; + + Transform m_Transform; + if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) + { + Transform m_Father; + if (assetsfileList.TryGetTransform(m_Transform.m_Father, out m_Father)) + { + //GameObject Parent; + if (assetsfileList.TryGetGameObject(m_Father.m_GameObject, out parentNode)) + { + //parentNode = Parent; + } + } + } + + parentNode.Nodes.Add(m_GameObject); + } + + + if (fileNode.Nodes.Count == 0) { fileNode.Text += " (no children)"; } + sceneTreeView.Nodes.Add(fileNode); + } + sceneTreeView.EndUpdate(); + #endregion + + if (File.Exists(mainPath + "\\materials.json")) + { + string matLine = ""; + using (StreamReader reader = File.OpenText(mainPath + "\\materials.json")) + { matLine = reader.ReadToEnd(); } + + jsonMats = new JavaScriptSerializer().Deserialize>>(matLine); + //var jsonMats = new JavaScriptSerializer().DeserializeObject(matLine); + } + + StatusStripUpdate("Finished loading " + assetsfileList.Count.ToString() + " files with " + (assetListView.Items.Count + sceneTreeView.Nodes.Count).ToString() + " exportable assets."); + + progressBar1.Value = 0; + treeSearch.Select(); + TexEnv dsd = new TexEnv(); + } + + private void assetListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + e.Item = visibleAssets[e.ItemIndex]; + } + + + + private void tabPageSelected(object sender, TabControlEventArgs e) + { + if (e.TabPageIndex == 0) { treeSearch.Select(); } + else if (e.TabPageIndex == 1) { listSearch.Select(); } + } + + private void recurseTreeCheck(TreeNodeCollection start) + { + foreach (GameObject GObject in start) + { + if (GObject.Text.Like(treeSearch.Text)) + { + GObject.Checked = !GObject.Checked; + if (GObject.Checked) { GObject.EnsureVisible(); } + } + else { recurseTreeCheck(GObject.Nodes); } + } + } + + private void treeSearch_MouseEnter(object sender, EventArgs e) + { + treeTip.Show("Search with * ? widcards. Enter to scroll through results, Ctrl+Enter to select all results.", treeSearch, 5000); + } + + private void treeSearch_Enter(object sender, EventArgs e) + { + if (treeSearch.Text == " Search ") + { + treeSearch.Text = ""; + treeSearch.ForeColor = System.Drawing.SystemColors.WindowText; + } + } + + private void treeSearch_Leave(object sender, EventArgs e) + { + if (treeSearch.Text == "") + { + treeSearch.Text = " Search "; + treeSearch.ForeColor = System.Drawing.SystemColors.GrayText; + } + } + + private void treeSearch_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + if (e.Modifiers == Keys.Control) //toggle all matching nodes //skip children? + { + sceneTreeView.BeginUpdate(); + //loop assetsFileList? + /*foreach (var AFile in assetsfileList) + { + foreach (var GObject in AFile.GameObjectList) + { + if (GObject.Text.Like(treeSearch.Text)) + { + GObject.Checked = true; + GObject.EnsureVisible(); + } + } + }*/ + + //loop TreeView to avoid checking children already checked by parent + recurseTreeCheck(sceneTreeView.Nodes); + sceneTreeView.EndUpdate(); + } + else //make visible one by one + { + bool foundNode = false; + + while (!foundNode && lastAFile < assetsfileList.Count) + { + var AFile = assetsfileList[lastAFile]; + + while (!foundNode && lastGObject < AFile.GameObjectList.Count) + { + var GObject = AFile.GameObjectList[lastGObject]; + if (GObject.Text.Like(treeSearch.Text)) + { + foundNode = true; + + GObject.EnsureVisible(); + sceneTreeView.SelectedNode = GObject; + + lastGObject++; + return; + } + + lastGObject++; + } + + lastAFile++; + lastGObject = 0; + } + lastAFile = 0; + } + } + } + + private void sceneTreeView_AfterCheck(object sender, TreeViewEventArgs e) + { + foreach (GameObject childNode in e.Node.Nodes) + { + childNode.Checked = e.Node.Checked; + } + } + + + private void ListSearchTextChanged(object sender, EventArgs e) + { + if (startFilter) + { + assetListView.BeginUpdate(); + assetListView.SelectedIndices.Clear(); + //visibleListAssets = exportableAssets.FindAll(ListAsset => ListAsset.Text.StartsWith(ListSearch.Text, System.StringComparison.CurrentCultureIgnoreCase)); + visibleAssets = exportableAssets.FindAll(ListAsset => ListAsset.Text.IndexOf(listSearch.Text, System.StringComparison.CurrentCultureIgnoreCase) >= 0); + assetListView.VirtualListSize = visibleAssets.Count; + assetListView.EndUpdate(); + } + } + + private void listSearch_Enter(object sender, EventArgs e) + { + if (listSearch.Text == " Filter ") + { + listSearch.Text = ""; + listSearch.ForeColor = System.Drawing.SystemColors.WindowText; + startFilter = true; + } + } + + private void listSearch_Leave(object sender, EventArgs e) + { + if (listSearch.Text == "") + { + startFilter = false; + listSearch.Text = " Filter "; + listSearch.ForeColor = System.Drawing.SystemColors.GrayText; + } + } + + private void assetListView_ColumnClick(object sender, ColumnClickEventArgs e) + { + assetListView.BeginUpdate(); + assetListView.SelectedIndices.Clear(); + switch (e.Column) + { + case 0: + if (isNameSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.Text.CompareTo(y.Text)); + isNameSorted = true; + } + + break; + case 1: + if (isTypeSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.TypeString.CompareTo(y.TypeString)); + isTypeSorted = true; + } + break; + case 2: + if (isSizeSorted) { visibleAssets.Reverse(); } + else + { + visibleAssets.Sort((x, y) => x.exportSize.CompareTo(y.exportSize)); + isSizeSorted = true; + } + break; + } + assetListView.EndUpdate(); + } + + private void resizeNameColumn() + { + var vscroll = ((float)assetListView.VirtualListSize / (float)assetListView.Height) > 0.0567f; + columnHeaderName.Width = assetListView.Width - columnHeaderType.Width - columnHeaderSize.Width - (vscroll ? 25 : 5); + } + + private void selectAsset(object sender, ListViewItemSelectionChangedEventArgs e) + { + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + assetInfoLabel.Visible = false; + assetInfoLabel.Text = null; + textPreviewBox.Visible = false; + fontPreviewBox.Visible = false; + FMODpanel.Visible = false; + lastLoadedAsset = null; + + FMOD.RESULT result; + if (sound != null) + { + result = sound.release(); + ERRCHECK(result); + } + sound = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / 0:00.0"; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODinfoLabel.Text = ""; + + lastSelectedItem = (AssetPreloadData)e.Item; + + if (e.IsSelected) + { + assetInfoLabel.Text = lastSelectedItem.InfoText; + if (displayInfo.Checked && assetInfoLabel.Text != null) { assetInfoLabel.Visible = true; } //only display the label if asset has info text + + if (enablePreview.Checked) + { + lastLoadedAsset = lastSelectedItem; + PreviewAsset(lastLoadedAsset); + } + } + } + + + private void splitContainer1_Resize(object sender, EventArgs e) + { + resizeNameColumn(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + resizeNameColumn(); + } + + + private void PreviewAsset(AssetPreloadData asset) + { + switch (asset.Type2) + { + #region Texture2D + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, true); + + if (m_Texture2D.m_TextureFormat < 30) + { + byte[] imageBuffer = new byte[128 + m_Texture2D.image_data_size]; + + imageBuffer[0] = 0x44; + imageBuffer[1] = 0x44; + imageBuffer[2] = 0x53; + imageBuffer[3] = 0x20; + imageBuffer[4] = 0x7c; + + BitConverter.GetBytes(m_Texture2D.dwFlags).CopyTo(imageBuffer, 8); + BitConverter.GetBytes(m_Texture2D.m_Height).CopyTo(imageBuffer, 12); + BitConverter.GetBytes(m_Texture2D.m_Width).CopyTo(imageBuffer, 16); + BitConverter.GetBytes(m_Texture2D.dwPitchOrLinearSize).CopyTo(imageBuffer, 20); + BitConverter.GetBytes(m_Texture2D.dwMipMapCount).CopyTo(imageBuffer, 28); + BitConverter.GetBytes(m_Texture2D.dwSize).CopyTo(imageBuffer, 76); + BitConverter.GetBytes(m_Texture2D.dwFlags2).CopyTo(imageBuffer, 80); + BitConverter.GetBytes(m_Texture2D.dwFourCC).CopyTo(imageBuffer, 84); + BitConverter.GetBytes(m_Texture2D.dwRGBBitCount).CopyTo(imageBuffer, 88); + BitConverter.GetBytes(m_Texture2D.dwRBitMask).CopyTo(imageBuffer, 92); + BitConverter.GetBytes(m_Texture2D.dwGBitMask).CopyTo(imageBuffer, 96); + BitConverter.GetBytes(m_Texture2D.dwBBitMask).CopyTo(imageBuffer, 100); + BitConverter.GetBytes(m_Texture2D.dwABitMask).CopyTo(imageBuffer, 104); + BitConverter.GetBytes(m_Texture2D.dwCaps).CopyTo(imageBuffer, 108); + BitConverter.GetBytes(m_Texture2D.dwCaps2).CopyTo(imageBuffer, 112); + + m_Texture2D.image_data.CopyTo(imageBuffer, 128); + + imageTexture = DDSDataToBMP(imageBuffer); + imageTexture.RotateFlip(RotateFlipType.RotateNoneFlipY); + previewPanel.BackgroundImage = imageTexture; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom; + } + break; + } + #endregion + #region AudioClip + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, true); + + if (m_AudioClip.m_Type != 22 && m_AudioClip.m_Type != 1) + { + //MemoryStream memoryStream = new MemoryStream(m_AudioData, true); + //System.Media.SoundPlayer soundPlayer = new System.Media.SoundPlayer(memoryStream); + //soundPlayer.Play(); + + //uint version = 0; + FMOD.RESULT result; + FMOD.CREATESOUNDEXINFO exinfo = new FMOD.CREATESOUNDEXINFO(); + + /*result = FMOD.Factory.System_Create(ref system); + ERRCHECK(result); + + result = system.getVersion(ref version); + ERRCHECK(result); + if (version < FMOD.VERSION.number) + { + MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + "."); + Application.Exit(); + } + + result = system.init(1, FMOD.INITFLAGS.NORMAL, (IntPtr)null); + ERRCHECK(result);*/ + + exinfo.cbsize = Marshal.SizeOf(exinfo); + exinfo.length = (uint)m_AudioClip.m_Size; + + result = system.createSound(m_AudioClip.m_AudioData, (FMOD.MODE.HARDWARE | FMOD.MODE.OPENMEMORY | loopMode), ref exinfo, ref sound); + ERRCHECK(result); + + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + result = sound.getLength(ref FMODlenms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + timer.Start(); + FMODstatusLabel.Text = "Playing"; + FMODpanel.Visible = true; + + result = channel.getFrequency(ref FMODfrequency); + ERRCHECK(result); + FMODinfoLabel.Text = FMODfrequency.ToString() + " Hz"; + } + else { StatusStripUpdate("Unsuported format"); } + break; + } + #endregion + #region Shader & TextAsset + case 48: + case 49: + { + TextAsset m_TextAsset = new TextAsset(asset, true); + + string m_Script_Text = UnicodeEncoding.UTF8.GetString(m_TextAsset.m_Script); + m_Script_Text = Regex.Replace(m_Script_Text, "(? 0) + { + IntPtr data = Marshal.AllocCoTaskMem(m_Font.m_FontData.Length); + Marshal.Copy(m_Font.m_FontData, 0, data, m_Font.m_FontData.Length); + + System.Drawing.Text.PrivateFontCollection pfc = new System.Drawing.Text.PrivateFontCollection(); + // We HAVE to do this to register the font to the system (Weird .NET bug !) + uint cFonts = 0; + AddFontMemResourceEx(data, (uint)m_Font.m_FontData.Length, IntPtr.Zero, ref cFonts); + + pfc.AddMemoryFont(data, m_Font.m_FontData.Length); + System.Runtime.InteropServices.Marshal.FreeCoTaskMem(data); + + //textPreviewBox.Font = new Font(pfc.Families[0], 16, FontStyle.Regular); + //textPreviewBox.Text = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ\r\n1234567890.:,;'\"(!?)+-*/=\r\nThe quick brown fox jumps over the lazy dog. 1234567890"; + fontPreviewBox.SelectionStart = 0; + fontPreviewBox.SelectionLength = 80; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 16, FontStyle.Regular); + fontPreviewBox.SelectionStart = 81; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 12, FontStyle.Regular); + fontPreviewBox.SelectionStart = 138; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 18, FontStyle.Regular); + fontPreviewBox.SelectionStart = 195; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 24, FontStyle.Regular); + fontPreviewBox.SelectionStart = 252; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 36, FontStyle.Regular); + fontPreviewBox.SelectionStart = 309; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 48, FontStyle.Regular); + fontPreviewBox.SelectionStart = 366; + fontPreviewBox.SelectionLength = 56; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 60, FontStyle.Regular); + fontPreviewBox.SelectionStart = 423; + fontPreviewBox.SelectionLength = 55; + fontPreviewBox.SelectionFont = new Font(pfc.Families[0], 72, FontStyle.Regular); + fontPreviewBox.Visible = true; + } + + break; + } + #endregion + } + } + + public static Bitmap DDSDataToBMP(byte[] DDSData) + { + // Create a DevIL image "name" (which is actually a number) + int img_name; + Il.ilGenImages(1, out img_name); + Il.ilBindImage(img_name); + + // Load the DDS file into the bound DevIL image + Il.ilLoadL(Il.IL_DDS, DDSData, DDSData.Length); + + // Set a few size variables that will simplify later code + + int ImgWidth = Il.ilGetInteger(Il.IL_IMAGE_WIDTH); + int ImgHeight = Il.ilGetInteger(Il.IL_IMAGE_HEIGHT); + Rectangle rect = new Rectangle(0, 0, ImgWidth, ImgHeight); + + // Convert the DevIL image to a pixel byte array to copy into Bitmap + Il.ilConvertImage(Il.IL_BGRA, Il.IL_UNSIGNED_BYTE); + + // Create a Bitmap to copy the image into, and prepare it to get data + Bitmap bmp = new Bitmap(ImgWidth, ImgHeight); + BitmapData bmd = + bmp.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); + + // Copy the pixel byte array from the DevIL image to the Bitmap + Il.ilCopyPixels(0, 0, 0, + Il.ilGetInteger(Il.IL_IMAGE_WIDTH), + Il.ilGetInteger(Il.IL_IMAGE_HEIGHT), + 1, Il.IL_BGRA, Il.IL_UNSIGNED_BYTE, + bmd.Scan0); + + // Clean up and return Bitmap + Il.ilDeleteImages(1, ref img_name); + bmp.UnlockBits(bmd); + return bmp; + } + + private void FMODinit() + { + FMOD.RESULT result; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / 0:00.0"; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + + if (sound != null) + { + result = sound.release(); + ERRCHECK(result); + sound = null; + } + + uint version = 0; + + result = FMOD.Factory.System_Create(ref system); + ERRCHECK(result); + + result = system.getVersion(ref version); + ERRCHECK(result); + if (version < FMOD.VERSION.number) + { + MessageBox.Show("Error! You are using an old version of FMOD " + version.ToString("X") + ". This program requires " + FMOD.VERSION.number.ToString("X") + "."); + Application.Exit(); + } + + result = system.init(1, FMOD.INITFLAGS.NORMAL, (IntPtr)null); + ERRCHECK(result); + + result = system.getMasterSoundGroup(ref masterSoundGroup); + ERRCHECK(result); + + result = masterSoundGroup.setVolume(FMODVolume); + ERRCHECK(result); + } + + private void FMODplayButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + if (channel != null) + { + timer.Start(); + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + FMODpauseButton.Text = "Pause"; + } + else + { + result = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + FMODstatusLabel.Text = "Playing"; + //FMODinfoLabel.Text = FMODfrequency.ToString(); + + uint newms = 0; + + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + + result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + } + } + } + + private void FMODpauseButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + + if (channel != null) + { + bool playing = false; + bool paused = false; + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.getPaused(ref paused); + ERRCHECK(result); + result = channel.setPaused(!paused); + ERRCHECK(result); + + //FMODstatusLabel.Text = (!paused ? "Paused" : playing ? "Playing" : "Stopped"); + //FMODpauseButton.Text = (!paused ? "Resume" : playing ? "Pause" : "Pause"); + + if (paused) + { + FMODstatusLabel.Text = (playing ? "Playing" : "Stopped"); + FMODpauseButton.Text = "Pause"; + timer.Start(); + } + else + { + FMODstatusLabel.Text = "Paused"; + FMODpauseButton.Text = "Resume"; + timer.Stop(); + } + } + } + } + + private void FMODstopButton_Click(object sender, EventArgs e) + { + FMOD.RESULT result; + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) + { + result = channel.stop(); + ERRCHECK(result); + //channel = null; + timer.Stop(); + FMODtimerLabel.Text = "0:00.0 / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); ; + FMODstatusLabel.Text = "Stopped"; + FMODprogressBar.Value = 0; + FMODpauseButton.Text = "Pause"; + //FMODinfoLabel.Text = ""; + } + } + } + + private void FMODloopButton_CheckedChanged(object sender, EventArgs e) + { + FMOD.RESULT result; + + if (FMODloopButton.Checked) + { + loopMode = FMOD.MODE.LOOP_NORMAL; + } + else + { + loopMode = FMOD.MODE.LOOP_OFF; + } + + if (sound != null) + { + result = sound.setMode(loopMode); + ERRCHECK(result); + } + + if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool paused = false; + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing || paused) + { + result = channel.setMode(loopMode); + ERRCHECK(result); + } + /*else + { + /esult = system.playSound(FMOD.CHANNELINDEX.FREE, sound, false, ref channel); + ERRCHECK(result); + + result = channel.setMode(loopMode); + ERRCHECK(result); + }*/ + } + } + + private void FMODvolumeBar_ValueChanged(object sender, EventArgs e) + { + FMOD.RESULT result; + FMODVolume = Convert.ToSingle(FMODvolumeBar.Value) / 10; + + result = masterSoundGroup.setVolume(FMODVolume); + ERRCHECK(result); + + /*if (channel != null) + { + bool playing = false; + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool paused = false; + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing || paused) + { + result = channel.setVolume(FMODVolume); + ERRCHECK(result); + } + }*/ + } + + private void FMODprogressBar_Scroll(object sender, EventArgs e) + { + uint newms = 0; + + if (channel != null) + { + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + FMODtimerLabel.Text = (newms / 1000 / 60) + ":" + (newms / 1000 % 60) + "." + (newms / 10 % 100) + "/" + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); + } + } + + private void FMODprogressBar_MouseDown(object sender, MouseEventArgs e) + { + timer.Stop(); + } + + private void FMODprogressBar_MouseUp(object sender, MouseEventArgs e) + { + FMOD.RESULT result; + uint newms = 0; + + if (channel != null) + { + newms = FMODlenms / 1000 * (uint)FMODprogressBar.Value; + + result = channel.setPosition(newms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + bool playing = false; + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + if (playing) { timer.Start(); } + } + } + + private void timer_Tick(object sender, EventArgs e) + { + FMOD.RESULT result; + uint ms = 0; + bool playing = false; + bool paused = false; + + if (channel != null) + { + result = channel.getPosition(ref ms, FMOD.TIMEUNIT.MS); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + result = channel.isPlaying(ref playing); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + + result = channel.getPaused(ref paused); + if ((result != FMOD.RESULT.OK) && (result != FMOD.RESULT.ERR_INVALID_HANDLE)) + { + ERRCHECK(result); + } + } + + //statusBar.Text = "Time " + (ms / 1000 / 60) + ":" + (ms / 1000 % 60) + ":" + (ms / 10 % 100) + "/" + (lenms / 1000 / 60) + ":" + (lenms / 1000 % 60) + ":" + (lenms / 10 % 100) + " : " + (paused ? "Paused " : playing ? "Playing" : "Stopped"); + FMODtimerLabel.Text = (ms / 1000 / 60) + ":" + (ms / 1000 % 60) + "." + (ms / 10 % 100) + " / " + (FMODlenms / 1000 / 60) + ":" + (FMODlenms / 1000 % 60) + "." + (FMODlenms / 10 % 100); + FMODprogressBar.Value = (int)(ms * 1000 / FMODlenms); + FMODstatusLabel.Text = (paused ? "Paused " : playing ? "Playing" : "Stopped"); + + if (system != null) + { + system.update(); + } + } + + private void ERRCHECK(FMOD.RESULT result) + { + if (result != FMOD.RESULT.OK) + { + FMODinit(); + MessageBox.Show("FMOD error! " + result + " - " + FMOD.Error.String(result)); + //Environment.Exit(-1); + } + } + + + private void Export3DObjects_Click(object sender, EventArgs e) + { + if (sceneTreeView.Nodes.Count > 0) + { + bool exportSwitch = (((ToolStripItem)sender).Name == "exportAll3DMenuItem") ? true : false; + + + var timestamp = DateTime.Now; + saveFileDialog1.FileName = productName + timestamp.ToString("_yy_MM_dd__HH_mm_ss"); + //extension will be added by the file save dialog + + if (saveFileDialog1.ShowDialog() == DialogResult.OK) + { + switch ((bool)Properties.Settings.Default["showExpOpt"]) + { + case true: + ExportOptions exportOpt = new ExportOptions(); + if (exportOpt.ShowDialog() == DialogResult.OK) { goto case false; } + break; + case false: + switch (saveFileDialog1.FilterIndex) + { + case 1: + WriteFBX(saveFileDialog1.FileName, exportSwitch); + break; + case 2: + break; + } + + if (openAfterExport.Checked && File.Exists(saveFileDialog1.FileName)) { System.Diagnostics.Process.Start(saveFileDialog1.FileName); } + break; + } + } + + } + else { StatusStripUpdate("No Objects available for export"); } + } + + public void WriteFBX(string FBXfile, bool allNodes) + { + var timestamp = DateTime.Now; + + using (StreamWriter FBXwriter = new StreamWriter(FBXfile)) + { + StringBuilder fbx = new StringBuilder(); + StringBuilder ob = new StringBuilder(); //Objects builder + StringBuilder cb = new StringBuilder(); //Connections builder + cb.Append("\n}\n");//Objects end + cb.Append("\nConnections: {"); + + HashSet MeshList = new HashSet(); + HashSet MaterialList = new HashSet(); + HashSet TextureList = new HashSet(); + + int ModelCount = 0; + int GeometryCount = 0; + int MaterialCount = 0; + int TextureCount = 0; + + //using m_PathID as unique ID would fail because it could be a negative number (Hearthstone syndrome) + //consider using uint + //no, do something smarter + + #region write generic FBX data + fbx.Append("; FBX 7.1.0 project file"); + fbx.Append("\nFBXHeaderExtension: {\n\tFBXHeaderVersion: 1003\n\tFBXVersion: 7100\n\tCreationTimeStamp: {\n\t\tVersion: 1000"); + fbx.Append("\n\t\tYear: " + timestamp.Year); + fbx.Append("\n\t\tMonth: " + timestamp.Month); + fbx.Append("\n\t\tDay: " + timestamp.Day); + fbx.Append("\n\t\tHour: " + timestamp.Hour); + fbx.Append("\n\t\tMinute: " + timestamp.Minute); + fbx.Append("\n\t\tSecond: " + timestamp.Second); + fbx.Append("\n\t\tMillisecond: " + timestamp.Millisecond); + fbx.Append("\n\t}\n\tCreator: \"Unity Studio by Chipicao\"\n}\n"); + + fbx.Append("\nGlobalSettings: {"); + fbx.Append("\n\tVersion: 1000"); + fbx.Append("\n\tProperties70: {"); + fbx.Append("\n\t\tP: \"UpAxis\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"UpAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"FrontAxis\", \"int\", \"Integer\", \"\",2"); + fbx.Append("\n\t\tP: \"FrontAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"CoordAxis\", \"int\", \"Integer\", \"\",0"); + fbx.Append("\n\t\tP: \"CoordAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"OriginalUpAxis\", \"int\", \"Integer\", \"\",1"); + fbx.Append("\n\t\tP: \"OriginalUpAxisSign\", \"int\", \"Integer\", \"\",1"); + fbx.AppendFormat("\n\t\tP: \"UnitScaleFactor\", \"double\", \"Number\", \"\",{0}", Properties.Settings.Default["scaleFactor"]); + fbx.Append("\n\t\tP: \"OriginalUnitScaleFactor\", \"double\", \"Number\", \"\",1.0"); + //sb.Append("\n\t\tP: \"AmbientColor\", \"ColorRGB\", \"Color\", \"\",0,0,0"); + //sb.Append("\n\t\tP: \"DefaultCamera\", \"KString\", \"\", \"\", \"Producer Perspective\""); + //sb.Append("\n\t\tP: \"TimeMode\", \"enum\", \"\", \"\",6"); + //sb.Append("\n\t\tP: \"TimeProtocol\", \"enum\", \"\", \"\",2"); + //sb.Append("\n\t\tP: \"SnapOnFrameMode\", \"enum\", \"\", \"\",0"); + //sb.Append("\n\t\tP: \"TimeSpanStart\", \"KTime\", \"Time\", \"\",0"); + //sb.Append("\n\t\tP: \"TimeSpanStop\", \"KTime\", \"Time\", \"\",153953860000"); + //sb.Append("\n\t\tP: \"CustomFrameRate\", \"double\", \"Number\", \"\",-1"); + //sb.Append("\n\t\tP: \"TimeMarker\", \"Compound\", \"\", \"\""); + //sb.Append("\n\t\tP: \"CurrentTimeMarker\", \"int\", \"Integer\", \"\",-1"); + fbx.Append("\n\t}\n}\n"); + + fbx.Append("\nDocuments: {"); + fbx.Append("\n\tCount: 1"); + fbx.Append("\n\tDocument: 1234567890, \"\", \"Scene\" {"); + fbx.Append("\n\t\tProperties70: {"); + fbx.Append("\n\t\t\tP: \"SourceObject\", \"object\", \"\", \"\""); + fbx.Append("\n\t\t\tP: \"ActiveAnimStackName\", \"KString\", \"\", \"\", \"\""); + fbx.Append("\n\t\t}"); + fbx.Append("\n\t\tRootNode: 0"); + fbx.Append("\n\t}\n}\n"); + fbx.Append("\nReferences: {\n}\n"); + + fbx.Append("\nDefinitions: {"); + fbx.Append("\n\tVersion: 100"); + //fbx.AppendFormat("\n\tCount: {0}", 1 + srcModel.nodes.Count + FBXgeometryCount + srcModel.materials.Count + srcModel.usedTex.Count * 2); + + fbx.Append("\n\tObjectType: \"GlobalSettings\" {"); + fbx.Append("\n\t\tCount: 1"); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Model\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", ModelCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Geometry\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", GeometryCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Material\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", MaterialCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Texture\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.Append("\n\t}"); + + fbx.Append("\n\tObjectType: \"Video\" {"); + //fbx.AppendFormat("\n\t\tCount: {0}", TextureCount); + fbx.Append("\n\t}"); + fbx.Append("\n}\n"); + fbx.Append("\nObjects: {"); + + FBXwriter.Write(fbx); + fbx.Length = 0; + #endregion + + #region write Models, collect Mesh & Material objects + foreach (var assetsFile in assetsfileList) + { + foreach (var m_GameObject in assetsFile.GameObjectList) + { + if (m_GameObject.Checked || allNodes) + { + #region write Model and Transform + ob.AppendFormat("\n\tModel: {0}, \"Model::{1}\"", m_GameObject.uniqueID, m_GameObject.m_Name); + + if (m_GameObject.m_MeshFilter != null || m_GameObject.m_SkinnedMeshRenderer != null) + { + ob.Append(", \"Mesh\" {"); + } + else { ob.Append(", \"Null\" {"); } + + ob.Append("\n\t\tVersion: 232"); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"InheritType\", \"enum\", \"\", \"\",1"); + ob.Append("\n\t\t\tP: \"ScalingMax\", \"Vector3D\", \"Vector\", \"\",0,0,0"); + ob.Append("\n\t\t\tP: \"DefaultAttributeIndex\", \"int\", \"Integer\", \"\",0"); + + //connect model to parent + GameObject parentObject = (GameObject)m_GameObject.Parent; + if (parentObject.Checked || allNodes) + { + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", m_GameObject.uniqueID, parentObject.uniqueID); + //if parentObject is a file or folder node, it will have uniqueID 0 + } + else { cb.AppendFormat("\n\tC: \"OO\",{0},0", m_GameObject.uniqueID); }//connect to scene + + Transform m_Transform; + if (assetsfileList.TryGetTransform(m_GameObject.m_Transform, out m_Transform)) + { + float[] m_EulerRotation = QuatToEuler(new float[] { m_Transform.m_LocalRotation[0], -m_Transform.m_LocalRotation[1], -m_Transform.m_LocalRotation[2], m_Transform.m_LocalRotation[3] }); + + ob.AppendFormat("\n\t\t\tP: \"Lcl Translation\", \"Lcl Translation\", \"\", \"A\",{0},{1},{2}", -m_Transform.m_LocalPosition[0], m_Transform.m_LocalPosition[1], m_Transform.m_LocalPosition[2]); + ob.AppendFormat("\n\t\t\tP: \"Lcl Rotation\", \"Lcl Rotation\", \"\", \"A\",{0},{1},{2}", m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2]);//handedness is switched in quat + ob.AppendFormat("\n\t\t\tP: \"Lcl Scaling\", \"Lcl Scaling\", \"\", \"A\",{0},{1},{2}", m_Transform.m_LocalScale[0], m_Transform.m_LocalScale[1], m_Transform.m_LocalScale[2]); + } + + //mb.Append("\n\t\t\tP: \"UDP3DSMAX\", \"KString\", \"\", \"U\", \"MapChannel:1 = UVChannel_1&cr;&lf;MapChannel:2 = UVChannel_2&cr;&lf;\""); + //mb.Append("\n\t\t\tP: \"MaxHandle\", \"int\", \"Integer\", \"UH\",24"); + ob.Append("\n\t\t}"); + ob.Append("\n\t\tShading: T"); + ob.Append("\n\t\tCulling: \"CullingOff\"\n\t}"); + #endregion + + #region get MeshFilter + AssetPreloadData MeshFilterPD; + if (assetsfileList.TryGetPD(m_GameObject.m_MeshFilter, out MeshFilterPD)) + { + MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); + + AssetPreloadData MeshPD; + if (assetsfileList.TryGetPD(m_MeshFilter.m_Mesh, out MeshPD)) + { + MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + + /*if (m_GameObject.m_MeshFilter != null && m_GameObject.m_MeshFilter.m_FileID >= 0) + { + var MeshFilterAF = assetsfileList[m_GameObject.m_MeshFilter.m_FileID]; + AssetPreloadData MeshFilterPD; + if (MeshFilterAF.preloadTable.TryGetValue(m_GameObject.m_MeshFilter.m_PathID, out MeshFilterPD)) + { + MeshFilter m_MeshFilter = new MeshFilter(MeshFilterPD); + + if (m_MeshFilter.m_Mesh.m_FileID >= 0) + { + var MeshAF = assetsfileList[m_MeshFilter.m_Mesh.m_FileID]; + AssetPreloadData MeshPD; + if (MeshAF.preloadTable.TryGetValue(m_MeshFilter.m_Mesh.m_PathID, out MeshPD)) + { + MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + } + }*/ + #endregion + + #region get Renderer + AssetPreloadData RendererPD; + if (assetsfileList.TryGetPD(m_GameObject.m_Renderer, out RendererPD)) + { + Renderer m_Renderer = new Renderer(RendererPD); + + foreach (var MaterialPPtr in m_Renderer.m_Materials) + { + AssetPreloadData MaterialPD; + if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + + /*if (m_GameObject.m_Renderer != null && m_GameObject.m_Renderer.m_FileID >= 0) + { + var RendererAF = assetsfileList[m_GameObject.m_Renderer.m_FileID]; + AssetPreloadData RendererPD; + if (RendererAF.preloadTable.TryGetValue(m_GameObject.m_Renderer.m_PathID, out RendererPD)) + { + Renderer m_Renderer = new Renderer(RendererPD); + foreach (var MaterialPPtr in m_Renderer.m_Materials) + { + if (MaterialPPtr.m_FileID >= 0) + { + var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; + AssetPreloadData MaterialPD; + if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + } + }*/ + #endregion + + #region get SkinnedMeshRenderer + AssetPreloadData SkinnedMeshPD; + if (assetsfileList.TryGetPD(m_GameObject.m_SkinnedMeshRenderer, out SkinnedMeshPD)) + { + SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); + + foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) + { + AssetPreloadData MaterialPD; + if (assetsfileList.TryGetPD(MaterialPPtr, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + + AssetPreloadData MeshPD; + if (assetsfileList.TryGetPD(m_SkinnedMeshRenderer.m_Mesh, out MeshPD)) + { + MeshList.Add(MeshPD);//first collect meshes in unique list to use instances and avoid duplicate geometry + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + + /*if (m_GameObject.m_SkinnedMeshRenderer != null && m_GameObject.m_SkinnedMeshRenderer.m_FileID >= 0) + { + var SkinnedMeshAF = assetsfileList[m_GameObject.m_SkinnedMeshRenderer.m_FileID]; + AssetPreloadData SkinnedMeshPD; + if (SkinnedMeshAF.preloadTable.TryGetValue(m_GameObject.m_SkinnedMeshRenderer.m_PathID, out SkinnedMeshPD)) + { + SkinnedMeshRenderer m_SkinnedMeshRenderer = new SkinnedMeshRenderer(SkinnedMeshPD); + + foreach (var MaterialPPtr in m_SkinnedMeshRenderer.m_Materials) + { + if (MaterialPPtr.m_FileID >= 0) + { + var MaterialAF = assetsfileList[MaterialPPtr.m_FileID]; + AssetPreloadData MaterialPD; + if (MaterialAF.preloadTable.TryGetValue(MaterialPPtr.m_PathID, out MaterialPD)) + { + MaterialList.Add(MaterialPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MaterialPD.uniqueID, m_GameObject.uniqueID); + } + } + } + + if (m_SkinnedMeshRenderer.m_Mesh.m_FileID >= 0) + { + var MeshAF = assetsfileList[m_SkinnedMeshRenderer.m_Mesh.m_FileID]; + AssetPreloadData MeshPD; + if (MeshAF.preloadTable.TryGetValue(m_SkinnedMeshRenderer.m_Mesh.m_PathID, out MeshPD)) + { + MeshList.Add(MeshPD); + cb.AppendFormat("\n\tC: \"OO\",{0},{1}", MeshPD.uniqueID, m_GameObject.uniqueID); + } + } + } + }*/ + #endregion + + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { + FBXwriter.Write(ob); + ob.Length = 0; + } + } + } + } + #endregion + + #region write Geometry + foreach (var MeshPD in MeshList) + { + Mesh m_Mesh = new Mesh(MeshPD); + + if (m_Mesh.m_VertexCount > 0)//general failsafe + { + StatusStripUpdate("Writing Geometry: " + m_Mesh.m_Name); + + ob.AppendFormat("\n\tGeometry: {0}, \"Geometry::\", \"Mesh\" {{", MeshPD.uniqueID); + ob.Append("\n\t\tProperties70: {"); + var randomColor = RandomColorGenerator(MeshPD.uniqueID); + ob.AppendFormat("\n\t\t\tP: \"Color\", \"ColorRGB\", \"Color\", \"\",{0},{1},{2}", ((float)randomColor[0] / 255), ((float)randomColor[1] / 255), ((float)randomColor[2] / 255)); + ob.Append("\n\t\t}"); + + #region Vertices + ob.AppendFormat("\n\t\tVertices: *{0} {{\n\t\t\ta: ", m_Mesh.m_VertexCount * 3); + + int c = 3;//vertex components + //skip last value in half4 components + if (m_Mesh.m_Vertices.Length == m_Mesh.m_VertexCount * 4) { c++; } //haha + + //split arrays in groups of 2040 chars + uint f3Lines = m_Mesh.m_VertexCount / 40;//40 verts * 3 components * 17 max chars per float including comma + uint remf3Verts = m_Mesh.m_VertexCount % 40; + + uint f2Lines = m_Mesh.m_VertexCount / 60;//60 UVs * 2 components * 17 max chars per float including comma + uint remf2Verts = m_Mesh.m_VertexCount % 60; + + //this is fast but line length is not optimal + for (int l = 0; l < f3Lines; l++) + { + for (int v = 0; v < 40; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(l * 40 + v) * c], m_Mesh.m_Vertices[(l * 40 + v) * c + 1], m_Mesh.m_Vertices[(l * 40 + v) * c + 2]); + } + ob.Append("\n"); + } + + if (remf3Verts != 0) + { + for (int v = 0; v < remf3Verts; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Vertices[(f3Lines * 40 + v) * c], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Vertices[(f3Lines * 40 + v) * c + 2]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t}"); + #endregion + + #region Indices + //in order to test topology for triangles/quads we need to store submeshes and write each one as geometry, then link to Mesh Node + ob.AppendFormat("\n\t\tPolygonVertexIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + int iLines = m_Mesh.m_Indices.Count / 180; + int remTris = (m_Mesh.m_Indices.Count % 180) / 3; + + for (int l = 0; l < iLines; l++) + { + for (int f = 0; f < 60; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], (-m_Mesh.m_Indices[l * 180 + f * 3 + 1] - 1)); + } + ob.Append("\n"); + } + + if (remTris != 0) + { + for (int f = 0; f < remTris; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], (-m_Mesh.m_Indices[iLines * 180 + f * 3 + 1] - 1)); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t}"); + ob.Append("\n\t\tGeometryVersion: 124"); + #endregion + + #region Normals + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\tLayerElementNormal: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tNormals: *{0} {{\n\t\t\ta: ", (m_Mesh.m_VertexCount * 3)); + + if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 3) { c = 3; } + else if (m_Mesh.m_Normals.Length == m_Mesh.m_VertexCount * 4) { c = 4; } + + for (int l = 0; l < f3Lines; l++) + { + for (int v = 0; v < 40; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(l * 40 + v) * c], m_Mesh.m_Normals[(l * 40 + v) * c + 1], m_Mesh.m_Normals[(l * 40 + v) * c + 2]); + } + ob.Append("\n"); + } + + if (remf3Verts != 0) + { + for (int v = 0; v < remf3Verts; v++) + { + ob.AppendFormat("{0},{1},{2},", -m_Mesh.m_Normals[(f3Lines * 40 + v) * c], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 1], m_Mesh.m_Normals[(f3Lines * 40 + v) * c + 2]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Colors + + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\tLayerElementColor: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + //ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + //ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByPolygonVertex\""); + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tColors: *{0} {{\n\t\t\ta: ", m_Mesh.m_Colors.Length); + //ob.Append(string.Join(",", m_Mesh.m_Colors)); + + int cLines = m_Mesh.m_Colors.Length / 120; + int remCols = m_Mesh.m_Colors.Length % 120; + + for (int l = 0; l < cLines; l++) + { + for (int i = 0; i < 120; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_Colors[l * 120 + i]); + } + ob.Append("\n"); + } + + if (remCols > 0) + { + for (int i = 0; i < remCols; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_Colors[cLines * 120 + i]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}"); + ob.AppendFormat("\n\t\t\tColorIndex: *{0} {{\n\t\t\ta: ", m_Mesh.m_Indices.Count); + + for (int l = 0; l < iLines; l++) + { + for (int f = 0; f < 60; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[l * 180 + f * 3], m_Mesh.m_Indices[l * 180 + f * 3 + 2], m_Mesh.m_Indices[l * 180 + f * 3 + 1]); + } + ob.Append("\n"); + } + + if (remTris != 0) + { + for (int f = 0; f < remTris; f++) + { + ob.AppendFormat("{0},{1},{2},", m_Mesh.m_Indices[iLines * 180 + f * 3], m_Mesh.m_Indices[iLines * 180 + f * 3 + 2], m_Mesh.m_Indices[iLines * 180 + f * 3 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region UV + //does FBX support UVW coordinates? + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_1\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV1.Length); + + for (int l = 0; l < f2Lines; l++) + { + for (int v = 0; v < 60; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[l * 120 + v * 2], 1 - m_Mesh.m_UV1[l * 120 + v * 2 + 1]); + } + ob.Append("\n"); + } + + if (remf2Verts != 0) + { + for (int v = 0; v < remf2Verts; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV1[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV1[f2Lines * 120 + v * 2 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayerElementUV: 1 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"UVChannel_2\""); + ob.Append("\n\t\t\tMappingInformationType: \"ByVertice\""); + ob.Append("\n\t\t\tReferenceInformationType: \"Direct\""); + ob.AppendFormat("\n\t\t\tUV: *{0} {{\n\t\t\ta: ", m_Mesh.m_UV2.Length); + + for (int l = 0; l < f2Lines; l++) + { + for (int v = 0; v < 60; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[l * 120 + v * 2], 1 - m_Mesh.m_UV2[l * 120 + v * 2 + 1]); + } + ob.Append("\n"); + } + + if (remf2Verts != 0) + { + for (int v = 0; v < remf2Verts; v++) + { + ob.AppendFormat("{0},{1},", m_Mesh.m_UV2[f2Lines * 120 + v * 2], 1 - m_Mesh.m_UV2[f2Lines * 120 + v * 2 + 1]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + + ob.Append("\n\t\t\t}\n\t\t}"); + } + #endregion + + #region Material + ob.Append("\n\t\tLayerElementMaterial: 0 {"); + ob.Append("\n\t\t\tVersion: 101"); + ob.Append("\n\t\t\tName: \"\""); + ob.Append("\n\t\t\tMappingInformationType: \""); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("AllSame\""); } + else { ob.Append("ByPolygon\""); } + ob.Append("\n\t\t\tReferenceInformationType: \"IndexToDirect\""); + ob.AppendFormat("\n\t\t\tMaterials: *{0} {{", m_Mesh.m_materialIDs.Count); + ob.Append("\n\t\t\t\t"); + if (m_Mesh.m_SubMeshes.Count == 1) { ob.Append("0"); } + else + { + int idLines = m_Mesh.m_materialIDs.Count / 500; + int remIds = m_Mesh.m_materialIDs.Count % 500; + + for (int l = 0; l < idLines; l++) + { + for (int i = 0; i < 500; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_materialIDs[l * 500 + i]); + } + ob.Append("\n"); + } + + if (remIds != 0) + { + for (int i = 0; i < remIds; i++) + { + ob.AppendFormat("{0},", m_Mesh.m_materialIDs[idLines * 500 + i]); + } + } + else { ob.Length--; }//remove last newline + ob.Length--;//remove last comma + } + ob.Append("\n\t\t\t}\n\t\t}"); + #endregion + + #region Layers + ob.Append("\n\t\tLayer: 0 {"); + ob.Append("\n\t\t\tVersion: 100"); + if ((bool)Properties.Settings.Default["exportNormals"] && m_Mesh.m_Normals != null && m_Mesh.m_Normals.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementNormal\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementMaterial\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + // + /*ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementTexture\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementBumpTextures\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}");*/ + if ((bool)Properties.Settings.Default["exportColors"] && m_Mesh.m_Colors != null && m_Mesh.m_Colors.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementColor\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV1 != null && m_Mesh.m_UV1.Length > 0) + { + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 0"); + ob.Append("\n\t\t\t}"); + } + ob.Append("\n\t\t}"); //Layer 0 end + + if ((bool)Properties.Settings.Default["exportUVs"] && m_Mesh.m_UV2 != null && m_Mesh.m_UV2.Length > 0) + { + ob.Append("\n\t\tLayer: 1 {"); + ob.Append("\n\t\t\tVersion: 100"); + ob.Append("\n\t\t\tLayerElement: {"); + ob.Append("\n\t\t\t\tType: \"LayerElementUV\""); + ob.Append("\n\t\t\t\tTypedIndex: 1"); + ob.Append("\n\t\t\t}"); + ob.Append("\n\t\t}"); //Layer 1 end + } + #endregion + + ob.Append("\n\t}"); //Geometry end + + //write data 8MB at a time + if (ob.Length > (8 * 0x100000)) + { + FBXwriter.Write(ob); + ob.Length = 0; + } + } + } + #endregion + + #region write Materials, collect Texture objects + StatusStripUpdate("Writing Materials"); + foreach (var MaterialPD in MaterialList) + { + Material m_Material = new Material(MaterialPD); + + ob.AppendFormat("\n\tMaterial: {0}, \"Material::{1}\", \"\" {{", MaterialPD.uniqueID, m_Material.m_Name); + ob.Append("\n\t\tVersion: 102"); + ob.Append("\n\t\tShadingModel: \"phong\""); + ob.Append("\n\t\tMultiLayer: 0"); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"ShadingModel\", \"KString\", \"\", \"\", \"phong\""); + + #region write material colors + foreach (var m_Color in m_Material.m_Colors) + { + switch (m_Color.first) + { + case "_Color": + case "gSurfaceColor": + ob.AppendFormat("\n\t\t\tP: \"DiffuseColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_SpecColor": + ob.AppendFormat("\n\t\t\tP: \"SpecularColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + case "_ReflectColor": + ob.AppendFormat("\n\t\t\tP: \"AmbientColor\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2]); + break; + default: + ob.AppendFormat("\n;\t\t\tP: \"{3}\", \"Color\", \"\", \"A\",{0},{1},{2}", m_Color.second[0], m_Color.second[1], m_Color.second[2], m_Color.first);//commented out + break; + } + } + #endregion + + #region write material parameters + foreach (var m_Float in m_Material.m_Floats) + { + switch (m_Float.first) + { + case "_Shininess": + ob.AppendFormat("\n\t\t\tP: \"ShininessExponent\", \"Number\", \"\", \"A\",{0}", m_Float.second); + break; + default: + ob.AppendFormat("\n;\t\t\tP: \"{0}\", \"Number\", \"\", \"A\",{1}", m_Float.first, m_Float.second); + break; + } + } + #endregion + + //ob.Append("\n\t\t\tP: \"SpecularFactor\", \"Number\", \"\", \"A\",0"); + ob.Append("\n\t\t}"); + ob.Append("\n\t}"); + + #region write texture connections + foreach (var m_TexEnv in m_Material.m_TexEnvs) + { + AssetPreloadData TexturePD; + if (assetsfileList.TryGetPD(m_TexEnv.m_Texture, out TexturePD)) + { + + } + else if (jsonMats != null) + { + Dictionary matProp; + if (jsonMats.TryGetValue(m_Material.m_Name, out matProp)) + { + string texName; + if (matProp.TryGetValue(m_TexEnv.name, out texName)) + { + foreach (var asset in exportableAssets) + { + if (asset.Type2 == 28 && asset.Text == texName) + { + TexturePD = asset; + break; + } + } + } + } + } + + if (TexturePD != null) + { + TextureList.Add(TexturePD); + + cb.AppendFormat("\n\tC: \"OP\",{0},{1}, \"", TexturePD.uniqueID, MaterialPD.uniqueID); + switch (m_TexEnv.name) + { + case "_MainTex": + case "gDiffuseSampler": + cb.Append("DiffuseColor\""); + break; + case "_SpecularMap": + case "gSpecularSampler": + cb.Append("SpecularColor\""); + break; + case "_NormalMap": + case "_BumpMap": + case "gNormalSampler": + cb.Append("NormalMap\""); + break; + default: + cb.AppendFormat("{0}\"", m_TexEnv.name); + break; + } + } + } + #endregion + } + #endregion + + #region write & extract Textures + Directory.CreateDirectory(Path.GetDirectoryName(FBXfile) + "\\Texture2D"); + + foreach (var TexturePD in TextureList) + { + Texture2D m_Texture2D = new Texture2D(TexturePD, true); + + #region extract texture + string texPath = Path.GetDirectoryName(FBXfile) + "\\Texture2D\\" + TexturePD.Text; +//TODO check texture type and set path accordingly; eg. CubeMap, Texture3D + if (uniqueNames.Checked) { texPath += " #" + TexturePD.uniqueID; } + if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } + else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } + else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } + + if (File.Exists(texPath)) + { + StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); + + switch (m_Texture2D.m_TextureFormat) + { + case 1: //Alpha8 + case 2: //A4R4G4B4 + case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure + case 4: //G8R8A8B8 //confirmed on X360, iOS + case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS + case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS + case 10: //DXT1 + case 12: //DXT5 + case 13: //R4G4B4A4, iOS (only?) + WriteDDS(texPath, m_Texture2D); + break; + case 30: //PVRTC_RGB2 + case 31: //PVRTC_RGBA2 + case 32: //PVRTC_RGB4 + case 33: //PVRTC_RGBA4 + case 34: //ETC_RGB4 + WritePVR(texPath, m_Texture2D); + break; + default: + { + using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) + { + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + break; + } + } + } + #endregion + + ob.AppendFormat("\n\tTexture: {0}, \"Texture::{1}\", \"\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.Append("\n\t\tType: \"TextureVideoClip\""); + ob.Append("\n\t\tVersion: 202"); + ob.AppendFormat("\n\t\tTextureName: \"Texture::{0}\"", TexturePD.Text); + ob.Append("\n\t\tProperties70: {"); + ob.Append("\n\t\t\tP: \"UVSet\", \"KString\", \"\", \"\", \"UVChannel_0\""); + ob.Append("\n\t\t\tP: \"UseMaterial\", \"bool\", \"\", \"\",1"); + ob.Append("\n\t\t}"); + ob.AppendFormat("\n\t\tMedia: \"Video::{0}\"", TexturePD.Text); + ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); + ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); + ob.Append("\n\t}"); + + //Video ID is prefixed by 1 + ob.AppendFormat("\n\tVideo: 1{0}, \"Video::{1}\", \"Clip\" {{", TexturePD.uniqueID, TexturePD.Text); + ob.Append("\n\t\tType: \"Clip\""); + ob.Append("\n\t\tProperties70: {"); + ob.AppendFormat("\n\t\t\tP: \"Path\", \"KString\", \"XRefUrl\", \"\", \"{0}\"", texPath); + ob.Append("\n\t\t}"); + ob.AppendFormat("\n\t\tFileName: \"{0}\"", texPath); + ob.AppendFormat("\n\t\tRelativeFilename: \"Texture2D\\{0}\"", Path.GetFileName(texPath)); + ob.Append("\n\t}"); + + //connect video to texture + cb.AppendFormat("\n\tC: \"OO\",1{0},{1}", TexturePD.uniqueID, TexturePD.uniqueID); + } + #endregion + + FBXwriter.Write(ob); + ob.Clear(); + + cb.Append("\n}");//Connections end + FBXwriter.Write(cb); + cb.Clear(); + + StatusStripUpdate("Finished exporting " + Path.GetFileName(FBXfile)); + } + } + + private static float[] QuatToEuler(float[] q) + { + double eax = 0; + double eay = 0; + double eaz = 0; + + float qx = q[0]; + float qy = q[1]; + float qz = q[2]; + float qw = q[3]; + + double[,] M = new double[4, 4]; + + double Nq = qx * qx + qy * qy + qz * qz + qw * qw; + double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0; + double xs = qx * s, ys = qy * s, zs = qz * s; + double wx = qw * xs, wy = qw * ys, wz = qw * zs; + double xx = qx * xs, xy = qx * ys, xz = qx * zs; + double yy = qy * ys, yz = qy * zs, zz = qz * zs; + + M[0, 0] = 1.0 - (yy + zz); M[0, 1] = xy - wz; M[0, 2] = xz + wy; + M[1, 0] = xy + wz; M[1, 1] = 1.0 - (xx + zz); M[1, 2] = yz - wx; + M[2, 0] = xz - wy; M[2, 1] = yz + wx; M[2, 2] = 1.0 - (xx + yy); + M[3, 0] = M[3, 1] = M[3, 2] = M[0, 3] = M[1, 3] = M[2, 3] = 0.0; M[3, 3] = 1.0; + + double test = Math.Sqrt(M[0, 0] * M[0, 0] + M[1, 0] * M[1, 0]); + if (test > 16 * 1.19209290E-07F)//FLT_EPSILON + { + eax = Math.Atan2(M[2, 1], M[2, 2]); + eay = Math.Atan2(-M[2, 0], test); + eaz = Math.Atan2(M[1, 0], M[0, 0]); + } + else + { + eax = Math.Atan2(-M[1, 2], M[1, 1]); + eay = Math.Atan2(-M[2, 0], test); + eaz = 0; + } + + return new float[3] { (float)(eax * 180 / Math.PI), (float)(eay * 180 / Math.PI), (float)(eaz * 180 / Math.PI) }; + } + + private static byte[] RandomColorGenerator(string name) + { + int nameHash = name.GetHashCode(); + Random r = new Random(nameHash); + //Random r = new Random(DateTime.Now.Millisecond); + + byte red = (byte)r.Next(0, 255); + byte green = (byte)r.Next(0, 255); + byte blue = (byte)r.Next(0, 255); + + return new byte[3] { red, green, blue }; + } + + + private void ExportAssets_Click(object sender, EventArgs e) + { + if (exportableAssets.Count > 0) + { + if (saveFolderDialog1.ShowDialog() == DialogResult.OK) + { + var savePath = saveFolderDialog1.FileName; + if (Path.GetFileName(savePath) == "Select folder or write folder name to create") + { savePath = Path.GetDirectoryName(saveFolderDialog1.FileName); } + //Directory.CreateDirectory(saveFolderDialog1.FileName);//this will be created later, when grouping is determined + + switch (((ToolStripItem)sender).Name) + { + case "exportAllAssetsMenuItem": + ExportAll(savePath, assetGroupOptions.SelectedIndex); + break; + case "exportFilteredAssetsMenuItem": + ExportFiltered(visibleAssets, savePath, assetGroupOptions.SelectedIndex); + break; + case "exportSelectedAssetsMenuItem": + List selectedAssetList = new List(); + var selIndices = assetListView.SelectedIndices; + foreach (int index in selIndices) { selectedAssetList.Add((AssetPreloadData)assetListView.Items[index]); } + ExportFiltered(selectedAssetList, savePath, assetGroupOptions.SelectedIndex); + break; + } + + if (openAfterExport.Checked) { System.Diagnostics.Process.Start(savePath); } + } + + } + else + { + StatusStripUpdate("No exportable assets loaded"); + } + } + + private void ExportAll(string selectedPath, int groupFiles) + { + int exportedCount = 0; + + foreach (var assetsFile in assetsfileList) + { + if (assetsFile.exportableAssets.Count > 0) + { + string exportpath = selectedPath; + if (groupFiles == 1) { exportpath += "\\" + Path.GetFileNameWithoutExtension(assetsFile.filePath) + "_export"; } + Directory.CreateDirectory(exportpath); + + foreach (var asset in assetsFile.exportableAssets) + { + if (groupFiles == 0) + { + switch (asset.Type2) + { + case 28: + exportpath = selectedPath + "\\Texture2D"; + break; + case 83: + exportpath = selectedPath + "\\AudioClip"; + break; + case 48: + exportpath = selectedPath + "\\Shader"; + break; + case 49: + exportpath = selectedPath + "\\TextAsset"; + break; + case 128: + exportpath = selectedPath + "\\Font"; + break; + } + Directory.CreateDirectory(exportpath); + } + exportedCount += ExportAsset(asset, exportpath); + } + } + } + string statusText = "Finished exporting " + exportedCount.ToString() + " assets."; + if ((exportableAssets.Count - exportedCount) > 0) { statusText += " " + (exportableAssets.Count - exportedCount).ToString() + " assets skipped (not extractable or files already exist)"; } + StatusStripUpdate(statusText); + } + + private void ExportFiltered(List filteredAssetList, string selectedPath, int groupFiles) + { + if (filteredAssetList.Count > 0) + { + int exportedCount = 0; + + foreach (var asset in filteredAssetList) + { + string exportpath = selectedPath; + if (groupFiles == 1) { exportpath += "\\" + Path.GetFileNameWithoutExtension(asset.sourceFile.filePath) + "_export"; } + else if (groupFiles == 0) + { + switch (asset.Type2) + { + case 28: + exportpath = selectedPath + "\\Texture2D"; + break; + case 83: + exportpath = selectedPath + "\\AudioClip"; + break; + case 48: + exportpath = selectedPath + "\\Shader"; + break; + case 49: + exportpath = selectedPath + "\\TextAsset"; + break; + case 128: + exportpath = selectedPath + "\\Font"; + break; + } + } + + Directory.CreateDirectory(exportpath); + exportedCount += ExportAsset(asset, exportpath); + } + + string statusText = "Finished exporting " + exportedCount.ToString() + " assets."; + if ((filteredAssetList.Count - exportedCount) > 0) { statusText += " " + (filteredAssetList.Count - exportedCount).ToString() + " assets skipped (not extractable or files already exist)"; } + StatusStripUpdate(statusText); + } + else + { + StatusStripUpdate("No exportable assets selected or filtered"); + } + } + + private int ExportAsset(AssetPreloadData asset, string exportPath) + { + int exportCount = 0; + + switch (asset.Type2) + { + #region Texture2D + case 28: //Texture2D + { + Texture2D m_Texture2D = new Texture2D(asset, true); + + string texPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { texPath += " #" + asset.uniqueID; } + if (m_Texture2D.m_TextureFormat < 30) { texPath += ".dds"; } + else if (m_Texture2D.m_TextureFormat < 35) { texPath += ".pvr"; } + else { texPath += "_" + m_Texture2D.m_Width.ToString() + "x" + m_Texture2D.m_Height.ToString() + "." + m_Texture2D.m_TextureFormat.ToString() + ".tex"; } + + if (File.Exists(texPath)) + { + StatusStripUpdate("Texture file " + Path.GetFileName(texPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Texture2D: " + Path.GetFileName(texPath)); + exportCount += 1; + + switch (m_Texture2D.m_TextureFormat) + { + case 1: //Alpha8 + case 2: //A4R4G4B4 + case 3: //B8G8R8 //confirmed on X360, iOS //PS3 unsure + case 4: //G8R8A8B8 //confirmed on X360, iOS + case 5: //B8G8R8A8 //confirmed on X360, PS3, Web, iOS + case 7: //R5G6B5 //confirmed switched on X360; confirmed on iOS + case 10: //DXT1 + case 12: //DXT5 + case 13: //R4G4B4A4, iOS (only?) + WriteDDS(texPath, m_Texture2D); + break; + case 30: //PVRTC_RGB2 + case 31: //PVRTC_RGBA2 + case 32: //PVRTC_RGB4 + case 33: //PVRTC_RGBA4 + case 34: //ETC_RGB4 + WritePVR(texPath, m_Texture2D); + break; + default: + { + using (BinaryWriter writer = new BinaryWriter(File.Open(texPath, FileMode.Create))) + { + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + break; + } + } + } + break; + } + #endregion + #region AudioClip + case 83: //AudioClip + { + AudioClip m_AudioClip = new AudioClip(asset, true); + + string audPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { audPath += " #" + asset.uniqueID; } + audPath += m_AudioClip.extension; + + if (File.Exists(audPath)) + { + StatusStripUpdate("Audio file " + Path.GetFileName(audPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting AudioClip: " + Path.GetFileName(audPath)); + exportCount += 1; + + using (BinaryWriter writer = new BinaryWriter(File.Open(audPath, FileMode.Create))) + { + writer.Write(m_AudioClip.m_AudioData); + writer.Close(); + } + + } + break; + } + #endregion + #region Shader & TextAsset + case 48: //Shader + case 49: //TextAsset + { + TextAsset m_TextAsset = new TextAsset(asset, true); + + string textAssetPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { textAssetPath += " #" + asset.uniqueID; } + textAssetPath += m_TextAsset.extension; + + if (File.Exists(textAssetPath)) + { + StatusStripUpdate("TextAsset file " + Path.GetFileName(textAssetPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting TextAsset: " + Path.GetFileName(textAssetPath)); + exportCount += 1; + + using (BinaryWriter writer = new BinaryWriter(File.Open(textAssetPath, FileMode.Create))) + { + writer.Write(m_TextAsset.m_Script); + writer.Close(); + } + } + break; + } + #endregion + #region Font + case 128: //Font + { + unityFont m_Font = new unityFont(asset); + + string fontPath = exportPath + "\\" + asset.Text; + if (uniqueNames.Checked) { fontPath += " #" + asset.uniqueID; } + fontPath += m_Font.extension; + + if (File.Exists(fontPath)) + { + StatusStripUpdate("Font file " + Path.GetFileName(fontPath) + " already exists"); + } + else + { + StatusStripUpdate("Exporting Font: " + Path.GetFileName(fontPath)); + + using (BinaryWriter writer = new BinaryWriter(File.Open(fontPath, FileMode.Create))) + { + writer.Write(m_Font.m_FontData); + writer.Close(); + } + + exportCount += 1; + } + break; + } + #endregion + /*default: + { + string assetPath = exportPath + "\\" + asset.Name + "." + asset.TypeString; + byte[] assetData = new byte[asset.Size]; + Stream.Read(assetData, 0, asset.Size); + using (BinaryWriter writer = new BinaryWriter(File.Open(assetPath, FileMode.Create))) + { + writer.Write(assetData); + writer.Close(); + } + exportCount += 1; + break; + }*/ + } + return exportCount; + } + + private void WriteDDS(string DDSfile, Texture2D m_Texture2D) + { + using (BinaryWriter writer = new BinaryWriter(File.Open(DDSfile, FileMode.Create))) + { + writer.Write(0x20534444); + writer.Write(0x7C); + writer.Write(m_Texture2D.dwFlags); + writer.Write(m_Texture2D.m_Height); + writer.Write(m_Texture2D.m_Width); + writer.Write(m_Texture2D.dwPitchOrLinearSize); //should be main tex size without mips); + writer.Write((int)0); //dwDepth not implemented + writer.Write(m_Texture2D.dwMipMapCount); + writer.Write(new byte[44]); //dwReserved1[11] + writer.Write(m_Texture2D.dwSize); + writer.Write(m_Texture2D.dwFlags2); + writer.Write(m_Texture2D.dwFourCC); + writer.Write(m_Texture2D.dwRGBBitCount); + writer.Write(m_Texture2D.dwRBitMask); + writer.Write(m_Texture2D.dwGBitMask); + writer.Write(m_Texture2D.dwBBitMask); + writer.Write(m_Texture2D.dwABitMask); + writer.Write(m_Texture2D.dwCaps); + writer.Write(m_Texture2D.dwCaps2); + writer.Write(new byte[12]); //dwCaps3&4 & dwReserved2 + + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + } + + private void WritePVR(string PVRfile, Texture2D m_Texture2D) + { + using (BinaryWriter writer = new BinaryWriter(File.Open(PVRfile, FileMode.Create))) + { + writer.Write(m_Texture2D.pvrVersion); + writer.Write(m_Texture2D.pvrFlags); + writer.Write(m_Texture2D.pvrPixelFormat); + writer.Write(m_Texture2D.pvrColourSpace); + writer.Write(m_Texture2D.pvrChannelType); + writer.Write(m_Texture2D.m_Height); + writer.Write(m_Texture2D.m_Width); + writer.Write(m_Texture2D.pvrDepth); + writer.Write(m_Texture2D.pvrNumSurfaces); + writer.Write(m_Texture2D.pvrNumFaces); + writer.Write(m_Texture2D.dwMipMapCount); + writer.Write(m_Texture2D.pvrMetaDataSize); + + writer.Write(m_Texture2D.image_data); + writer.Close(); + } + } + + + public UnityStudioForm() + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); + InitializeComponent(); + uniqueNames.Checked = (bool)Properties.Settings.Default["uniqueNames"]; + displayInfo.Checked = (bool)Properties.Settings.Default["displayInfo"]; + enablePreview.Checked = (bool)Properties.Settings.Default["enablePreview"]; + openAfterExport.Checked = (bool)Properties.Settings.Default["openAfterExport"]; + assetGroupOptions.SelectedIndex = (int)Properties.Settings.Default["assetGroupOption"]; + resizeNameColumn(); + } + + private void resetForm() + { + /*Properties.Settings.Default["uniqueNames"] = uniqueNamesMenuItem.Checked; + Properties.Settings.Default["enablePreview"] = enablePreviewMenuItem.Checked; + Properties.Settings.Default["displayInfo"] = displayAssetInfoMenuItem.Checked; + Properties.Settings.Default.Save();*/ + + base.Text = "Unity Studio"; + + unityFiles.Clear(); + assetsfileList.Clear(); + exportableAssets.Clear(); + visibleAssets.Clear(); + + sceneTreeView.Nodes.Clear(); + + assetListView.VirtualListSize = 0; + assetListView.Items.Clear(); + assetListView.Groups.Clear(); + + previewPanel.BackgroundImage = global::Unity_Studio.Properties.Resources.preview; + previewPanel.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center; + assetInfoLabel.Visible = false; + assetInfoLabel.Text = null; + textPreviewBox.Visible = false; + fontPreviewBox.Visible = false; + lastSelectedItem = null; + lastLoadedAsset = null; + + FMODinit(); + + } + + private void UnityStudioForm_FormClosing(object sender, FormClosingEventArgs e) + { + /*Properties.Settings.Default["uniqueNames"] = uniqueNamesMenuItem.Checked; + Properties.Settings.Default["enablePreview"] = enablePreviewMenuItem.Checked; + Properties.Settings.Default["displayInfo"] = displayAssetInfoMenuItem.Checked; + Properties.Settings.Default.Save(); + + foreach (var assetsFile in assetsfileList) { assetsFile.a_Stream.Dispose(); } //is this needed?*/ + } + + public void StatusStripUpdate(string statusText) + { + toolStripStatusLabel1.Text = statusText; + statusStrip1.Update(); + } + } +} diff --git a/Unity Studio/UnityStudioForm.resx b/Unity Studio/UnityStudioForm.resx new file mode 100644 index 0000000..61f6224 --- /dev/null +++ b/Unity Studio/UnityStudioForm.resx @@ -0,0 +1,838 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 325, 17 + + + Two or more assets may have the same name, and Unity Studio will never overwrite an existing file. +Check this option to add a unique numeric identifier at the end of each filename, and ensure that all assets are extracted. + + + + + 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 + B4miQIUoSo42AAAAAElFTkSuQmCC + + + + 440, 17 + + + abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWYZ +1234567890.:,;'\"(!?)+-*/= + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + +The quick brown fox jumps over the lazy dog. 1234567890 + + + 556, 17 + + + 636, 17 + + + 169, 17 + + + 776, 17 + + + 17, 17 + + + 912, 17 + + + 67 + + + + AAABAAEAAAAAAAEAIACdcgAAFgAAAIlQTkcNChoKAAAADUlIRFIAAAEAAAABAAgGAAAAXHKoZgAAAAlw + SFlzAAALEwAACxMBAJqcGAAAIABJREFUeJzsvXeUHNWdL/6pqs5hunuCZhRHM5KIlggSshAoWIDfA4wx + 2IuDwMaPJOCZZwz4Gev81stZbPO89pp14L0j7y4GhNYoIgECmyREBoExFpqoMEoTO+dU9fuj59bcun2r + umc0Mxpp+nNOn+6uulV1q+p+8/d+r6AoCiqooILJCfFkd6CCCio4eagwgAoqmMSoMIAKKpjEMJ3sDlRQ + wemIdevWmWVZ/tKiRYvSixYt2nmy+6MHoeIErKCC0cH69eunWq3WJU6nc1ldXd2yurq6RT6fL+zxeLwn + u296qDCACioYIdatW+cRRXFxQ0PDcq/Xu6yurm6xx+Ox2+12ZLNZCIIARVFgtVrPcrvdbSe7vzxUTIAK + KigTmzZtkoLB4CKfz7fc6/WuWLRo0RKv11vjcrkgCAJSqRRisRhCoRCy2Sw8Hg/sdjvy+fwXAUxIBlDR + ACqowACPPvro2R6PZ1l1dfWKmpqapT6fb7bb7YbJZEIul0M6nUY2m4Usy5BlGYqiQBRFyLIMl8uFqqoq + iKK4o6am5tqTfS88VBhABRVQ+P3vf99osVgurqqqWu7z+S6trq6eX1VVBavVClmWkclkkM1mkc/nAQCK + okAQBM2HbLdYLPB6vZAkKVxbW1sDIH8Sb42LCgOoYFLjV7/6Va3NZlvidruXV1VVLfd6vYuqqqokp9MJ + QRCQy+WQy+VU6U7ohRC7KA5F0mkGQP77fD5YLBZYrdZL3G73O+N+gyVQ8QFUMKnw29/+1prL5RY7HI4V + VVVVK8466+zFVVXuKpfLBZPJBEVRkMvlEI/HVWLnSXla0rP/CVPI5/PIZrOwWCzI5/OXA5hwDKCiAVRw + 2uOXv/zlAkmSlrtcrhVVVVVL3W73tKqqKtjtdgBQJTshZho0cetJe/Y3+c7n87Db7cQMeLu6uvrSMb/Z + YaLCACo47fDQQw/NtVgslzidzuUej+dSp9N5hsvlgsPhgNlsLpLoNHjbSxE7/ZtmEgAgSRJ8Ph/MZnO+ + pqamBkB4LO55pKgwgApOeaxdu7bearUutdvtK5xO53KHw3GB2+2Gw+GAzWZTbXVJkiBJkhqfp+15oEC8 + RsStxwiM9smyjOrqalitVlit1mvdbveOMX4cw0LFB1DBKYeHHnrIkUqlljgcjhV2u33F9OnTP+9wOGxu + txt2ux0mkwkmkwmSJKnfiqJAlmXkcjmNA48WgKww5DEBtq2eJkG3y2azsFqtyGazqwBUGEAFFQwX999/ + /0KbzbbMZrOttNvtS2tqauocDgdcLpeG6C0Wi+rMI0Qvy3KRdCZaANlGg0fsek4/ug05lmUO2WyWbPvi + aD+XE0XFBKhgQuL73//+maIoXup0OleaTKZLbDZbk9PpBLHlB0NrsFgssFgsEARBDdUBWiKm7XKi5muJ + VIQgDBEvac9T8Y18ALzt5JrV1dUwm81wOByz7Hb7kdF8VieCigZQwYTAvffeOzWfz19is9lWms3m5S6X + a77L5YLL5YLT6YTdbofVaoXD4YDValXV+nw+j1wup0pmURShQIGA4lAd+V0sxRUQOUjMAj2VnoBlNHpa + AokG5PN5mM1mpNPpK+x2+3+O8uMbMSoMoIKTgh/84Af2bDZ7scViWQlghdlsXuJ0Oi0ulwtutxtOpxMO + h0N15FksFg3Bk8k2PKkrCgUJXg4hE9COQaNQIDmv3n7e9RRFQSaTgc1mA4BVACoMoILJh9tuu22h1Wpd + JgjCCpPJdInVaq2z2WzweDxwOp0q4dvtdthsNoiiiFwuh3w+j1QqBaB0Bh4hYrKfEDS9jYAldj27nt6n + 5wOg2/MShYgfQJblVSN7emODig+ggjHDHXfccRaASyVJWmEymS4FMJuo8R6PB263G7SaL0mSJvVWz+am + bXRi+7MMgccgWCbA8+DT51YUBZIkAUCRb4CreQzuZxkNaVddXU18F+c5nc5PR/ZURxcVDaCCUcNtt91W + D+ASk8n0BVmWVyiKMt9isaiSvaqqSv04nU5YLBY1NJfJZDQqOO2sY6U4/Z8G2U8fR/+nv3lSusBMFNUh + yLZnNQZeGjAvukD8ACQcmMvlvgigwgAqOLXx0EMPWbq7u5eIorhSEIQvSJK0RFEUm8ViUSV8VVUVvF4v + XC4XLBaLRq2Px+MA+Ik2bB4+2c8jQtZrr5fpp+cPoNuJIr89K/F5JgXdJ56GQJkBlwP4pc5jHVdUGEAF + w8Ltt99+viiKywCsBLBUUZQGSZLgdDpVovd4PPB4PLBarRBFUXXcJRIJANBk4/EcbCwTMHKyGRG4UTyf + /m/kwONJdPo3rWmwiUXsNUjdgMHnZwWQLrrgOKPiA6jAEHfddVdzPp9fZjabvwDgUkVR5kiSBLvdDpJu + 63a74fP5YLfbVbU+nU6rcXmenU22Exsb0M+nZ7fxNAb2vGwbIz8CbXbQ1+Bdh8csjI6l+0bSgm02G8xm + 8yqXy/W6waMfF1Q0gAo0uPfee73pdPoSSZJWmkymlVardZEoirBYLLDb7arTjqTdkiQcUh0nlUppiEyP + cAjR0Ko+PY2WdbjpZe3RIM7AUiE5PZ+AXthQvTYABcXEzx6rp4nIsoxsNkvKhF0OoMIAKjjpEB544IHF + uVxuhdls/oLNZltqt9urSKYdicM7HA41PEecWplMBrlcrijkBhRn3BGwBAdA1QR46bQ06HPyNAL2GvQ+ + PYedHniJPhAEiAYmh1EOATkfSVpCIS14rW4HxgkVE2AS4v777z9HkqTlJpNphclkukRRlJmSJKnEbrPZ + yOw1WK1Wtf4dHZ4DtGE42nNP7wOKHWZ66jgB0Qz0Qnss86D38RyARiYBu59tw96D3nF6pgb9Tc5RW1tL + JirVud3ugTJf25igogFMEqxdu/ZqWZavcjqdK6qrq8+1WCyw2WyQJAmiKMJqtcJut8NsNqt2eTabRSaT + QTpd8FXxCIBsJ//1UmJpZxlvO30+WZaLfAM0o2GlKrkWfQ4WeqHDslR/jk2vJ/2NTAxgqEqQ2WwmSUEb + uR0eJ1QYwCTAo48+umr27NnPEwI0mUwqoZPQHJ1mm8lkuEkvBEaxdvoYNpOON/2WJynZcwPQJPuQ32z4 + jyeNeTF5+j7Yvuj5G4wYRTkmCOmzohSmBw/iC6gwgArGGlar9dcNDQ1qNVuz2QwAqloPaNVqWvqWIx3Z + BB56P03EpcJpemo43Y5uoydl6X28a7H3wJogPKbH7qfvnZyD7QuPIQqCJhx4he5FxgmVxUFPc/z2t7/9 + H9XV1QtMpgKvJwMwk8moKjUhYJqQ2cFMiJuEs2i7n5yXJgJaXWc1AQAaCV5KfS9FkAS0OUGfl5xDT6Xn + mQV0O95zIcexfgKe+UNfQxRFZLNZ4gyck06n55S8sTFEhQGcxli3bp3D6XT+rKqqSlPLniZW8h+AhiD1 + VGdC2LwceVYTYAmQJSx2Hy3RWUKmP2Qbj8DovpaKKkDRDxXSv3nMQo/R8PpG9wmAamqJoohUKnVStYAK + AziNkc1mH6ytra0XBAGZTEZXjaaz2IhTkOf1BqCxw8nxdGSAJjpyPCs1yfEsUesRI09y6xEXTw2npa+m + H4Kx1sAjfiP/AGtS8DQL0pbyA1xWdNPjiAoDOE3x2GOPzayurv6h0+lEKpXSlUq8wcqz+wmhA1pC0rPR + WcKir0nOQ7dn25QKG9KmBruNd23WicfTRvT8DnSfjHwSRvfOMjFigqHgCCxt34wRKgzgNIXZbP55dXW1 + hdibJP/eyLkmCMVxdgKWKOnzEb8AMQ14djH5TzSM4msXt+f1F4CG6MkxetKZZjY8zYC123lgmRT9fOjz + G4G+Jpn2PFjUpCaRSCwq6yRjgAoDOA3x2GOPXVRdXb3aYrEgkUhwpTnvN2A8VRYo7UnP5/O6TjXSnucx + Z8GaDHrtWTNDlmW1D4IgwGazwWQycc0Utm96v/nPiu+c1GMi7HEkLVgQBDI9+KSgwgBOQ7jd7l/V1tYi + nU4jn8+rUhnQDlCaeFi1mvw3smfJN09C8j56kQZW3WfVZUIwPLVaURS15p4gCLBYLKiqqoLH40FVVRVc + LleRSk7ui+fjoO+Nvg77n3fP7DcvvEiDTA9WFOXyok6MEyp5AKcZHnvsseubmpqWCYKARCKhWQmHtb1Z + VZmWzrTEJDCapceq3+Q/yfFnowU8NZ1HeDRDoEOQhIDNZjMsFgtIxWCr1YpQKIxkMgG73Y5IJIJsNgsS + BiX94J2b9IE1C3iEbOS4pPvPe9bk/FQ+wFIALgAx3ZONESoM4DTCrl27TDU1Nf/H7XYjFAoVET4tnVgH + Gj3IeZl9BDQB0dKcdgyqPgHw7XoavOvQxKdH8A6HA2TZ7mw2i3A4jP3796Orqws9PT1YtWoVnE4n0um0 + huDJedlr86Q6uRe6r2zfedvpZ2VkShE/gM1msyQSiWUOh+NF7onGEBUGcBqho6Pjnjlz5swlM/UkSeJO + 3uFJa5YYyH42hGZErDR4k3P0JCJ9bkEQVBtekiSYzWZYrVZ1GrLNZkMul0M0GlWJvaenB/39/QiFwujs + 7MCVV16FpqYmHDp0CIqiqD4A+p5YhkWDR9h6RK5nQtD3q3cuMi/Abrcjm81eBqDCACoYGdatW1dbX1// + /zmdTvT19WkGIc8GB4rj4iwjIKAJlCQACYKgUe9pTYCcj7Rj/9O/CWGSCUAmkwl2u12tIehwOKAoCqLR + KI4dO4be3l709PSgr68fwWAA8XgCgAJJMiEYDKCxsRFXX30VQqEQUqmU2kc2dKkn8fWY43Ch5+BkmeDJ + XjWowgBOE9hstn+sq6vzJhIJZDIZ1fbnOfGIik7202m9vBRePUZCT9AxUo/p4/P5vOZ6hOCJSu90OgEA + sVgMfX19qoTv6+tDIBBAPB6HLCuQJOLAU5DJZJHJxNHb24sbbrgBtbW1+Oyzz4oIsBzJrncMy+B4x/MI + nj6WZTx0WrDJZJqfSCSmORyO4/w3PDaoMIDTAE899dTZU6dO/Z8mkwn9/f2ayTyEqAnIQGSdczxnGAFr + 99PnpLfRzIHOGKS1B1J3wOVyqV56URQRj8cRCATQ0tKC7u5u9Pb2IRDwIxaLFUUy8vkcUqns4JyGLGQ5 + j+PHj2PJkiVYtWoVDh8+jGw2C4vFUvYz5NnoNEqZT3rnMWoriqLqBzCbzcjlcpcBeKrsTo8CKgzgNIDF + Yvl5bW2t4Pf7IcuyxvPPEi8BvZ/dDhgPeHYiEH0scdqR5CNJkmCz2dSFPzweDyRJQiKRQCAQQGdn5yDB + 98Lv9yMSiVAET6YpF2oMZrPZwU8O2WxGzaYjMxq/+tWvAgDC4TDoyU/0/eoROJubQIMlZj3bnve/VDtF + UehVjlahwgAqGA6eeOKJy5qamq7N5XKIxWLqwAf0Y/e0zc46+gAUxdxZqUVAawF0HJ4s6UWqBJvNZqRS + KQQCAcpx14uBgQFEIhHkclmK4KEWFc1mc8jlshThZwfrFWSRyxVsZ7PZjCNHjuDGG2/ExRdfjH379hX5 + KnhRCD3bnuc7oZ8nex7eM2K38RgLfS4SDgQw7vkAFQZwisPr9f6f6upqHD9+XGPHA8VSnvYHsGE/linw + 2pFtJNtOEASYzWa1ZiBJwLFYLMhkMggGg5RK34v+/gFEImG14IgoSlAUGbKsIJNJUtKdEPsQ0RNVmfwn + zCYcDqO+vh433ngjgsEgEomEJuzHFgo1Ak2kpex5vf/lnJf+pv0AZrN5RiwWO8flcu0r2dlRQoUBnMLY + sGHDzfPmzVuYSCSQSCRgMpm4qj9g7PjimQPkP1HpyXaTyaSq9GSVH5vNpsbiOzo60N3dPRiaG0A4HEI6 + nYEoChpGk0qldCU8S/TkN1lQhDgPBUFEb28v1qxZg7POOgsffvghgGI/Bu8ZsM+CF/0gx8qyrKYUJxKJ + Iu1C75wEeglQpC0JB1osFuTz+S8CqDCACoyxadMmV21t7T87HA50dXVppvQCfGdUOYOVtCN2NbHhaQnv + cDiQy+UQDodx6NAhHD9+fFDC9yMYDA7WEBQgSQWVHlCQTmc0Ep4mfB6haz955PO5QaZWCBWKoohjx45i + 4cKFWL16NQ4ePKjJ+DNS5dn7NpLg5HgSjtR7fka2Pxt25V07k8nA6XRCEITLADyq26FRRoUBnKLIZrP3 + NzQ0zCCprrTjD0CR15616en/9AQak8mkFgh1Op3w+XxwOp3I5/OIRCI4evQouru70d3drRJ8MpkEAE2R + EJbICfHTaj35zxI6kfTkQ0wacv58XkAmU/A7rFmzBl6vF52dnUWqvpFTj34GRk49RVFgt9tht9uRTqc1 + 5cvJc+Y5S9lzGLUhswMH73MFCnSZ47z2UUeFAZyCeOqpp2bNmTPnfrPZDL/fP6gOa0tXEfCkDu05JwVC + 6XX8HA4HgEIsnhA7HYunl/giyGazSCQSBmr9ELEXfhNCzw1WyCHEPkT09MxCWu02mwV0d/fgG9/4Or78 + 5S+jvb1ddfzR90oTnpEWwAvb0c/S5XKpbUwmk5plSa5BH8c7Jy/6wDIEogVZLBZ3NBpd4na73xrWoBgh + KgzgFITX6/2nmpoaZ39/P2RZVpfj0gvd0XY8yacnS3ITT70oiojFYujv70dPTw8Ti49DUWRIkgmETrLZ + HJLJpEa6s467Ygk/JOVZCU++6Q+5BzpBCQDS6QwaGuqxZs0apFIphMNhDYMwUst56rdeu3w+ryYn7dz5 + IhYsmA+fz4dgMKhpp8mDgKKZA8H2iYB1DBI/wGCq8xUAKgyggmJs3Lhxydy5c7+by+UQDAZVm5dW8wmx + E6Ihjjs6NEdi8QMDA2htbUNPz1AsPhqNQZaHkm8EAcjl8sNw3BHCJyq9luj1CJ5IXZpw2AiF1WpFT08P + HnjgASxduhR79uxR27KgbW8SEaDbsoyS3k40ilmzZmHPnj145pln0Ng4C7Nnz1YnWtF91NM0yokkEJAl + 0gVB+CKAnwxnXIwUFQZwAnj88ccvt1qt52QymQidFkuph8rgoFeEAhRJkpDJZJRBb7YiCIL6GwBkWZYF + QRCy2awMAIIgKIqiKLlcLp9KpRLnnXfe92pra3HgwAEAQ5l+ZMkpEpojy3pVVVWpsXiSfLN//37VcVec + fFNIr+Un35Qj4Y1VeiOCZ8EmHVmtVsRiMcyfPx+33HILjh8/jlQqpcl90JO27D7yrHiZj4RZ1NTUIJvN + YOfOFxEOh9HVdRif//zniyZZ0degwQsXGjkLqSjHYgBeACFu41FEhQGMEC+99NK911133b+m02lkMhkA + 2vnqZPDyttH76GIWhEiI1KPDXoqiIJ1Oo7a2FoFAAMFgEGazWd3vdDrhdDrgchWy7YaSb4Lo6upS7fiB + gQGEw4XkG1GUIIpDZkI6ndbE240l/JANzzrttISeRz6vvXc9gtcDPQ04FArh1ltvRXNzM9577z2NlkAT + 93By9lkNgKydMHPmTDz77Hb89a9/RXV1Ddrb25FMJmCz2YqSrkg/2ZwLPfBChaRasM1mE6PR6Eq32/3s + sB7UCFBhACPAiy+++P0rrrjiXxOJBLq7u4tWraGhF1sm37SdzlMN6YFkt9sRCAQQi8XUmXLEeUcn3+zb + 14Lu7uOD2XaFabLZrDb5phCLN06+0ZPw5ar0IyV49v7N5oIJMzAwgFWrVuGb3/wm2tvbySSaovPrqeCl + QnbknQDAtGnT0N3djeeff36Q+Zixf/9+HDvWjSlT6hCPx7nH6vkTWM2D1ycyjdtms0FRlMsAVBjARMPz + zz9/z9VXX/3rSCSC1tZWJJNJjUeYF1qiVV3WzqTbsMfR7QRhaOrojBkzMH36dGSzWQQCAbS3t1PJN/0I + hUJIp9MQBHEwFk+Sb9Kc0Jxx8g2RSkStN1LpR4PgaRD/hdlcmNRjs9mwZs0a2O12DAwMcDP89Dzu5Fny + iI/ens/n4XQ6MWVKHdat+3ccOHAAtbU1kGUZx48fR2dnJ+bNm4u+vj6NpOdpHzyGU8oMIO940A8w5qgw + gGFg+/bt91x77bX/FolE0NLSgnQ6DbvdrsmU4xE+/Z/ezpP+escTVX/27NmoqanBW2+9hc7OTtUcSKVS + EARBE5rLZNIlJLx+8g1PpefZ8LxafaMFSTKpqca9vb34zne+gyuvvBKfffaZ6qSjIx+lvP70c+VV+iHb + Gxsb8dln+/CXv/wFDodDLayaTCbR1taGq666Uo3dG12LDUPq9Y18k9mBgxOpzkilUrNtNtuh4T214aHC + AMrEjh07/te11177aDQaRUtLC62qcePOBLx9PKml1544hxRFQXNzM+rr67Ft2za8/PIrMJkkzZTXwiSZ + hKGE56n1Q047QvgF250l+rEmeBoF1b9wf+l0GjNmzMAdd9yBaDSCaDSqyX3gwUgz0IMsy/B6vbDZbHj2 + 2e0YGPDDbreqmY0mk4TOzg74/X44nU6EQiHutfT6YmSOkP4RjctsNiObzV5us9n+3fDkJ4gKAygDzz// + /D1f/vKXH43FYti3b5+G+A0HoAIo4FfCAYaW2SIftnQ1GRCyLGPWrFmYOnUqNm7chL/85c9wOBzI5/OI + RqNlheb0PPVEpS9lw48H0dMwmUwwmQrRjO7ubtx9991YuHAh9uzZo/HeE9DPkYae9CXHEJCKRE1NTXj7 + 7bfx1ltvw+l0IBqNIJfLQxAKfTp0qAtdXV0499xzEYlEdPuvZ4bomSM0stksST1eBaDCAE4mtm3bds91 + 1133b/F4HC0tLWqyBl1Qk1XpVUkvClDk4qo6KiMQBQgorpVHl8kixD99+nRs2rQJO3e+oHqhk8mkxnM/ + Gsk3J4vgaZDSYFarFeFwGAsXLsR3v/tdHDlyBOl0uijspweWIfC0Nfp9TJkyBYlEAs8+ux3ZbAaAgmQy + BVkuRGmsVisCgQA6OjqwePHiogpKvP6whG5E+OR4khYsiuKYLxtWYQAGePnllzXEz6r9eqo++aYlFRsd + AKASP+9chFAbGxsxc+ZMPPPMM9i5cyfIYh80A+BJ+tGKxY83iB/DZDJBkiQkk0ncfvvtmDFjBt5//31d + Dz8BseNpjaqU1JVlGVarFTNmzMDmzVvw6aefwuEoOBozmXQRs2hvb0cqlYLFYlHnQRjdT7lOQEDrBzCZ + TFPi8fh5TqfzbyUf3AhRYQA6eO211x6+4oor1pIprqzkB/jTQek4MMsMjNrT5yPz3efOnQuXy4Unn3wS + r776qpq9Fw6HuQyA2O+E6AmRE6KniX2iEDwLUgnYbndgYKAfN9zwdXz9619Ha2urGp9nHaW0+s8ztQh4 + 3nnCJJqbm9DZ2YmtW7fCbDarz5esq0iYisPhQGtrK44cOYKamhqkUqmie9AjcqPt9Lcsy+oEL1mWvwKg + wgDGEx999NHTq1at+tbAwAA6OjogCIXiEzyiYdU7veqzvEHJtgdAPMBoamqC0+nE448/jt27d8Nut6vE + H41GEY/HkUgkkcmkVYkxEdX54YAk/FitVqRSKcycORMPPvgjZDIZddITaQdopT0Ba4rpqeY0sdXW1sJu + d2D9+qdx7NgxOBx2xGIxJBKJQQfg0NoJLpcLhw8fwb59Lbj22mvUcKCeucGahWy/9ECtHnwtgIeG+SjL + RmVpMAYff/zx+oULF36rr68P+/fvhyRJsFqt6n5ehpfe4OJJfnYQ0MeSNeObmprgcrnw+OOP45133oHT + 6UIikUAkEkEsFkM8Hkc8nkAqVZBQqVQK6XQaJCsxm81qpP6pgoLjr2D7RyJh3HLLLTj33HPR0dFRtHgJ + oJ/Rx9vH+mmAAvGbzWY0NTVh16438O6776Gqyo1YLKY+U55jNZPJoK2tTT2evp56+jKdkbyxQ1cJAnBB + NBqtHc5zHA4qDIDCe++999SFF164uq+vD4cOHYIoihrJLwgCFGiJ12gA8iQVzxSgHX+NjY2oqqrCk08+ + iXfeeWfQ4RfVEH8iMUT8mUyhOCbRAE4lgqcx5PizIRQK4fOf/zy+/e1v49ChQ2qhDyPGSsAyCt67os/T + 0NCAcDiM7du3Q5YLE54SiSSSyWIGQPIprFYLOjo60N8/oJYxJ30h3RF1xgbrK2L309EfkvshCMIXRuUh + c1BhAIPYu3fv+iVLltzY39+Pw4cPQxCEohVlBEEAdNQ4ntpJw2g/GQyNjY3wer146qmnsHv3bthsNkSj + MZX4CQNgpdOpSvQE5FmbzWZ1os0dd9yBKVOmoKenx7Dohp4qzRIaywDy+TxsNhumTp2KF198CXv37oXN + Zh18vkmk0ymN5KfnQZjNZnR1deHgwUPw+bwlC66wxM8THnRb1heEMSwWWmEAAD788MP1n/vc51YPDAyg + q6tLtfkB/YSSUgNPz/5kVVGiqs+YMQM1NTXYsGEDXnvtdVithVBfJBKmiD+hqvyUinjKg0j/Qr5/P666 + 6ipcf/316OjoUOPzwJBWxXPmsc+Yt51sI46/xsZGdHV14YUXXoDVatE4/tjoSkEiF0Ks+XwewWAQ7e3t + sNsdmslIRpOQ9MDeBzkXqRasKMoVI3y0JTHpGcCHH364/qKLLlrd39+vEj/taS7HziQf+uUTAcBrz9bv + mz59Ourq6rBhwwa88sorg5Iopnr7h4hf6/U/HUAKfJrNFuRyeXi9Ptx5512QZRnBYFDXruep9TRj4GkM + NNMlk6i2b9+Oo0ePQhBEDfHTvhR2XkShjj/Q1taGRCKhERZ6Woqen4inDQpCIRRKzRRtikQi80bhcRdh + UjOAjz/+WCX+w4cPF9n8gL4KSdvtfFUORYyBlhLEXp82bRrq6urwX//1X/jLX/4Cq9WKeDzBtfnJwDxd + iB/QSn+/fwCrV38LK1euQHt7u7qffvZ674b8L8UUZFmGyWTCnDlz8NFHH+GVV16Fy+VEPB4tkv6FlOih + Dz1Zymq1orOzE8eOHYPH49Fcn8DIFNTzAdAgDGdQYIxJUtCkZQAff/zx+gsvvHD1wMAAjhw5okrTnkvs + AAAgAElEQVQiehCxjjsC8vLYwUV+G81So1W7qVOnYsqUKXjmmWfw0ksvwWq1Dnr7w5S3P66RSqcT8ZNn + XmB6cZxxxhm49dZb0dfXpxbg1HPgkd88M4ANw9K/FUVBbW0tFEXBtm3PIhaLIZfLIZFIFT1nNoGK1gZE + UcTx48fQ2bkfXq+XO7mIRTl+InY79b4rDGC08NFHH6nEX1D/BDWcQ2D0Emmbj3X4APwpveS4fD4PAGho + aMCUKVOwceNGvPjiS7BabZokH8IAksnTz+YnII4/i6Vgf9966604++yzVScsrTkBWo2KtpX1nGws8vk8 + LBYLZs2ahVdffQ3vv/8+nE7HYNiPlf7aRCpFUVQtgEQDEokkWltbVZWdzUGgv3lg27COQ0EYSgtGgQGM + Or1OOgbwwQcfrF+4cKGG+OkZdXo2v5HKxg48WgOgJRgxGerr61FfX4/Nmzdj586dsFotSCTiCIeLvf2Z + zJA9ejqBzvcPBAJYtuxS3HTTTTh48KAqYUs50HirFulpXkP+lmkIBoPYvn07BKEwxbfwSRVlVdKJVFot + IDtYwdeM9vZ2+P1+zboBvOSrchgDu4+pGOWLRCKLy3q4w8CkYgCffPLJU4sXL17t9/tx/PhxjdoP6BO7 + nilAjmEdgOx+2uavq6tDfX09tm7diueff17NJy/Y/NGiUB+Z7HM6QRCGwn7EIXrnnXfC4/Ggr6+vKOxH + P3/6HCzY90QTVD6fh8PhQG1tHZ577nm0tLTCYjGrWlY6ndI4/ljw/ABmsxkHDx5EV9dhjRnAmiPlaAF6 + +8g1B8fRqIcDJw0D2L1791Pnn3/+jYFAAMeOHVMHIVDaruQ5d/QyAtncfmCouGVNTQ2mTp2K7du3Y8eO + HSrxE8k/lOF3etr8BCTf32azo6+vH9de+xV8+ctfRkdHuxr2Y4meR9Q8Zx/5D2hrMIiiiObmJuzfvx8v + vLATDodNY2Kxqj8LWgsgTEBRFAwMDKC9vR0Oh4NrBrB+CD3wBAv5phjSqPsBJgUD+OCDD9YvX778Rr/f + j2PHjkEURU1smXzzGAH7Ykrlc/My/vL5PGpqajBt2jTs2PEctm17FiaTCalUiiP5T09vP8FQ2M+MbDaD + +vopuPPOQn3/aDSmqWjEc+yR7eRcRo4/whRyuRw8Hg/sdge2bXsWvb09UBRlMLqilf5Gz3xIC8irfgBZ + ltHW1qZmK7L95qFcByDZTkwSQRCWAnDqnngEOO0ZwJtvvrl+8eLFqwOBALq7u1XJzxtYrKRnk3bol8QL + AfI4vyzLqK6uxvTp07Fz505s3boVJpOEdDqtTuwZcvhpif9Uz/DjYUj62xAIBHDTTTfhkksuwf79+wGg + yPbnSX7yXU5+PcnXnzt3Lt5//wO8/vrrcLlcGulPE7/RMx/yAwyZATabVV0Q1e12A+A783i2P3svej4M + cl0AlkQisaLkQx4GTmsG8MEHH6xftmzZar/fj+7u7iKbXzPYOB5c+jdrW+pxeNrhR0pMTZ8+DS+99BI2 + bdoESRKRTmc4xJ+aFMRvMplgsVgQjUYxf/583HrrrTh+/DgymQz3merlYdAgJgCPUSuKgvr6emQyGWzZ + slV1rBZi/klV+hMpawTWDMhmCzM3jxw5jP3798Pn83FNkVJMqtT9kWsOjqtRzQo8bRnAe++9p0r+3t7e + IpufliCCIBQyd1Ao4VUu1yYf3pRURVHg8Xgwc+ZMvPzyK/jTn/4EURSRyWQQDoc4Nn/qtCZ+QRBU6U98 + H7fddhvmzJmDY8eOASh29umZZTxpySOyfD4Pq9WKadOm4c9//gs++mgPHA67qm2x0r8UtNGAocpL0WgM + ra1tRRme5bxHPU2UvWdqXIyqI/C0ZAAfffTR+iVLlqz2+/0a4jdSGdUP+INKL7mHBuH+ZE25mTNn4tVX + X8WGDRsgCAIymSxCoRCi0ZjG5icD8XQlfkC/vn9nZ6eanaen+utJfPo//U1vnzVrFgYGBvDss9thMpmQ + SCQ0jj96JmU54EUDTCYJbW2tiEajsNlsun03Gj88pkcLGMo5+blEIjGtrM6WgdOOAbz99ttPL1y4cLXf + 70dfX5+G+PWgN3OrlJrPticSwu12Y9asWXj99dfx1FProSiFxTSHJH9MI4XKsT9PZZB3QNf3v/POO+Fw + OBAIBAzDrOT4UloB+5/U9/d4PNi+fQf27++E2WwqmkpdjupPgzh16XkBVqsV+/cfGAwHeorak37p9Zne + zgMZW8QMyOVyoxYNOK0YwJ49e56+5JJLvuX3+9Hf36+qnbyMsVI2JaCdx28UzyXbZVmG0+lEY2Mjdu3a + hSeffHLwxRWIv2DzxzUOv9NlSq8RaMdfX18fvva1r+HKK69EZ2enxoQqx96nwSN+8r5FUcTcuXPQ3t6O + nTtfVDP+eKp/udIfGNIA6HAgAPT29qCjowMOh7PYvGT6zLsPQH8NQ/JNriUIwqiZAacNA3jjjTeeXrRo + 0bcCgQAGBgY0Nj+gffA8YuOplfSgJMfRL4b+LcsyHA4HGhtnYffu3fjjH5+ALBeIPxQKDWb4xRGPxzTe + /tOd+EmZL7OZ1PefiTvuuEM1gXjMFuA7XfX8LvR2Iimrq6thMpmxefMW+P1+yLJMhf3SI5L+BFpH4FCx + kNbWFijKUJUgvdmIevtKMTuSnVhhAAx6e3ufXrFihUby68Vk9Qgd0C8bzbZjNQhZVuBwODB79my89dbb + ePzxx9WJJKEQndsf03j7T3fiB+jZflYEg0F897s3Y9GiRTh06JChnU+jVCIN/d7IohqFd/EWdu/eDZfL + qZb5Yuf6j+T5s5ODSJWgtrZ29Pb2wUVVCaL7T8C7X71+0GOOaB8ApsVisc8Nu+McnPIM4NNPP91QX1// + rWAwqNqTdDIJYMxljWxLejtv8BFvtMNhx+zZs/HOO+/gP//zP1WHTcHmj6rSn006mQzET4p8hsNhXHjh + hfjud/8Hjh07psn313vWvNRa9j9h6LSqPHXqVKTTaWzZsg25XI4K+xXn+48ExeHAQlrw4cNdOHDgIDxe + b1njR2+86e2n/QCjpQWc0gzgo48+2rBgwYJvBgIB+P1+1QYk4HFZo0y+UsTOHifLMmw2GxobG/Huu+/h + 3//9P5DNFmzKgrefJn6t7Xm6Ez95F6TQZyaTxZo1azBz5gw1IYtn67PqvLYdPx2YfHK5HOx2O6ZMmYIX + XtiJTz75BHa7TZ1bMdywnx54acGFKkEhtLW1qanMpZ4P77fRfsIAAECW5VFxBJ6yDGDPnj3/tXDhwm8G + g0G1cgyb3muUkUW3o9vrMQj2v6IoKvF/8MEH+MMf1iGTSQNQBpN86Pn8k4v4Aa3jr79/AP/9v/83/MM/ + 3IDOzk4oytDCngSltDMAEEX++yMEKQgCZs+ejd7eXmzfvh1Wq0V1uLKJVsNx/PFAmwEkLVgURbS2tiKd + TsNqtRra+UP7iu+X9wwK968JB64EYC46YJg4JRlAW1vbM4sWLfoGUfuB4kUfyG8jlYrdpncM+yEryTQ1 + NeHjj/+KdevWqfXjieSPx2Ncr/NkIH7igyGl1dxuF+666y6YzSaEQiHDWXvkm2ce6F1LEAQ198LpdGLr + 1m04dKgLkiSqcf/hZPyVA7o+AJsWfOTIEbVKkFG/B38Z7CveRvwAgiC4YrHYJSd6H6ccA/j00083nnnm + mTewkt+IkGmuy9qMdFs96UJDlmVYLBY0NTXhk08+wf/7f/9XXR2GVfsnk7efBlH7bTY7+vv78Y1vfAOX + X345Ojs7i3w0w7WVedvy+bxa5uuzz/bhz3/+s+r4KyT9aGspnqj0B9h8gKyqARw/fhzt7R1wOLTFQqme + G9r7egyDvi7RdmRZPmE/wCnFAFpbWzctWLDgHwKBAEKhkCppaBjFX1lGwO5nQUsiQLuQxN69e/H73/9e + DWXRxE8n+ZCBN1mIn8y3KKT7JtDU1IQ77rgD4XAYqVTKsFwa/VuPQfO0A1JnQRAEbN68GeFwGPl8DolE + smh25WhIf3JNXjQglUqhpaUFANSxqZ1QVt75jcYwuQdBEE7YD3DKMIC///3vm84666yvBYNBRCIRVfIb + JegYhVaMHjDvfIT4m5ubsW/fPvzmN79BNBqFKIoIBkPqcl1kya50Onnap/fyQK/uEw6Hceutt+K88xag + q6uLm/Cjl4VJEzmvvgIBKfM1ffp07Nq1C2+99TYT9hsi/tF+FzwzwGq1oL29DcFgEHa7vei+ePfKbqPv + kX4GtAk6qAUsBuA9kXs4JRhAW1vbpvnz538tGAwiHA4D0F+ii3WalLIjjRxPPMnf2tqKf/u33yAcjkCS + TIOSP4J4PE6p/SlkMqOnbp4qoFf3CQaDuPjii3HzzTfjyJGjZLlrrt2vZ26x+3lQlEJl5UQigc2bt0BR + ZKRSKUr1H13bnwabFVgoE2bBwYMHceDAAU21YKP+D3dcUvkAYjQa/cKJ3MOEZwD79u3bdOaZZ2okv9H6 + fKVUex5D4M1BJ1AURZX87e3t+PWvH0UoFBp0aAVVyV8g/oTG4TeZiJ92/BHN7M4770RdXZ06J4Onxusl + ZZH/7G/6WJLvX11djR07nsPevXupsJ82338siqsUzwsoMHy/34+2tjaYTKay1zPkaTrkGjxQ+QAnND14 + QjOAlpaWzeecc87XgsECoQHQTfKhf/OkCo/LlppSSspTNTc3o7OzE//6r79GMBiA2WxS1f4hm3/yEj+g + re/f39+Ha665Btdff31R2I83VZanEbDvhX035N3Nnj0bx44dw44dz6nEf6L5/sOB1gzIIpPJQlGgLmfO + rjBllIdilDvAG5uDYesTcgROWAbQ3t6++eyzz/4qIX5i8wPGHlMjwjcaVEbEv3//Afzyl79CIOCH2WxB + MKjN8CPLSE9W4qcdf7lcDtXV1erqPvF4XDc5qxxpr/ee8vk8vF4vrFYrNm/egmPHCqv7DC2flh6VpJ9S + KF4zoBAObG/vwPHjx9UqQbz7ZMETSHpjnDID5qVSqaaR9n9CMoD29vbNZ5xxxlfJJJpyJToNvUFkpOrT + DheTyYTm5mYcOnQIv/zlv2BgoB8WiwWhUFBTw4+E+oi3f7IRP6BN+vH7/bjxxhuxcuVyHDp0SJMVR9R3 + vem/eoOd5xAzmUyYPXs2/va3v+Hll1+B2+1CLBalVP+hIp9j6YTlpQUXqgQdQUdHJ5xOp044sPQY5rWj + nwEJB+Zyuf820v5POAbw6aefbjnjjDM0kr+UnWj0YHleZqO2xFnV3NyMw4cP41/+5V/Q19cHq9WqUftj + sdigtz81qYmflv6xWAxnnnkmbr/9dgwM+DVlvoyIXc85SB/HOmWnTJkCANi4cRPi8Riy2WxRxp9eie/R + BC8tOJfLIR6Pq+FAozUOyhFOeiDMzeVyjbhO4IRiAIcOHdq6YMGC64PBoBpfL5VTrQeehGH3sf+Jrdrc + 3IwjR47gF7/4BXp6emC1WlVvf4X4h0A7/ggDuP3223HWWWeppdfptuyxeoycdhSyxxC7ur6+Hi+//DLe + e+/9wbX9hur7k7UUxlr6E7BpwZlMYXJQa2sr4vE4bDab2n/6W084laMVkeu63W50dnYOjLTvE4YBtLS0 + bJ09e/Z1oVAIiURCY/MDpT3EpTQBo20ANJK/u7sbv/jFL9Dd3Q2r1UYl+dDFPCY38QPatf38fj+WL1+O + m266CV1dXZr5/cPxvehJQ5poZsyYgWg0is2bt0AUh1b3oROvxkP6E2jDgVnkcoV8gP379+PQoUNqlSBt + QpBxeJMHlnF4vV4kk8ncfffd9/BI+z4hGEBLS8vWs88++zpW8uvFhXkweph6YT7yEmji7+npwSOPPIKj + R4/BZrMxGX4xtajEZHX4EdDSXxAK6b133303vF4vgsGgYQ7GcEw4uk0ul4PL5UJVVRWefXY7Wltb1YVF + y1ndZ6zA8wMAQF9fH1pb2yBJxfUOS5mmLNg2hSIrZjzxxBP3bd++vXekfT/pDKCtrW3b2WeffV0oFEIy + mTS0A1mUUivJNr1SU4T4BUFAU1MT+vv78cgjj+Dw4cOw222DNj+t9g8RfyaTmbTED9BhPzv6+vpw/fXX + 45prrsH+/fs1Glk5syv1GAX9nzDppqYmdHV14bnnnoPT6UA8ri30cbISsHhpwfl8oUoQAN2itEZjWI8x + KIqC6upq7N+//8CaNWt+cyL9PqkMoLOzc9uZZ575FVrtp+0+XiUV8m00YIykCn1OQvzNzc0IBoN45JFH + cPDgQdjtdsbmjw/mlVeIH9A6/rLZDBoa6nHXXXchk8kglUpxiVtvjgYN1uFHf/L5PHw+HyRJwqZNm9Hb + WxB6xbP9xlf6EwxpAPnBIiRZWK02tLW1o6+vD263e1iaj9FzcjgcAICNGzfefKL9PmkMoKWlZdvcuXO/ + EgwGDSU/i1IOFL3ccnobkfwA0NzcjHA4jJ///OdqUcdQKDS4ZFdcjfOnUslJr/YTsKv73HzzzVi6dKm6 + rDf74U3/Jdt55b1ZkNl+M2bMwJ49e/Dqq6+iqspNTbemZ/uNj+OPxZAZkFPzAcxmE7q6utDR0QGn01mS + +dHnorer+wY3u91uvPrqq88/+OCDb55ov08KAzhw4MC2s88++yvBYBDpdLpI8gPFxMsSvp6kZ8HjqrTk + j0aj+NnPfoa2tjY4na5B4icTe2JIJhMnzbaciBha3ceKSCQyuLrPbejt7UU+nzdcJZn+preXWg4MABoa + GpDP57Fx4yY174JX5kuWT877KfYDFKIQ4XAYra2t6n0ZTV4rqfqjsNhMNpvFE088ccto9HvcGUBbW9uz + zc3NXwmFQmqcmHfjrMe0FFdnpQt7Ppr4AaCpqQnxeBwPP/xTtLS0wOl0DZbujqjFPIjNT2r3T3biFwR6 + dR8zkskk1qxZgzlzmtUFWEg7HhHzCMBo2i9R/a1WK2pqavDSS3/Ghx9+OGj7F6f8jlfYTw/aRUMKacEm + k4SWllZ1/QBAPwWdt53eRiIuTzzxxD89+eSTfaPR53FlAAcOHNg+d+7ca0OhkFpBx4gbljs7jPcwjSR/ + U1MTUqkUHn74p/jss71wuQrEX1D7SQXfoRLSJ3tgTQQIwpDXv5Dv348rrrgC3/rWt3Dw4EEAxbMvWeg5 + Y1lmz7adMWMGgsEgtmzZAovFPGj3j16Rz9FC8eSgAtF3dnagq6sLHo+npBOQBXk+iqKgpqYGvb29vbfe + eutDo9XncWMABw8e3N7U1PTlaDSqqv1GNjoLnjThQc9xSNeMy2QyePjhh/H3v38Kt9tN2fwxdXYfSSXl + Dc7JBnpJb4vFAkUprO5z9913w+l0IhKJcLM1eWm/rJbA/qavmcvl4Ha74HA4sHXrNnR2dsJsNlOa2fhl + /JWD4kVDshAEAcePd6Otrb2oeE25TkBFUdTaAv/xH/8xKqo/wbgwgM7Ozu2zZ8/+cjgc1l0Flgc9NXK4 + xxC1v7GxEdlsFv/8zw/jk08+UYk/HI6o6/WlUkMSvxxH1un8YQnfYrHAbrejv78PN9xwA6666iocOHCg + iNCN3okeA2DfLQn7NTbOxv79+/HCCy8M5vvTdRZHt8zXaICXFpzJpLFv3z4AxbNZAT7hs4KsqqoKf/3r + X9/88Y9//MJo9tdUusmJobOzc0dzc/M1hPgB/ZskKFVAgYCoR3rnFISh8kmzZs1CLpfDP//zw/jooz1w + u90IBIKIRMJqIklB4svgXZ6owJMDCoAhJkCv6ptOZ9DY2Ii77rprUFPK6E524U3iofeR8/OQz+dRW1sL + AHjmmY0IBAKw221qOHYsynyNBmhnYCEtOAOr1Yq2tjaEQiFVY9JjfjwfCSks8oc//OHmxx57bFT7O6Yj + urOz87k5c+Z8KRwOI5vNGkpv3gMwygQsp3gCmdJbW1uL3t4+/OxnP8U777wDl8uF7u5uRCIRJBKJwfh1 + GplMekINpokESTLBarUgkUjg/vvvw8KFC/HZZ59pPPjsO+EVXy0FwrTNZjMaGhrw7rvvYdeuN+B2FyI0 + ZLbfia7uM1YoTgjKwel04uDBg9i/fz8WLlyo1rYAip3dNMjcFJvNhqeffvrRxx577MBo93fMGEBXV9eO + 5ubmL4XDYeRyOS6hslLBCOW2Je3IlFGHwwFJkuD3D+DSSy/F1VdfrXEaEbuN/pDjqbNCDcICUBRAEDCo + KZSnrZSzXW9fYZu2D8Xbtd/G1yD9J21YAh66N9r8AQoq7MqVK3H06NHBtkPvlUhznmef+GDI++ENdrJN + lmVMnz4dmUwGzzzzDPL5HFKpPLe+/0Rj2NpwYGFegCzLCAQCaG1txcKFCzXPoBRTrK6uxsDAQLSzs/OB + sejvmDCAjo6O5+bNm/elUCg07GIMRmq9IAgFEtAlEu15SNglFAqhqakJn/vcqCyndopD0Tw+LTEW72Mr + +CiKgp6eHrUqM2DszCIoNSeefOdyOTgcDng8Hmzb9uygr8YFv99fVN9/LAt9nAhYLYD4vfbtawEpMcf6 + wngM0Wq1QhRFrFu3bs1PfvKTMbnZUWcABw4ceG7OnDlfCoVCdPliQ9u9lETUtMegnOOck24PAKlUSh3E + qVRKXUSEtOP9LrWvVPvi/wqPXxXdl9G1SvlMgKEohx6MfCUE5ZhXtHqvJ/F5x/Ocfuy1yT3MnDkD/f39 + 2Lp1K2w2m+qjYW3/ieL4Y8GbHORwONDe3o6jR4+ioaEBfr+/5Hm8Xi9aWlo++fGPf7xhrPo6qlGAgwcP + Pj979uwvRaNRDfHT3wR6g4O3jwXrSdZrzxuIZHs59qjesfTv0mYJP2ORx/j02rHX5YG3MlJRTzheeJ4T + iu1fqedcysOv9/zZ7bIso6qqCmazBZs3b0FX19DqPvTCqhNR9adBGAAdCZAkCUePHkV7e7vu8uH08W63 + G7Is44knnvj2WPZ11BhAV1fXC42NjVdHIpETVs3KnTWlB94gpz96lVpLHScIAgRRex6jUtd6RGZ4fkFr + c/OOYfezHnVeX9ia/KXuG0DJfvCeIfvfiMnR/SZhvxkzZqC1tRUvvvgi3G6S75+asGE/HkhCEGEChfoE + OSQSCezbp60SxNOYRFGEw+HAzp07n3jkkUf+PpZ9HRUG0NHR8cLMmTOvikQiGmfPcIlYb7CVc/xwGATd + ppwBrmkH4/vSu3fe/fBAaxV6DIPspwmeHMe7J14f2HYs82DPoSiKhiGw98PL8uM9G943OZ6E/f70p2dQ + 0CJz1GSfobUWJrL0JyjOCszAarWgpaUFiURCndEHaJ+xoijw+XyIxWKZJ5988n+OdT9PmAEcPnz4haam + JpX4WZRDiEbQy+yj/+upUnqDlf1fbh+NGE651ygl/XkEanRvtHTXY0R61+adi0f4gNbDX+paeufTO4aE + /Wpra/HGG7vx1ltvUWv7FZf4nkhhPz1o5wUUwoEWS6FK0IEDB+ByuTTtybMxm80wmUzYsGHDDzZu3Bgb + 636eEAPo6Oh4Yfr06VfF4/GyVTIj1VHPMVWKQPX285IqeP/LGaR61y0iGKZPRuEedls5908TPK+dHsHr + Tbst5/6MmKXeMzJiBDw0NDQglUph48aNADC4us/ETvoxAusIzOUKaeUDA/3q7EC2vaIUCn20tLR03n77 + 7b8fj36OmAF0dXXtbGpquioWixmq/cPh1qUIjm1rdA5eGyMV1OjcPLtZr72AYpW83GONVigq57/RvdEq + PM2UjLQD+r+eZ9+oL0b3TEt/u90Ol8uFHTt2YO/evarnn8zEnOhhPz0MaQGFrEBSS4L4Acjy6eT5Op1O + AMDGjRu/M159HBEDOHTo0M7p06dfWY7kL4eYWfBCVuVIIb3rlsNYSu0rxSx4arBeOehy+sqzyfXOxWo1 + pe6vHI3K6PnpaQV670iPCZL3OmPGDHR3d2Pr1mfhcNgH6zCM3+o+Y4WhfIChxUNtNhva2trQ19cPl8ul + Ycgulwsvv/zyjp/85CfvjFcfh80Aurq6yiZ+PZQ7AMuJXY8UwyF4vQFe7n2Ukq68/hgR8nD6Rn+Xis8b + bdNbm4E+L9sno99AgUA8Hg8kScLGjZtw/PhxCIJQNNuvIP1PDdWfRrEZkIPJZMLhw4fR3t6mLhumKIV8 + /0QioTz33HO3jmcfh8UADh069Ldp06ZdmUgkDGPp5aqqw5FK5RyjJ7lKnU+PqMshNqO+6zkny+2HEZMw + ktKlmA75bWQS0O0VRV8Lo8/D/jd6diTTraGhAa+/vgsvvPACvN4qdVnvZLIQ9iMagKKcWtIfKE4LJppM + LBbFnj17ABQYq8VigdVqxe9+97tbfvOb3/SPZx+HlQk4ZcqUxng8rtlWrnSmB0MpNdUoE41tV8716UGu + 1wdakumdt9Q16GNZyagngeljeEyVFxLk+SSMbHTefdP91cvoG/rNfyZ6jL6cRCt6v9VqVavoDi2zNjTP + /1RT/WnQGkAmk1ULp/KQTCbj3B1jiGFpAA6HY6qiKHuLdujRBWcMlGIU5aTe6kFPQrP72G16bfScfzxJ + rXfOcvpQTp/YbfrSujQjNpLMes+u1D2W0rbYY0VRRCaTQXd3N5YuvRhXX30VDh48qImf05OzTlXQRULy + +Zw6fXrhwoXqfqIZrFmz5vEbb7yxajz7N1wfQNLn810EQJOdpHA4gCAIRhPltO1GgFL5Abxtejn7egRZ + Sg1nr1UuoehpFXrXMFLrWfAW5ChF3HrPwug+2XPrJQLpHQcUZhbGYjHkcjl85zvfwfTp09Uc+VOZ6FnQ + mmU0GsWMGTNwzjnnqFPkBUFAMBhEfX294/rrr//dePZtJFGAlNfrXQyKCZQrOcg2+pv3W0+6ldpWCnrH + lzPYTmT+AG+/Xt/LJUS98xhpQaWuX4rxsdcxCo+W6ocgDPkKjh8/jrq6Otxyyy3o6+sbsVCY6BAEAaFQ + COeeey5qamoQi8U0zzCZTOK666676ZZbbjlvvPo00jwAwgQ+LdVQjxq4U70AACAASURBVLjKIbqRSHW2 + TTmS2YgY2P88IjHqu14pMV7/CFEQlFMuW++e9e5Dr696/TK6htHcg3L7JEkSMpkM4vE4brrpJixduhTH + jh2HyWQaNoOfiGDfraIAF1xwAQCodTLIh6yG/b3vfe+P49W/E8kELGICpYjRaJseyiF4XvtyiKQUIyhX + s9G7ppH01OuD3nlEUQSE4fk5iJQuR5qX6mupe+e10WOavG19fX2QJAk//OEPkc8X0n0lSSpaPORUgyAI + 6loKhUIn01QGQPYTiKKIUCiE888///yf/vSnN41H/070yaZpJlDugOZtL5fbq22Eof+lpLEeyplDYLSN + 3l7q2rysQPKtJzHZiIKA4kiBkWZh9M1e2+heR0L0vHvWuw4hjkAggMsuuwzf/OY3B1dmtqpM4FQFqako + SRLi8TjOOeccnHnmmUgkEtz2pBL1bbfd9tt77rnHOub9G4VzqEyAl/46VhCYEINhiI7+XSbTKZdpsecp + hxEN12wplXPBfoxm5pUr7dk2RgxEj4HqZTOy7UkoMhQKAQAefPBB1NXVIZ1Ow2KxwGQynZJMgGhuoijC + bDYjmUzhwgsvVEub89oLgoBAIIApU6Z4lixZ8oux7uNoPdW01+u9SBCEv/EGqt6ALydtlfzXG4TsMSzh + KEohRqH+pjyy7Dbe9lLHkWQPupYgry39HNhj2d+82oTlHEMvYMKG0PSOJTF29ly89vQxRloH+z6MwDKL + np4enHHGGfje976HYDAIu90Os9nMLac90UGr/6Iowu124cILLwSgz9QJXaTTaVxzzTX33H333XPHtI+j + HG6xhMPh92VZPl+vQblx/uE4D3nhPTI4jZJIyr2G3jVpRjOS8+sxwVL7ef0Y7ntkB6CeOcTeJ7kWKeDB + O1cpGLXN5/OYOXMmEokELr10GQ4c2A+Hw6GWID9VZgMCGFw+3Qan0wlJktDYOBtbtmxGfX09/H6/IZNU + lEJ9hF27dr25cuXK5WPWx1E+X8bj8Xw+FAq9ryjK+SMZmAS8Y4dzLkVR4HA4YDab1SWaSCmmCk4MuVwO + 3d3dyGQykCSpLCmv5wOhmQph2j09PZg5cyZ+9KP/jRtvvBEejwdms1lNDjpVcgSI/W8ymRCNRrFgwQJM + nToV4XDY8DjybKLRKFauXLnsJz/5yTUPPfTQc2PRx7GoCpzxer2Lw+Hwe7IsX8ju5EnNchmFnsTlOZ5k + WUYikYDb7YbL5cKBAwfw8ccfo6GhYfB65d6OOsO/zO3lnK/UMXTnBJ1tpdIvlTLalgdFAQRhqMrN4sWL + MWXKFBw9erQkYbPbybumCZ7eL0nSYL58DKtXr8bTTz+Nl176M+rqatUZgafCtGBi/xcYgBmyrODCCwve + /1JrZJDxnUql4Ha78e1vf3sdgKlj0c+xWhcgO6gJvAdgIQDNS+dBjwmUUrMJ2HOTOnPhcBiSJKGmpgb7 + 9u3Db3/7OzQ3N49IbT5lwNA8eSyEkIeLwnGFAR0OhxEIBHH99dehqqoK4XCYq1mxDkmyjf7mHQMU3p3f + 74fL5cLatWuxa9cuAIDFYlHThCf6uyPOv4LvQkF9/RTV/qdh9CwkSUIoFMKcOXMa1q1b90+33377P416 + P0f7hBRyXq/38wA+AsoP89Ewkvh6nmeWCSiKgkAgAI/Hg3/8x3/EF794BTo6OqAoxmW0T2kwtKEoUDUe + 8ns4H6DAOCRJRHW1Dzt3voCjR4+irq4OkiQVlSTnRRqMnjW7n35vl1xyCb7znZvR19enOgRPhSXaaPU/ + kUjirLPOwjnnnKNZFVv3mVDbC0uMZbF69eqf3HvvvaOuBYz1k8x7vd7Ph0Kh9wEspNW/sQLrFCMDtLu7 + G1OnTsXatWsRi8WxY8d2zJs3D0RlPm2ZwQlDobzZZthsVvj9ATzzzDO47777UFNTg/7+ftVLX4rQeRoB + D6IoIhKJoLq6Gj/60f/Gc8/tQCwWh8Vi0azqNBGhVf9NiEQiuOCCC+BwODRrU7DH8DRkQRAQiURQU1OD + a6655g8AvjSafR0PVkqYwHsAFtGDgDcghhsy5LVlIYoi8vk8enp60NDQgJ///GeIx+PYsmUL5s6dOziQ + CrZ5hQ+wEAbj2KbBxUFtcDodeOWVV7F8+XJcdNFFIIvAmEwm3fdppLEZmQm9vb1obGzE97//fTzwwAOY + Nm2aWlqLLDY70UAzAEkqRALo2X8AP3JiZA4kEgmsWrXq6rvuumvFY4899sao9XUcbSmJMAEAIwrP8faV + 4xsgyOfzEAQBDQ0NAIBbbrkFmzdvxrx584pCTIV3Mbm5ARmkZIlwq9UKm80Ol8upqrWPPvprZDIZHD9+ + XFXN9aQZD6Xa5PN5TJ06Ffl8HsuWLcfevXvhdruQSCSQTk/MxVzp8J/ZbEZ9fT02b96MxsZGTfiPBY8h + 0HkcNTU16OzsPDB37tw5o9XX8WQAACAOmgOLSpkCRrH34cTp2X0sE/jGN76BLVu2YN68eeqKs4VkFyK5 + 6KNp79pYMwdeJGAkx48kSjF4pCBAEESYTJJatcZut8PhcMLjqYLfH8D999+Ha6+9Fj09PUilUkVaAAu9 + KIFeu3w+D0mSMH36dGzduhVf/epX0dAwdZABFGoGTjSHoMVigc1mg8tVYFTXXnst/vjHP6rVjowS2Yy2 + i6IIj8eD3/zmN9+/5557/m00+jreDAAoMIH3AFwE6GsCI2EO5bQXBAG5XA6iKKK+vh4AcM011+D5559H + U1MT0umMWp2GzpQbwmTQCgrmkCgOqbJmsxkWiwV2ux1Op3Owlp8JNTU1+P3vfwev14uuri7uijcE5UaA + 2Hb5fB4+nw9utxvXX389tm3bhvr6esRiMaTT6QkVFhQEQWWUVVVVGBjw42c/+ynuueceDAwMqG3YY0qd + EyiMY4/Hg0gkkrnjjjumbNy40TihoJz+niTuKYZCoXcBLAaGbw4MRxPQ25fP51UmoCgKLr/8crz22muY + Nm06Mpm0WsTxVEs+GU0Q5x9xZpnNFthsVpUB1NTUIBQKY/Xqb+HOO+9EIBBAJBLReOnLMQWMfAXkHIqi + YObMmfj444+xcuVKWK1W5HI5dd2AifJ+JEmC1WqFw+GAy+WCLMt4+umncemll2JgYKBs6a/3TBSlsHbA + c889t/6aa6454RmDJ4sBABQT4JkDpVJtR5p+S4NmAvl8HitXrsRbb72FKVOmqJKFMIDJxgjo8N0QAzCr + g7uqqgo+nw8ulxuKouDRRx/FvHlzcfjwYQAomrxTKs/DqB9A4V05nU5UV1fjBz+4D7/+9b9i6tSpiEaj + quk2EWA2m1X7X1GA+fM/h82bN8PpdGqWVCcYDvET2Gw22O12PPjggxf+/Oc//+uJ9PdkTrGSvV7vEgAf + GMX12d9GD6bUdvY6JETY29sLSZLw2muvYcmSJejr64PJNLSC61iHLiciSL4/iUNnMhlkMhmk02mkUmkk + k0kkEgnk84WsvfXrnwIAVFdX6z4r+h2w76LUGBDFwirBiqLghz98AE1NTYjF4rBarRNmtiDLMOPxGM47 + 7zx4PB7EYrGidvrMT3+Mk4gAANxwww1/PNE+n+ynpni93iWKorxPPxB6ALEEX44TyUiqsIOTMIG+vj6Y + zWbs2rULF110Efz+AdhsNrWKC+/YyQJFUahVbrPIZNLq0l2xWBweTxV2735zcE0/lzq/v5wkIB6MmEFf + Xx8aGhpw3333IRqNqHM8JkJyEGsymUwmNfxHqv8AKClQSOYlf19h6nQ0GsUFF1yw4Fe/+tV3TqTPJ5sB + AIDi8/kulmX5fRI/ZSVDKdVRj1OWyyAkSUI+n0dfXx+sVit27dqFCy64AH6/Hw6HE2bzxJAwJxtDK90W + NIJkMolkMoFkMgVJkrB+/dPIZDKoq6sDoD8NnCf92f3sMUBBC8hms0in07j99ttxySWXoL9/QNUCTvaU + YTr9V5ZlzJgxQ1P9h0Y5ERAjEJPn29/+9m9vuOEGz8h6PDEYAAAo1dXVFyuK8h5hAmUdVKaDyYihkH0m + k0llAg6HA7t378Z5550Pv39AjedOBClzMkE0gUKN+wxSqTQSiSQSiTjsdjv27t2LZ599Vo0W8LSAciID + tNZHa35kbPj9fpjNZqxdu1YNE5L3M1xtYzRBq/+xWAznnnsu5s2bh0QiUXQfRmZSOdcRRRHBYBB1dXXu + 22677YGR9nmiMABgSBN4rxTR0ttLnpTjM6AHJZ1oQTMBl8uF3bvfwPz58zEwMKBOLT7ZUuZkg9SxHzIF + Cr6AeDwOt9uNzZs3o6+vD3V1dYYDHeCHw3j+HraNoiiIRCK48sor8fWvfx09PT2w2+0nVQtg1f90Oo0L + L7wQkiQhmUyq7UpNihsu/H4/rrjiijNGevxEYgAAgEEm8G6plXJZlNpfrv1OmEB/fz+qqqrwxhtv4Jxz + zhk0BxywWCyTngkQxyBRx4lDUBRFdHf3YMOG/wIAuN1uTYi3XO3OyHdAtkejUQDA2rU/hs/nQyaTPanl + w8i9kRqGVVVVmuo/dN9H4rui29DnE0UR8Xj8vZH2e8IxAADw+XxLeUwAMHaO8PYP10QAhuak9/f3w+fz + Yffu3TjjjDMqTGAQpC4A8QUUHIIJxGIxeL0evPTSi/jss8/g9XrVadk81VcvIkD2se0IyLgIBAI499xz + cddddyEQ8MNmO3laALH/C9I/g7lz5+K8885TM0/LQSkhpecIVxTlzyPu90gPHGv4fL6l+Xz+3XLLQuvZ + mOx+9je9jVbPCBMYGBhATU0Ndu/ejTlz5qiOwcnOBGgGQGsBRCt46qn1AACfz1fk9S4nMqBnuhGIoohU + KgVZlnHvvffizDPPQiQSPmlhQXryTywWw4IFC1BXV6eG/8oZn6VMJl70QBCEoy6X67MR93ukB44Hqqur + l8qy/A5rs5dSD41ULJaLGu2XJAnZbBYDAwOor6/H7t27MWvWLNUxOJmZgJ4WQHwB7777Ll599VXVd0JM + AX3CN9YC6P/0N2HQP/zhA4jH40xYcHwcgnTpb7O54Cgm6j+bpqyvwRrv19suiuKrI+mzevyJHDwe8Pl8 + l8iy/DatCQxnarCel7mcc9BMwO/3Y9q0aXjzzTcxbdo0DAwMRQcmKxOgw4K0FpBIJGGxWLBhwwbE43HU + 1tYaOnILn8EZCAZMnNUiyDTvZDKJm2++GZdddhl6e3ths9kGTYHxGd60/a8oCqZObdBU/ynPDC3vOuy5 + RFF8ZUSdJsefyMHjBZ/Pd6ksy2+TB806QngoFWctRw0lMJlMyGQy8Pv9mDVrFt58803U1zdgYGAALpdr + 0jOBYodgHDabFW1t7diyZStMJhPsdnvplO4S6jHvGEEQEA6HIYoi1q5dqxYpHc+wIG3/JxIJnH322Tjr + rLN0lwE3Qrmp7FQk4fRnAMAQE2Adg+XaTCMdCITZ0EygubkZu3e/gZqa2kmvCZAinUPJQUMZglVVVdi2 + bRuOHj2K6urqIhOOF+5loRe+JSBaYSQSwRe+8AXceOON6O3tHbf1BGjpTxb8uOCCC2Cz2XRX/2GPN5oJ + WeLYvzmdzp4RdXwQpwwDAFQm8BbhuOU+rHK0gXKOJwtZBgIBnHHGGdi9+w34fD74/f5JzQS0DsHUYHJQ + YfD7/X48/fQGAIWwYDmebp63u9Qx8XgcAPCjH/0IU6bUI51Oq1rAWDoEteE/CQ6HQ03/LTA74+OH4/ln + 256o/Q+cYgwAAHw+37JymQA9gIZTL8AIkiQhnU4jGAzinHPOwRtvvIGqKs+kZgL0XIGCQzA56BCMwePx + 4JVXXsHHH38Mt9ut2smlUEozINuJRkEyBOfNm4d77hm/VYXo2n/ZbBZNTU0477zzqHs8MeHDm/pOfkuS + NPkYAKAygTfLld5Gnn+6TbkqqMlkQiqVQjAYxPz58/HGG7vgdrsnNROgTYF0OqM6BDOZQtmu9evXQ5Zl + eL1ew1BYOZmDvHcqCAKy2SxyuRy+973vYcGCBQgGg2M+T4BmALFYDPPnz8fMmTM1s//0UK55ymsnSVLG + 4XC8cQJdB3CKMgAA8Pl8y2VZ3j1Ue90YpUJMevv0BqQkSSoTOP/88/H666/D6XSqyUITYXLKeKJYCyj4 + AuLxOFwuJ/bs+QgvvvgibDabGhbk+QJKSXsjiKKIQCCAqqoq/OhHP0IymYTZbFYZ8mg7BGn1v5BBmlO9 + /5lMpmzTspzrcLTZNwHET6D7AE5hBgAAPp9vRS6X20VehBFYLjocW1RvPzEHQqEQFi5ciNdee00t/ex0 + OifMPPXxwpAWkFFnCxbCggnY7Xb86U/PIBQKoaamBsDwpleX21ZRFCQSCXzzm9/E1VdfjZ6eHiosOLoM + Wbv4h4Da2lrd2X/loNQ9MinFJ6z+A6c4AwCAmpqaL+RyuddJIoYeSnmTWZSjnhHGk0wmEQqFsHjxYrz8 + 8suwWm0qEzCbzZOKCZDcADJbkGgBZrMZBw8exKZNmyCKom5YkEDvfemaaZQGEYlEAABr165Vr0PmCYym + FkAnACWTSZx55pn43Oc+N+LqRPpJQtoJRINmaIUBENTU1KzKZrOvl2MO8JwpPAxHPSPmQDgcxtKlS/Hy + y3+B2WyelEyADQsOFQ4pOAR37HgOBw4cgM/nA2C86tNwcjVAMWyyhNnFF1+M7373u+jv71dnC47WlG42 + /BePx3H++efD7XYjFouV1e+RFpgRRTFgt9s/HNHB7LlG4yQTATQTMCI2nmQphXLMAVKyKhwOY9myZXjp + pZcgihKCwaCaDjtZmMBQhuDQPIHk/9/euUdJUd15/Fvvrn5Ud0/PICAE42iChjgJBDEIA/giIQnrWRNO + Eg+anOMD85Ro8CjEmI1k1ySL2XhUxMSEeFg0EsUl6DoaD1l3TzI8BwSJAYmRCAzDzPT0s/pZ+0fPLW7X + VFVXz/TMMD31Ocfj0F1961Z33W/97u/3u7+bTkHTiojF+rBp0yYAZ8OCVQ30fsz8NPRrZAnuqlWrMGVK + abvxWq4WNM7/RVHQ5/9Odyyq9pqp6/wDMMQdX/upqzuyXwRedzLfc1KYwgw7M5TjOKRSKcRiMVx11VV4 + 6aXt0DQNfX1940oEzByCqVRKtwJ27Pgj/vSnP8Hv9+urBYHqfgPyf6uEIo7j9MzNlSvvRF9fn+4LqIUV + UHrQcPqisQ984AP6/L/WzkYjDMMMKfuPpu7uxkgkcnU2m33daAmYRQGqrcrixKtL0kHj8TgWL16Mbdu2 + oVgsIhaLjysROOsLICnCJRFQ1dLmmJs2/SdyuZw+FXCC0RvupA+5XA533HFHf53H7pqFBUtPf7Y//JfE + jBkzcNFFF+mFSytdx2BhGAaCILgCYEckErk6l8v9gXYM2lUUskq0sMKYzmpsj+M4JJNJxONxfPazn8UL + L7ygV88dTyJQKh92NkOw5BBMwOfzYv/+/fiv/9oGURTLVgsSrKZqmk3FXLPPkoSg++67D5lMVi9vPhSH + oHH+n82Wqv8wDFNW/ccKs7z+SucjfWVZ9h1Jko4NquMm1O1dGIlErjGKQCWq8QmYQf+QRAQSiQSuv/56 + PPvsb5HL5ZBMJseNCJglB5GogM/nw5Ytz6Grq0sPC9IMCNui3xNeIbOOfJb+LZPJJK6//nrccMMNNQkL + 0uE/hmEQCoXKwn+VxIn857Q8mGFNS82e/kAdCwBQEoFsNmsrAvSPQG6yWsGyLBKJBJLJJJYt+wI2bSpV + zSVx8fEgAkaHYCqVRjKZAs9zOH78H3j22WcBQC8iCpRbZkC/GNiUyqaPJdAiQLLyVq++D4qioFAoDMkK + ID4GUvvv4osvxmWXXeZoo1LjArVqz8/zvCsA1dAvAq9ZhQjLTE2TohROsXMMxuNxJJNJfPnLX8ZvfvMb + 3TM+HkRgYFgwTZUPC+Gll17G4cOHEQwGTadT5O8qn5JlIsKyLKLRKD7+8Y/jtttuw5kzZwYdFiTtkeW/ + iURp849IJOI4/Ef6Wy0sy2qyLL9e9Qft2qxlY+cqkUjk2lwu96oTERgMxieW8eYlGzmkUiksX74cTz31 + VP8OO6p+I9azCFgVDikU8kilklWtFrSDNq2Nr2ezWQDA3XffjQsvbEY8nhhU+TAi6sQCYFnWsvqPU5xe + M8uyuwD0DOokVm3WsrFzmUgkcl0ul3u1kmMQcLYSzQoz85U8MWKxGNLpNL761a/iySefhKqqUNVM3YtA + eVgwV5YcpChB/N///S927NgBr9fbvxNTdSJgFuExO6a7uxvnnXce7r77LiQScYiiVLUVQAS9tPuRhsmT + J1ed/uukv2YMtfqPaZu1bvBcJhKJXKeqapsTx6DRoeQEu2ou5MnR19eHdDqNW265BY8//jhUNY1sNquL + wHDHkEeLs5WD6HUCJacgzwvYvHkzUqmU7WpBI1ZPfKtji8UiMpkMbr31FsyfPx9dXV1VOwTp9N9kMjks + 1X9sjq9J+i/NuBIAAGhqalpMRIAo/1AqtRqPN/s8/TdJU1VVFStWrMAjjzyCdDqNbDan+wTqXQSMRUQ9 + Hg8OHXoLW7e+qK/eq5SmbcwHcBq9KW1fXtpVSNOKYFnWsUPQGP5T1TRmzpypVwKq9kFRze/MsmzS7/f/ + r+MPOG231g2OBYgIELPbyQ8/GI8t/XkCuYGi0SgymQy+8Y1vYN26dUinU8jl8nUtAsbdhs+KQAKBQADP + P/88Tpw4oe8wbJW7QV4fbBpxIpHA4sWL8aUvfUkvH+bECqDn/xzHwe/3D9j8Y6hYtcOy7B8BZGtyErrd + Wjc4VmhqalqcTqdfoYt3WCUDkZtxsLXb6PboCja9vb3IZDJYuXIlHnroIaRSSeTzBX3NfD2KAL3LML3N + OMsy6OzsxObNzwCAvorPzB9j5my1wswqI+XK7r33XkQiEWSzWUfrBOj4fyaTxYUXXoiWlhbHuf9DYTjm + /8A4FgAAaGpq+lQ6nX6F/uHN6gZUk0ZshfEz5Gbq7e1FNpvFqlWr8MMf/hDJZALFYrFuRUDTBu4nQNYJ + hEJBtLW9gv3790NRFP07qzYF2Hg+YKAVFo1Gcemll/bvKtTjqHyYsfrPZZddhsmTJyOZTDruH90P+qFg + Ny3of63m839gnAsAUC4CZB5oZXoO9iY0awM4e0P19vYil8thzZo1uP/+7yORSEDT0O+gqj8RoB2CJBya + SpX8INlsDps2bYKmaXpYcCiWF/0Z+vvP5XIoFou48847cckllyAa7dOtADMRoJ/+JR9Fsaz6j9P+WV2L + mTBQ5z7p8/kOOL3eahj3AgCUREBV1f8mGzvSImAUhFoPRnJT9vT0IJ/P4wc/eAD33Xcf4vFSUQuPR6o7 + S8DMCqB3FWpv34m2tjbIsjyosKDVOQn0d97Q0IB77rkHqVRSX5dgVj6Mnv9rGjBhwoRBV/+hHyS0hVnK + eBxYBLQW1X+tcAWgn6ampk9nMpmXacdgpejAUByDNOR83d3dKBQKWLt2Lb773e8iFouBZVl9u6t6EgGz + 5KB0ulQ+TJIkPPPMs4jFYlWtFrTCrLIu+S5VVcVNN92Ea6+91rCrEFcWuaGz/9LpFKZPn45LL7207Olf + TX/MYBjGdJE/wzCvVn0Sh7gCQNHY2LhEVdWXjY5B48CjzdJaeX/JDXbmzBkUi0X8+Mc/xsqVK9HX1wdN + 0/Qbs95EgCQH0bsKSZKIo0eP4ne/+x04joMoilV9z0ZhNkvOIv+Ox+NgGAZr1qwBy3J6+TDa20+b/2T5 + b0tLC3w+n74fAc1g/BRla1IG+opcC2CkaGpqWpJOp1+wyhOoJjGoGujoQFdXF4rFItatW4e77roLiUSi + LpOF6CKidCnxUoZgAFu3voh33nlHTw6qpjCoA6ea/nc8HkdraytuvfXWsvJh9JOf3v1XlmXMnj1bv4YB + 5xjC72PsN8uyB2VZfn/QDVbAFQATmpqa/jkej/8LcfgA5T+MmSk51EFJt8OyLE6fPo1cLoef/vSnWL9+ + PVRVRSaTqbulxGetgFLRELKEulAoIBbrw2OPPY5CoQBFUarOEKRXDtuZ3el0Gpqm4Uc/WosZM2YgGo2W + TQXIw6C0PVwGl1wyHXPnztVX/w1wVA7yu7AQqxcG2Zwj6uMuGgYmT578/Xg8/gAxQa0G/nBYBMTh1NPT + g2w2i9tvvx1PPvkkMpkMMhnaEhj7Px+9TiCXy+oRgUQiAb8/gPb2drz00kvweDwVdxUaEKnRBjrazCC7 + CoVCIaxevbpsPwFSQIQO/7W0tGDChAllm3/U4h4wW8TEcdx/D7lhG8b+HTSMTJ48+QfRaPT7JF2Ujktb + VXWplRjQyUJk7UDJEji7dkAQ6mMBkdmS4VQqhXQ6BZ/Ph9/+9jn09PQgHA7bCoCZp9/OUWv8zdLpNL74 + xS+a7idALABNg+nqv6H6gix8FlFZltuH1HAFxv7dM8xMmTLlX3p7e79HPMDAQK8ynaxSy4IiRATIKsLb + b7+dWjuQLUteGet+gfKwYPl+Au+++y62bNmiR0ScikAljIPubOGQ1fB4SgVKaEtA0zRMnDhxQPWfWkSD + zPrNsuwOAJWrjAwB7oEHHhjO9uuCYDD4P52dnXmv13sVwzBlqZ+VEoRq4RtgGAaqqoLnecydOxehUAi/ + //3vkcmU9t0TRUFPGKpVaHKkoZ/G5U43Dn5/AEeOHMHll8/WM+/IsQSrv6uBYRgUCgU0Nzfj1KmT2LFj + BxobG/W+pNNpzJo1E3fccQcKhUJVCUD0dVY6lrzPcdxjoijuHNTFOMQVAIcEg8E3urq6crIsX02LgNMf + k/53tTcoLQKCIGDevHmYPn06gJL53Nl5Gvl8HsViEZqm6U+tsSYIZyMh5SLg8chIJBJIJBJYuHABgFIm + X7XfvXHwmQ3GXC4Hn8+HGTNm4LnntiCVSsPnK+312NvbixtuuAHXXHONvvuQ03NXet14DMMw8Hg8d3Ec + d6biB4aAKwBVoCjKG52dnVmv13s1qWc/VJmu9QAAEitJREFUFJPf7Ia0g2EYvez0rFmzsGzZMtx4441Y + vHgxLrnkUiiKAlVV0d3dXSYIJK5NEo7OdUEgVgDDlEpvsyyHYDCII0eOoLm5WS+/TY61C/XR37GZGJuh + qiomTpwITdPw4otbMWnSJHAch1wuhxUrVuDDH/6wfn6n11PqDGxDBPRUkmXZ93w+32rHJxkkTC3nrOOF + 48eP3xsKhX5ETEbgbHjQ6iajfQTGvwlWq98IZDPSVCql56STRTOErq4udHR0YOfOndi5cyf27evA8ePv + lbUjSRKAkvVARKKaOPtwI4oiJEmC1+uF3x9AKBREQ0MDCoUipk+fjnXr/h0Mw6Cvr2+AADh5yleCbGOe + y+VwzTXX4J133kE4HIaiKNiyZQumTp2Knh5nlbkGCDxjXddY0zTdqcvz/C8DgcAtVXV8ELgCMEiOHTt2 + 77Rp037EcZw+kIBSSInMD42JRLlcTs9tz2QyeoZboVAAaaf/ePKjaCzLasViUdM0TSsWiym/3x8kFXVI + W2QQiKIIRVHK+nny5Ens27dPF4SOjg6cPHmy7BiPx6P3Q9O0IVs2Q4U4+zweGT6fF4qiIBQKoaEhgmg0 + im9/+1v4/Oc/j56eHhQKBVMHLAPG9GnrRBBIO42Njdi6dStuvvlm+P1+fPrTn8YvfvELxONxxynAdL8q + RSPItQOAKIpf9vl8mx2dZAi4AjAENmzYMO/tt98+X1GUZD6fLwqCoKVSqWI+ny8qilJMJpPFdDpdFEVR + i8fjxXA4XIzFYsW+vr5iQ0NDUVVVrVAoaCzLaoVCQQsEAlo6ndZ4ni9yHKelUilNVdViKBTSVFUtnjhx + ovu666678Tvf+c7Po9GoPg82piWTASFJEgKBQFmf//GPf2Dv3r1ob2/XBeHMmbPTTPK50RYEQRAgSRJk + 2Qu/34dQKIRwOAxBEBEOh/Czn/0M5513Hk6fPj1gByirfI2SJpRPDawEQdM0yLIMn8+Hr3zlK9i4cSOe + eOIJvaqwE/+Dbc6/YRGQ0VIMhUITAXQ6/8YGhysAY5COjo6Oj33sYy2dnZ2mS1erEYS//e1v2LNnD/78 + 5z9j586dOHDgAPr6+vT3WZaFKIq6lUNPGYYT0l+PxwOv14tAoGQFNDZG0NcXw7JlX8A3v/lN9PX1IZvN + ltVzMBt81U4DyDU2NTVh9+7dWLp0KZ555hm0traiu7u7ptdp/J1Ylu0IBoODW2pY7fldARh7rFixonX9 + +vV/TCaTA2rR2T3R6PeIme33+8uO+8tf/oJdu3ajvb0du3fvwptvHkQqdXbBC/E9jIQg8DzfbwWUnsTB + YBDhcBh+fwDFYhE/+cmP8ZGPfARdXV2WeRhWIVqnprkgCAgGg/j1r3+Nyy+/HM3NzfoCoqFg7BeZ/zMM + A57nfxIIBFYN6QRO++EKwNhk+/btL37mM59ZajSBaczEwLiwCTjrdZdlGV6vV3+/UCjg0KFD/YLwZ+ze + vRuHDh0qm/+SRKThEASGYSAIAmUFBHRfgKqquPLKK7F27YNIpVJlVXmMbVh9H3YCQA9MWZbh8Xj0NQrD + tSCMCIAgCNf5fL5hWwJM4wrAGOWmm2764COPPHLU6/Wyvb29A0TAOMcEzENjVoLAcRy8Xi88Ho/+vqqq + ePPNN7Fr1y60t7djz549OHz4cFliFBGEQqFQkwgDx3H6VIBYAcQfEI/HsWbN93D11VfhzJkzFQem2fWb + fV9mr0uSpNcwGA6IBcNxnKooSgOAyruM1uK8rgCMXR599NGffv3rX7/Lyc0POA+Jmd0TPM/D5/NBFEX9 + tVgshgMHSoKwc2c79u7di7/+9a9lnxNFUY+MDEYQ+k1i3Qrw+/0IBkNoaAgDYPDBD16Ahx9eB1GUQITQ + TviM/7YSBeN7xNcyXAVAKQF4TVGUa4flJCZUtzGayzlFe3v795cuXfqVqVOnRqwcgjR2Tz2rHAQyaPL5 + vO4cJBZCIBDAvHlXYt68KwEAPT092L9/f78g7MK+fXtx7Fj5TtZkZWU1OQiapuk7DPO8ClFMIZmUEIlE + cPjwYWzd+iJuvPFGCIJg+oSmQ6XG78N4XqNFZDZXr7X5T8f/GYap6d5/lXAtgDHOmjVrbnvwwQefoMOC + VtTSSiCFMMixPM9DUZSyqcjp06cpQdiJffv24b33Kicl0WnWxnJcsiwjEAjoDkGPp+S3ePjhdZg6deqA + sKBT6NCcZRgRA52HA5yLFvkHlSCWiyiKs71e7+7qWxgcrgDUAXv37j04c+bMj5haARqgwfmct1rM7h/i + vDNmKZKkJCIIHR0dOHHiRNlnjUlJZGDQFXk9HhmKoiAcDiESaUQ8HsPSpf+Eu+++C7FYDJlMpqprM/OH + mEUJbEOL/Vl+5LhKST9Gy6v/+roURZnguOM1wJ0C1AFPP/30t1paWv7g9/uRTCbLn4BU8guNXRJMJaym + C+Q9TdOQzWb1BCMiCJMmTcKkSZOwZMkSAMDx48exb98+tLe3Y9euXejo6EBXV1dZu/SiJrLsuVDII51O + Q5JESFIcwWAIr77ahquuWoSZM2fi9OnTjq7L7ulezYPRbCpVzeepvg5b7T/Lc7sWQH2wbdu27Z/73OeW + 0Dd/Nea+ldlr5zl3itmT0yxt+dixY9izZ48uCPv3H0BfX1R/n0QCeF4Az3OQZRnBYBCRSCNyuSxmzZqF + hx76N2QyWcTj8REtlmI2NbATBfo9Kv5/WyAQeHLEOg1XAOqG5cuXX/Too48e8Xg8iEajZesErOLfBDvv + t/F9Grv2K5nAxvRXsyzFw4cPlwnCwYOHkEyWinZ4PB40NTUhGAxCURQ0NEQQi8Vwzz2rsGTJEkdhwWqo + NPd3+jly7TTEspFluVmSpGMDGhlGXAGoIzZu3PgfN99887fom7+a0Bd5jWCXN1CrgWXlQyDZf4R8Po+D + Bw9iz5492L17N958800cO3YMsVgMHo8HU6dORTgcxrRp0/Dwww8jEAigu7v7nCyZRn4X8vTvn/8fVRTl + 4hHviysA9cOSJUuUDRs2vDtlypSw0SFoNrDp162EwOnr9PtORMUO4z3Jsiy8Xi9kWdZfSyaTOHz4MA4c + OICDBw/i6NGj6Onpxd///nfceuutuP/+78FJZGQ0IfkF/f6NxxRF+fpI98EVgDpj7dq1X1u9evWjvb29 + eky8UmKM8bVqEmnof9M4ua8q+Res2jDLUoxGozh69CgOHTqEI0eOYPny5WhubkY0GjVtw+68IwkRAEmS + bpBl+fmRPr8rAHXI3r17D8+cOXP6qVOnTJODnIS9zAa31fGV2rZrsxJWjkoakh9ABCGbzaKnpwderxf5 + fF6vGTDamAlOf93DoqIojQB6R7pP594EyWXIrF+//k4A8Pv9piE7s8w7Ywac8T2j085sMDt53e5ctIPQ + SixISJB+PZ/PIx6Po6urC2fOnEEqlYIsyygUCvocu9qwXqX3nWQwGjGGGalr2IVRGPyAKwB1yYYNG15p + a2trIwJgN7itIIPM+FmzJ6lZuqyVNWFs10mY0Yn3nW6XlBcnT3+6HWMfzQYx3Sez785MhOz6bdY2/TfL + siOy8s8MVwDqlM2bN387Go0iFAoNagGL1dPNbFDYiYrZsWaD0KotOwvBLAGJhmHOrjkwEx/6OLNzGQe5 + WaKQ1RTJ7m+jkPA87wqAS2351a9+9ZetW7c+JknSORkKqwa7JBqnGAcubAaulWjZCaKZMDjJvWAYJu7x + eP7k+EJqzNi+M1xs+eUvf7nm1KlTsaampjJTeLhxaiKTY60YMGgNr1fCzErQz1mhDbvphlW/6PfNRMNs + /s+y7B8B5Bxd0DDgCkAd88Ybb/Q+/fTT9wNnV92NBNU4yGoRhXIiItW+ZuaTqGVWISUAI7r8d0Bf3DBg + /bNnz56/zpo16+JTp06VFcxwGV7srIjS7s4MeJ7/qN/vPzjCXdNxLYBxwMaNG1cCpbAgHQasNozlMpBK + DlA7y4JhmPdHc/ADrgCMC37+859v3759+6t+vx+yLEOSJPA8r1sDtRaEsSIqwzX9oL9Lu7DpaIb/CK4A + jBNee+21ZZ2dnWuy2eyrhUIhzvO8XmNPkqSyvQM1TRtSdd/BxMedvj+U96w88U6Pd3JeOnxot46CYZhR + n/8Drg9gXPLee++FNU37JICFHMct9Pl8s4lFoGmankBjtiNQLfwHZk9GM4+90xWMTtq0at8snm/VtrE9 + 8jljW/TrZn+T+b8kSVNkWX7f8sQjgCsALjhy5MiFPM/P43l+kcfjaRUE4UJBEACU9gYg/1k9FY2Dg8Yq + YabS4LZLtKl0TDWLlyr1xW7QG78D+hgzNE0juf/gOO6goigftTx4hHAFwGUAe/fundXY2DifZdkFkiR9 + UpKk88jCGlVVUSwW9bwCs7kuKYxpNgDtFgsZXzd7utoONAaWe/9Z3ed2VkElnAx6Y/Ygz/NEANYFAoG7 + HJ1oGHEFwMWWd99916Oq6pxMJtMaDocXBAKBKziO85EpQyaTQT6fp3c2HigINuaxHVbH2YnFUBhMhmG1 + kO9NFMUlXq/35WE7kUNcAXCpivfffz+SzWbnchy3CMCCQCAwk671b/QfGAdptQx2YFd6+tdCMKpB0zS9 + tDnLstlgMBgBkBixDljgCoDLkHjrrbcuEgRhvizLiwRBmO/z+S4QBAG5XE4XBKsNQMZTQhKZ//c7AHcE + g8FFo90nwBUAlxqzY8eOT4TD4dbzzz9/gaZpn5QkqYn4DzKZjG4dGCMM55IYOIkMVEuxWNT3TeR5/nt+ + v//BmjU+BFwBcBk2Tp486Y3FYnMymUxrMBhcEAwGr+A4TiZhsGw2i2w2e85aB3ahSbvP0NBTDUEQyLbs + c2RZ3ln7HlePKwAuI8aBAwcmeDyeuYIgLBJFcYHP52shG39oWqmQh9GhCFRfQszJZ5yECMnrTsKKlXIA + yPyf47huRVGaAJwTA88VAJdRo62tbfrFF188n+f5hYIgzAsEAh/geV5PRspmswM2EaXy6Cu2bxd2pHES + Ziwb5IblxHbnIM5RnueJAGwJBAJfqNj5EcIVAJdzBeb111+f3djY2BqJRBbwPP9Jn88XIRGGdDqtOxZp + C8Es3GiVPOQ0N6DWaJqmb5PO8/zX/H7/4yNyYge4AuByTnLgwAGfJElzCoXCAq/Xu1BRlDmiKEqiKELT + NKiqilwuV7ZuATBYBtSTeqTDfgQiNkTIZFn+kCRJR0a8Ixa4AuAyJti1a9dERVHmcRy30OPxLAgEAjNk + WQbDMFBVteb5B7WCzP/7HYB/CwaDF45aZ0xwBcBlTPLGG29cqihKqyzLC0Oh0JWBQGCKLMvIZrOmgkAY + CTGgpyEk/Nc//38iEAisGPYOVIErAC71ALdt27bZHMfNnzFjxkK/33+FJEkNPp8PuVxO9x/QC5rIIB1M + mM9ugRJ9DDkPWW4tiuIyWZafq/G1DwlXAFzqjrfffjuQSqXmpNPpBRMnTlwUiUTmyLLMkx2CcrkcMpnM + gIQkWhDMnIcEu5ChETL/Z1kWwWBwAoCu4bjmweIKgEvds2PHjikArrzgggsWCYLQqijKJR6PB4VCAfl8 + viz/gPYfmIUcqxkvZPVf//x/j6Ion6jphdUAVwBcxh0bNmz46Jw5cxaEQqFWWZbn+v3+871eL7LZLDKZ + TFn+Ab2pSvkTn0GlXB5N0+j5/78GAoH7hueKBo8rAC7jHb6tre1yURTnX3DBBQuDweAVoiiGZFkGy7KI + xWIDEpIIlaoIAaVy7P3x/6v9fv+olwAz4gqAiwvFyy+/rEyYMOEKnucXiaK48Pzzz79ckiS9dqaqqrog + VHIo9q/7B8uyqWAw2AAgMxrXZIcrAC4uNjz//PPTpk2bdmUoFFokSVJrOBz+ENlkhYQcrUqmCYJA5v+v + KIryqdG6BjtcAXBxqYKnnnqqpaWlpTUcDi+QJGluQ0PDJFmWoWkaEomEvisxHf8XBGGVz+f7yWj33QxX + AFxcBslbb70lnj59+vJkMtna3Ny8YMKECVfIsqzIsoxisYhUKoV8Pg9BED7m8/n2j3Z/zXAFwMWlRmzd + ujXU1NQ0V5KkhcFgcGFjY+NsjuOiiqKER7tvVrgC4OIyjnF3BnJxGce4AuDiMo5xBcDFZRzjCoCLyzjG + FQAXl3GMKwAuLuMYVwBcXMYxrgC4uIxjXAFwcRnHuALg4jKOcQXAxWUc4wqAi8s4xhUAF5dxjCsALi7j + mP8HaXmb6e5VKzoAAAAASUVORK5CYII= + + + \ No newline at end of file diff --git a/Unity Studio/app.config b/Unity Studio/app.config new file mode 100644 index 0000000..18d7535 --- /dev/null +++ b/Unity Studio/app.config @@ -0,0 +1,48 @@ + + + + +
    + + + + + + True + + + True + + + True + + + True + + + 0 + + + True + + + False + + + True + + + True + + + 2.54 + + + 0 + + + False + + + + diff --git a/Unity Studio/helpers.cs b/Unity Studio/helpers.cs new file mode 100644 index 0000000..40148f2 --- /dev/null +++ b/Unity Studio/helpers.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace Unity_Studio +{ + public class PPtr + { + //m_FileID 0 means current file + public int m_FileID = -1; + //m_PathID acts more like a hash in some games + public long m_PathID = 0; + } + + public static class PPtrHelpers + { + public static PPtr ReadPPtr(this AssetsFile sourceFile) + { + PPtr result = new PPtr(); + var a_Stream = sourceFile.a_Stream; + + int FileID = a_Stream.ReadInt32(); + if (FileID >= 0 && FileID < sourceFile.sharedAssetsList.Count) + { result.m_FileID = sourceFile.sharedAssetsList[FileID].Index; } + + if (sourceFile.fileGen < 14) { result.m_PathID = a_Stream.ReadInt32(); } + else { result.m_PathID = a_Stream.ReadInt64(); } + + return result; + } + + public static bool TryGetPD(this List assetsfileList, PPtr m_elm, out AssetPreloadData result) + { + result = null; + + if (m_elm != null && m_elm.m_FileID >= 0 && m_elm.m_FileID < assetsfileList.Count) + { + AssetsFile sourceFile = assetsfileList[m_elm.m_FileID]; + + //TryGetValue should be safe because m_PathID is 0 when initialized and PathID values range from 1 + if (sourceFile.preloadTable.TryGetValue(m_elm.m_PathID, out result)) + { + return true; + } + } + + return false; + } + + public static bool TryGetTransform(this List assetsfileList, PPtr m_elm, out Transform m_Transform) + { + m_Transform = null; + + AssetPreloadData TransformPD; + if (assetsfileList.TryGetPD(m_elm, out TransformPD)) + { + if (TransformPD.specificIndex >= 0 && TransformPD.specificIndex < TransformPD.sourceFile.TransformList.Count) + { + m_Transform = TransformPD.sourceFile.TransformList[TransformPD.specificIndex]; + return true; + } + } + + return false; + } + + public static bool TryGetGameObject(this List assetsfileList, PPtr m_elm, out GameObject m_GameObject) + { + m_GameObject = null; + + AssetPreloadData GameObjectPD; + if (assetsfileList.TryGetPD(m_elm, out GameObjectPD)) + { + if (GameObjectPD.specificIndex >= 0 && GameObjectPD.specificIndex < GameObjectPD.sourceFile.GameObjectList.Count) + { + m_GameObject = GameObjectPD.sourceFile.GameObjectList[GameObjectPD.specificIndex]; + return true; + } + } + + return false; + } + } + + class TexEnv + { + public string name; + public PPtr m_Texture; + public float[] m_Scale; + public float[] m_Offset; + } + + class strFloatPair + { + public string first; + public float second; + } + + class strColorPair + { + public string first; + public float[] second; + } + + public static class StringExtensions + { + /// + /// Compares the string against a given pattern. + /// + /// The string. + /// The pattern to match, where "*" means any sequence of characters, and "?" means any single character. + /// true if the string matches the given pattern; otherwise false. + public static bool Like(this string str, string pattern) + { + return new Regex( + "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$", + RegexOptions.IgnoreCase | RegexOptions.Singleline + ).IsMatch(str); + } + } +} diff --git a/Unity Studio/unity.ico b/Unity Studio/unity.ico new file mode 100644 index 0000000000000000000000000000000000000000..99df2d1485078389332fd31d446dfea32bf531b6 GIT binary patch literal 29363 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