mirror of
https://github.com/Gericom/EveryFileExplorer.git
synced 2025-06-19 09:25:42 -04:00
496 lines
14 KiB
C#
496 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using LibEveryFileExplorer.Files;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using _3DS.UI;
|
|
|
|
namespace _3DS
|
|
{
|
|
public class ThemeFile : FileFormat<ThemeFile.ThemeIdentifier>, IViewable, IWriteable
|
|
{
|
|
public Color topSolidColor;
|
|
public Color bottomSolidColor;
|
|
public ThemeFile(byte[] Data)
|
|
{
|
|
EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(Data), Endianness.LittleEndian);
|
|
try
|
|
{
|
|
header = new ThemeHeader(er);
|
|
|
|
topHeight = 256;
|
|
bottomHeight = 256;
|
|
|
|
switch (header.topScreenDrawType)
|
|
{
|
|
case 1://solid color
|
|
er.BaseStream.Position = header.topScreenSolidColorDataOffset;//7 bytes here, first 4 is rgba, other 3 unknown (possible overlay colour ??)
|
|
Byte r = er.ReadByte();
|
|
Byte g = er.ReadByte();
|
|
Byte b = er.ReadByte();
|
|
Byte a1 = er.ReadByte();//alpha makes the colours appear lighter because the 3ds does blending
|
|
topSolidColor = Color.FromArgb(a1, r, g, b);
|
|
break;
|
|
case 3://texture
|
|
switch (header.topScreenFrameType)
|
|
{
|
|
case 0://tex1
|
|
case 3://tex1
|
|
topWidth = 1024;
|
|
topClampWidth = 1008;
|
|
topClampHeight = 240;
|
|
break;
|
|
case 1://tex0
|
|
topWidth = 512;
|
|
topClampWidth = 412;
|
|
topClampHeight = 240;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
switch (header.bottomScreenDrawType)
|
|
{
|
|
case 1://solid color
|
|
er.BaseStream.Position = header.bottomScreenSolidOrTextureOffset;//7 bytes here, first 4 is rgba, other 3 unknown (possible overlay colour ??)
|
|
Byte r = er.ReadByte();
|
|
Byte g = er.ReadByte();
|
|
Byte b = er.ReadByte();
|
|
Byte a1 = er.ReadByte();//alpha makes the colours appear lighter because the 3ds does blending
|
|
|
|
bottomSolidColor = Color.FromArgb(a1, r, g, b);
|
|
break;
|
|
|
|
case 3://texture
|
|
switch (header.bottomScreenFrameType)
|
|
{
|
|
case 0://tex4
|
|
case 3://tex4
|
|
bottomWidth = 1024;
|
|
bottomClampWidth = 1008;
|
|
bottomClampHeight = 240;
|
|
break;
|
|
|
|
case 1://tex2
|
|
bottomWidth = 512;
|
|
bottomClampWidth = 320;
|
|
bottomClampHeight = 240;
|
|
break;
|
|
|
|
case 2://tex3
|
|
bottomWidth = 1024;
|
|
bottomClampWidth = 960;
|
|
bottomClampHeight = 240;
|
|
break;
|
|
|
|
}
|
|
break;
|
|
}
|
|
er.BaseStream.Position = header.topScreenTextureOffset;
|
|
topScreenTexture = er.ReadBytes((topHeight * topWidth) * 2);
|
|
er.BaseStream.Position = header.bottomScreenSolidOrTextureOffset;
|
|
bottomScreenTexture = er.ReadBytes((bottomHeight * bottomWidth) * 2);
|
|
|
|
er.BaseStream.Position = header.FolderOpenedTexOffset;
|
|
openFolderTexture = er.ReadBytes((folderWidth * folderHeight) * 4);
|
|
er.BaseStream.Position = header.FolderClosedTexOffset;
|
|
closedFolderTexture = er.ReadBytes((folderWidth * folderHeight) * 4);
|
|
|
|
er.BaseStream.Position = header.iconBorder48pxOffset;
|
|
iconBorder48pxTexture = er.ReadBytes((iconBorder48pxWidth * iconBorder48pxHeight) * 4);
|
|
er.BaseStream.Position = header.iconBorder24pxOffset;
|
|
iconBorder24pxTexture = er.ReadBytes((iconBorder24pxWidth * iconBorder24pxHeight) * 4);
|
|
}
|
|
finally
|
|
{
|
|
er.Close();
|
|
}
|
|
}
|
|
|
|
public string GetSaveDefaultFileFilter()
|
|
{
|
|
return "3DS System Menu Theme (body_LZ.bin)|body_LZ.bin";
|
|
}
|
|
|
|
public byte[] Write()
|
|
{
|
|
MemoryStream m = new MemoryStream();
|
|
EndianBinaryWriter er = new EndianBinaryWriter(m, Endianness.LittleEndian);
|
|
|
|
er.BaseStream.Position = 0xD0;//just after header - normal start of data for theme files
|
|
|
|
header.topScreenTextureOffset = (uint)er.BaseStream.Position;
|
|
er.Write(topScreenTexture, 0, topScreenTexture.Length);
|
|
|
|
header.bottomScreenSolidOrTextureOffset = (uint)er.BaseStream.Position;
|
|
er.Write(bottomScreenTexture, 0, bottomScreenTexture.Length);
|
|
|
|
header.FolderOpenedTexOffset = (uint)er.BaseStream.Position;
|
|
er.Write(openFolderTexture, 0, openFolderTexture.Length);
|
|
|
|
header.FolderClosedTexOffset = (uint)er.BaseStream.Position;
|
|
er.Write(closedFolderTexture, 0, closedFolderTexture.Length);
|
|
|
|
header.iconBorder48pxOffset = (uint)er.BaseStream.Position;
|
|
er.Write(iconBorder48pxTexture, 0, iconBorder48pxTexture.Length);
|
|
|
|
header.iconBorder24pxOffset = (uint)er.BaseStream.Position;
|
|
er.Write(iconBorder24pxTexture, 0, iconBorder24pxTexture.Length);
|
|
|
|
header.Write(er);
|
|
|
|
return m.ToArray();
|
|
}
|
|
|
|
public int iconBorder48pxWidth = 64;
|
|
public int iconBorder48pxHeight = 128;
|
|
public byte[] iconBorder48pxTexture;
|
|
public Bitmap GetIconBorder48px(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(iconBorder48pxTexture, 36, 72, GPU.Textures.ImageFormat.RGB8, false);
|
|
return GPU.Textures.ToBitmap(iconBorder48pxTexture, iconBorder48pxWidth, iconBorder48pxHeight, GPU.Textures.ImageFormat.RGB8, true);
|
|
}
|
|
public int iconBorder24pxWidth = 32;
|
|
public int iconBorder24pxHeight = 64;
|
|
public byte[] iconBorder24pxTexture;
|
|
public Bitmap GetIconBorder24px(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(iconBorder24pxTexture, 25, 50, GPU.Textures.ImageFormat.RGB8, false);
|
|
return GPU.Textures.ToBitmap(iconBorder24pxTexture, iconBorder24pxWidth, iconBorder24pxHeight, GPU.Textures.ImageFormat.RGB8, true);
|
|
}
|
|
|
|
|
|
public int folderWidth = 128;
|
|
public int folderHeight = 64;
|
|
public byte[] openFolderTexture;
|
|
public byte[] closedFolderTexture;
|
|
public Bitmap GetOpenFolderTexture(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(openFolderTexture, 82, 64, GPU.Textures.ImageFormat.RGB8, false);
|
|
return GPU.Textures.ToBitmap(openFolderTexture, folderWidth, folderHeight, GPU.Textures.ImageFormat.RGB8, true);
|
|
}
|
|
public Bitmap GetClosedFolderTexture(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(closedFolderTexture, 74, 64, GPU.Textures.ImageFormat.RGB8, false);
|
|
return GPU.Textures.ToBitmap(closedFolderTexture, folderWidth, folderHeight, GPU.Textures.ImageFormat.RGB8, true);
|
|
}
|
|
|
|
|
|
public int bottomWidth;
|
|
public int bottomHeight;
|
|
public byte[] bottomScreenTexture;
|
|
public int bottomClampWidth;
|
|
public int bottomClampHeight;
|
|
|
|
public Bitmap GetBottomTexture(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(bottomScreenTexture, bottomClampWidth, bottomClampHeight, GPU.Textures.ImageFormat.RGB565, false);
|
|
return GPU.Textures.ToBitmap(bottomScreenTexture, bottomWidth, bottomHeight, GPU.Textures.ImageFormat.RGB565, true);
|
|
}
|
|
|
|
public int topWidth;
|
|
public int topHeight;
|
|
public byte[] topScreenTexture;
|
|
public int topClampWidth;
|
|
public int topClampHeight;
|
|
public Bitmap GetTopTexture(bool clamp)
|
|
{
|
|
if (clamp)
|
|
return GPU.Textures.ToBitmap(topScreenTexture, topClampWidth, topClampHeight, GPU.Textures.ImageFormat.RGB565, false);
|
|
return GPU.Textures.ToBitmap(topScreenTexture, topWidth, topHeight, GPU.Textures.ImageFormat.RGB565, true);
|
|
}
|
|
|
|
public System.Windows.Forms.Form GetDialog()
|
|
{
|
|
return new ThemeViewer(this);
|
|
}
|
|
|
|
public AudioSection audioSection;
|
|
public class AudioSection
|
|
{
|
|
public AudioSection(EndianBinaryReader er)
|
|
{
|
|
|
|
}
|
|
}
|
|
|
|
public ThemeHeader header;
|
|
public class ThemeHeader
|
|
{
|
|
public ThemeHeader(EndianBinaryReader er)
|
|
{
|
|
//offset 0x0
|
|
Version = er.ReadUInt32();
|
|
|
|
Unknown1 = er.ReadByte();
|
|
UseBGMusic = er.ReadByte() == 1;
|
|
Padding = er.ReadBytes(6);
|
|
|
|
//offset 0xC
|
|
topScreenDrawType = er.ReadUInt32();// 0 = none, 1 = solid colour, 2 = extension of val1, 3 = texture
|
|
topScreenFrameType = er.ReadUInt32();//0 = solid colour(only when draw type is 1 else uses tex 0), 1 = texture0, 3 = texture1
|
|
topScreenSolidColorDataOffset = er.ReadUInt32();
|
|
topScreenTextureOffset = er.ReadUInt32();
|
|
topScreenAdditionalTextureOffset = er.ReadUInt32();//used with draw type val2, optional when using draw type val2
|
|
|
|
//offset 0x20
|
|
bottomScreenDrawType = er.ReadUInt32();
|
|
bottomScreenFrameType = er.ReadUInt32();
|
|
bottomScreenSolidOrTextureOffset = er.ReadUInt32();
|
|
|
|
//offset 0x2C
|
|
UseSelectorColor = er.ReadUInt32() == 1;
|
|
SelectorColorBlockOffset = er.ReadUInt32();//0xC length
|
|
|
|
//offset 0x34
|
|
UseFolderColor = er.ReadUInt32() == 1;
|
|
FolderColorBlockOffset = er.ReadUInt32();//0xC length
|
|
|
|
//offset 0x3C
|
|
UseFolderTex = er.ReadUInt32() == 1;
|
|
FolderClosedTexOffset = er.ReadUInt32();//texture 6
|
|
FolderOpenedTexOffset = er.ReadUInt32();//texture 7
|
|
|
|
//offset 0x48
|
|
useUnknownBlock2 = er.ReadUInt32() == 1;
|
|
unknownBlock2Offset = er.ReadUInt32();//0xD length
|
|
|
|
//offset 0x50
|
|
useIconBorders = er.ReadUInt32() == 1;
|
|
iconBorder48pxOffset = er.ReadUInt32();
|
|
iconBorder24pxOffset = er.ReadUInt32();
|
|
|
|
//offset 0x4C
|
|
useUnknownBlock3 = er.ReadUInt32() == 1;
|
|
unknownBlock3Offset = er.ReadUInt32();//0xD length
|
|
|
|
useUnknownBlock4 = er.ReadUInt32() == 1;
|
|
unknownBlock4Offset = er.ReadUInt32();//0x9 length
|
|
|
|
useUnknownBlock5and6 = er.ReadUInt32() == 1;
|
|
unknownBlock5Offset = er.ReadUInt32();//0x20 length
|
|
unknownBlock6Offset = er.ReadUInt32();//0x20 length
|
|
|
|
useUnknownBlock7 = er.ReadUInt32() == 1;
|
|
unknownBlock7Offset = er.ReadUInt32();//0xD length
|
|
|
|
useUnknownBlock8 = er.ReadUInt32() == 1;
|
|
unknownBlock8Offset = er.ReadUInt32();//0xD length
|
|
|
|
useUnknownBlock9 = er.ReadUInt32() == 1;
|
|
unknownBlock9Offset = er.ReadUInt32();//0x9 length
|
|
|
|
useUnknownBlock10 = er.ReadUInt32() == 1;
|
|
unknownBlock10Offset = er.ReadUInt32();//0xD length
|
|
|
|
useUnknownBlock11 = er.ReadUInt32() == 1;
|
|
unknownBlock11Offset = er.ReadUInt32();//0x20 length
|
|
|
|
useUnknownBlock12 = er.ReadUInt32() == 1;
|
|
unknownBlock12Offset = er.ReadUInt32();//0x15 length
|
|
|
|
useUnknownBlock13 = er.ReadUInt32() == 1;
|
|
unknownBlock13Offset = er.ReadUInt32();//0xC length
|
|
|
|
useUnknownBlock14 = er.ReadUInt32() == 1;
|
|
unknownBlock14Offset = er.ReadUInt32();//0x6 length
|
|
|
|
useAudioSection = er.ReadUInt32() == 1;
|
|
audioSectionSize = er.ReadUInt32();
|
|
audioSectionOffset = er.ReadUInt32();
|
|
}
|
|
|
|
public void Write(EndianBinaryWriter er)
|
|
{
|
|
er.BaseStream.Position = 0;
|
|
//write header data
|
|
er.Write(Version);
|
|
|
|
er.Write(Unknown1);
|
|
er.Write((byte)(UseBGMusic ? 1 : 0));
|
|
er.Write(Padding, 0, 6);
|
|
|
|
er.Write(topScreenDrawType);
|
|
er.Write(topScreenFrameType);
|
|
er.Write(topScreenSolidColorDataOffset);
|
|
er.Write(topScreenTextureOffset);
|
|
er.Write(topScreenAdditionalTextureOffset);
|
|
|
|
|
|
er.Write(bottomScreenDrawType);
|
|
er.Write(bottomScreenFrameType);
|
|
er.Write(bottomScreenSolidOrTextureOffset);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write(UseFolderTex ? 1u : 0u);//TODO write 0 instead or somethign when this is disabled?
|
|
er.Write(FolderClosedTexOffset);
|
|
er.Write(FolderOpenedTexOffset);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write(useIconBorders ? 1u : 0u);//TODO write 0 instead or somethign when this is disabled?
|
|
er.Write(iconBorder48pxOffset);
|
|
er.Write(iconBorder24pxOffset);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
er.Write((UInt32)0);
|
|
}
|
|
|
|
public UInt32 Version;
|
|
public Byte Unknown1;
|
|
public bool UseBGMusic;
|
|
public Byte[] Padding;//6
|
|
|
|
public UInt32 topScreenDrawType;
|
|
public UInt32 topScreenFrameType;
|
|
public UInt32 topScreenSolidColorDataOffset;
|
|
public UInt32 topScreenTextureOffset;
|
|
public UInt32 topScreenAdditionalTextureOffset;
|
|
|
|
public UInt32 bottomScreenDrawType;
|
|
public UInt32 bottomScreenFrameType;
|
|
public UInt32 bottomScreenSolidOrTextureOffset;
|
|
|
|
public bool UseSelectorColor;
|
|
public UInt32 SelectorColorBlockOffset;
|
|
|
|
public bool UseFolderColor;
|
|
public UInt32 FolderColorBlockOffset;
|
|
|
|
public bool UseFolderTex;//6 and 7
|
|
public UInt32 FolderClosedTexOffset;
|
|
public UInt32 FolderOpenedTexOffset;
|
|
|
|
public bool useUnknownBlock2;
|
|
public UInt32 unknownBlock2Offset;
|
|
|
|
public bool useIconBorders;
|
|
public UInt32 iconBorder48pxOffset;
|
|
public UInt32 iconBorder24pxOffset;
|
|
|
|
public bool useUnknownBlock3;
|
|
public UInt32 unknownBlock3Offset;
|
|
|
|
public bool useUnknownBlock4;
|
|
public UInt32 unknownBlock4Offset;
|
|
|
|
public bool useUnknownBlock5and6;
|
|
public UInt32 unknownBlock5Offset;
|
|
public UInt32 unknownBlock6Offset;
|
|
|
|
public bool useUnknownBlock7;
|
|
public UInt32 unknownBlock7Offset;
|
|
|
|
public bool useUnknownBlock8;
|
|
public UInt32 unknownBlock8Offset;
|
|
|
|
public bool useUnknownBlock9;
|
|
public UInt32 unknownBlock9Offset;
|
|
|
|
public bool useUnknownBlock10;
|
|
public UInt32 unknownBlock10Offset;
|
|
|
|
public bool useUnknownBlock11;
|
|
public UInt32 unknownBlock11Offset;
|
|
|
|
public bool useUnknownBlock12;
|
|
public UInt32 unknownBlock12Offset;
|
|
|
|
public bool useUnknownBlock13;
|
|
public UInt32 unknownBlock13Offset;
|
|
|
|
public bool useUnknownBlock14;
|
|
public UInt32 unknownBlock14Offset;
|
|
|
|
|
|
public Boolean useAudioSection;
|
|
public UInt32 audioSectionSize;
|
|
public UInt32 audioSectionOffset;
|
|
}
|
|
|
|
public class ThemeIdentifier : FileFormatIdentifier
|
|
{
|
|
public override string GetCategory()
|
|
{
|
|
return "3DS Themes";
|
|
}
|
|
|
|
public override string GetFileDescription()
|
|
{
|
|
return "3DS System Menu Theme (body_LZ.bin)";
|
|
}
|
|
|
|
public override string GetFileFilter()
|
|
{
|
|
return "3DS System Menu Theme (body_LZ.bin)|body_LZ.bin";
|
|
}
|
|
|
|
public override Bitmap GetIcon()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
public override FormatMatch IsFormat(EFEFile File)
|
|
{
|
|
if (File.Name.Equals("body_LZ.bin"))
|
|
return FormatMatch.Content;
|
|
else
|
|
return FormatMatch.No;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|