Skip to content

Commit

Permalink
Set up logic to read some textures for SM64 DS.
Browse files Browse the repository at this point in the history
  • Loading branch information
MeltyPlayer committed Dec 22, 2024
1 parent 759daa0 commit 7804b37
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using fin.animation.keyframes;
using System.Drawing;

using fin.animation.keyframes;
using fin.compression;
using fin.data.dictionaries;
using fin.data.lazy;
using fin.data.queues;
using fin.image;
using fin.io;
using fin.math.transform;
using fin.model;
Expand Down Expand Up @@ -78,6 +82,33 @@ var firstChild
}
}

// Set up materials
var finMaterialManager = model.MaterialManager;
var lazyTextureDictionary
= new LazyDictionary<(Texture texture, Palette? palette), ITexture>(
textureAndPalette => {
var (sm64Texture, sm64Palette) = textureAndPalette;

var finTexture
= finMaterialManager.CreateTexture(
ImageReader.ReadImage(sm64Texture, sm64Palette));
finTexture.Name = sm64Texture.Name;

return finTexture;
});

foreach (var sm64Material in bmd.Materials) {
var textureId = sm64Material.TextureId;
var paletteId = sm64Material.TexturePaletteId;

if (textureId != -1) {
var sm64Texture = bmd.Textures[textureId];
var sm64Palette = paletteId != -1 ? bmd.Palettes[paletteId] : null;

var finTexture = lazyTextureDictionary[(sm64Texture, sm64Palette)];
}
}

// Set up mesh
{ }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ public partial class Bmd : IBinaryConvertible {
[RSequenceLengthSource(nameof(TextureCount))]
public Texture[] Textures { get; set; }

[RAtPosition(nameof(TexturePalettesOffset))]
[RSequenceLengthSource(nameof(TexturePaletteCount))]
public Palette[] Palettes { get; set; }

[RAtPosition(nameof(MaterialsOffset))]
[RSequenceLengthSource(nameof(MaterialCount))]
public Material[] Materials { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using System.Drawing;

using fin.image;
using fin.image.formats;
using fin.util.asserts;
using fin.util.color;

using schema.binary;

using SixLabors.ImageSharp.PixelFormats;

namespace sm64ds.schema.bmd;

/// <summary>
/// Shamelessly stolen from:
/// https://github.com/Arisotura/SM64DSe/blob/master/SM64DSFormats/BMD.NitroTexture.cs
/// </summary>
public class ImageReader {
public static IImage ReadImage(Texture texture, Palette? palette) {
switch (texture.TextureType) {
case TextureType.A3_I5: break;
case TextureType.PALETTE_4:
return ReadPalette4_(texture, palette.AssertNonnull());
case TextureType.PALETTE_16:
return ReadPalette16_(texture, palette.AssertNonnull());
case TextureType.PALETTE_256:
return ReadPalette256_(texture, palette.AssertNonnull());
case TextureType.TEX_4X4: break;
case TextureType.A5_I3: break;
case TextureType.DIRECT: break;
default: throw new ArgumentOutOfRangeException();
}

return FinImage.Create1x1FromColor(Color.Red);
}

private static IImage ReadPalette4_(Texture texture, Palette palette) {
var paletteColors = GetPaletteColors_(texture, palette);

var image = new Rgba32Image(texture.Width, texture.Height);
var fastLock = image.Lock();
var dst = fastLock.Pixels;
var dstI = 0;

using var textureBr = new SchemaBinaryReader(texture.Data);
while (!textureBr.Eof) {
var texel = textureBr.ReadByte();

for (var i = 0; i < 4; ++i) {
var subTexel = (texel >> (2 * i)) & 0x3;
dst[dstI++] = paletteColors[subTexel];
}
}

return image;
}

private static IImage ReadPalette16_(Texture texture, Palette palette) {
var paletteColors = GetPaletteColors_(texture, palette);

var image = new Rgba32Image(texture.Width, texture.Height);
var fastLock = image.Lock();
var dst = fastLock.Pixels;
var dstI = 0;

using var textureBr = new SchemaBinaryReader(texture.Data);
while (!textureBr.Eof) {
var texel = textureBr.ReadByte();

for (var i = 0; i < 2; ++i) {
var subTexel = (texel >> (4 * i)) & 0xF;
dst[dstI++] = paletteColors[subTexel];
}
}

return image;
}

private static IImage ReadPalette256_(Texture texture, Palette palette) {
var paletteColors = GetPaletteColors_(texture, palette);

var image = new Rgba32Image(texture.Width, texture.Height);
var fastLock = image.Lock();
var dst = fastLock.Pixels;
var dstI = 0;

using var textureBr = new SchemaBinaryReader(texture.Data);
while (!textureBr.Eof) {
var texel = textureBr.ReadByte();
dst[dstI++] = paletteColors[texel];
}

return image;
}

/*private static IImage ReadTex4x4_(Texture texture, Palette palette) {
var paletteColors = GetPaletteColors_(texture, palette);
int yOut = 0, xOut = 0;
var width = texture.Width;
var image = new Rgba32Image(width, texture.Height);
var fastLock = image.Lock();
var dst = fastLock.Pixels;
using var textureBr = new SchemaBinaryReader(texture.Data);
while (!textureBr.Eof) {
uint blox = Helper.BytesToUInt32(tex, _in);
ushort palidx_data = texture.
= Helper.BytesToUShort16(tex, m_TextureDataLength + (_in >> 1));
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
byte texel = (byte) (blox & 0x3);
blox >>= 2;
int pal_offset = (int) ((palidx_data & 0x3FFF) << 2);
ushort color_mode = (ushort) (palidx_data >> 14);
uint color = 0xFFFFFFFF;
switch (texel) {
case 0: color = Helper.BytesToUShort16(pal, pal_offset, 0); break;
case 1:
color = Helper.BytesToUShort16(pal, pal_offset + 2, 0); break;
case 2: {
switch (color_mode) {
case 0:
case 2:
color = Helper.BytesToUShort16(pal, pal_offset + 4, 0); break;
case 1: {
ushort c0 = Helper.BytesToUShort16(pal, pal_offset, 0);
ushort c1 = Helper.BytesToUShort16(pal, pal_offset + 2, 0);
color = Helper.BlendColorsBGR15(c0, 1, c1, 1);
}
break;
case 3: {
ushort c0 = Helper.BytesToUShort16(pal, pal_offset, 0);
ushort c1 = Helper.BytesToUShort16(pal, pal_offset + 2, 0);
color = Helper.BlendColorsBGR15(c0, 5, c1, 3);
}
break;
}
}
break;
case 3: {
switch (color_mode) {
case 0:
case 1: color = 0xFFFFFFFF; break;
case 2:
color = Helper.BytesToUShort16(pal, pal_offset + 6, 0); break;
case 3: {
ushort c0 = Helper.BytesToUShort16(pal, pal_offset, 0);
ushort c1 = Helper.BytesToUShort16(pal, pal_offset + 2, 0);
color = Helper.BlendColorsBGR15(c0, 3, c1, 5);
}
break;
}
}
break;
}
int _out = (int) (((y * width) + x) * 4);
int yoff = (int) (y * width * 4);
int xoff = (int) (x * 4);
var dstI = _out + yoff + xoff;
if (color == 0xFFFFFFFF) {
dst[dstI] = default;
} else {
dst[dstI] = ;
byte red = (byte) ((color & 0x001F) << 3);
byte green = (byte) ((color & 0x03E0) >> 2);
byte blue = (byte) ((color & 0x7C00) >> 7);
m_ARGB[_out + yoff + xoff] = blue;
m_ARGB[_out + yoff + xoff + 1] = green;
m_ARGB[_out + yoff + xoff + 2] = red;
m_ARGB[_out + yoff + xoff + 3] = 0xFF;
}
}
}
xOut += 4;
if (xOut >= width) {
xOut = 0;
yOut += 4;
}
}
return image;
}*/

// TODO: Optimize this to use stackalloc instead
public static Rgba32[] GetPaletteColors_(Texture texture, Palette palette) {
using var paletteBr = new SchemaBinaryReader(palette.Data);

var paletteColors = new Rgba32[palette.Data.Length >> 1];
for (var i = 0; i < paletteColors.Length; ++i) {
ColorUtil.SplitRgb5A1(paletteBr.ReadUInt16(),
out var b,
out var g,
out var r,
out _);
var a = (byte) (texture.UseTransparentColor0 && i == 0 ? 0 : 0xFF);

paletteColors[i] = new Rgba32(r, g, b, a);
}

return paletteColors;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ public partial class Material : IBinaryConvertible {
[RAtPosition(nameof(nameOffset_))]
public string Name { get; set; }

public uint TextureId { get; set; }
public uint TexturePaletteId { get; set; }
public int TextureId { get; set; }
public int TexturePaletteId { get; set; }

public FixedPointVector2 TextureScale { get; set; }
public uint TextureRotation { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using fin.schema;

using schema.binary;
using schema.binary.attributes;

namespace sm64ds.schema.bmd;

/// <summary>
/// Shamelessly stolen from:
/// https://kuribo64.net/get.php?id=KBNyhM0kmNiuUBb3
/// </summary>
[BinarySchema]
public partial class Palette : IBinaryConvertible {
private uint nameOffset_;

[NullTerminatedString]
[RAtPosition(nameof(nameOffset_))]
public string Name { get; set; }

private uint dataOffset_;
private uint dataLength_;

[RAtPosition(nameof(dataOffset_))]
[RSequenceLengthSource(nameof(dataLength_))]
public byte[] Data { get; set; }

[Unknown]
public uint Unknown { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
using schema.binary;
using fin.math;

using schema.binary;
using schema.binary.attributes;

namespace sm64ds.schema.bmd;

public enum TextureType {
A3_I5 = 1,
PALETTE_4 = 2,
PALETTE_16 = 3,
PALETTE_256 = 4,
TEX_4X4 = 5,
A5_I3 = 6,
DIRECT = 7
}

/// <summary>
/// Shamelessly stolen from:
/// https://kuribo64.net/get.php?id=KBNyhM0kmNiuUBb3
Expand All @@ -26,4 +38,11 @@ public partial class Texture : IBinaryConvertible {
public ushort Height { get; set; }

public uint Parameters { get; set; }

[Skip]
public TextureType TextureType
=> (TextureType) this.Parameters.ExtractFromRight(26, 3);

[Skip]
public bool UseTransparentColor0 => this.Parameters.GetBit(29);
}

0 comments on commit 7804b37

Please sign in to comment.