Files
GradientTool/HDMA/Generator2.cs

501 lines
17 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Decompiled with JetBrains decompiler
// Type: SFXProductions.GradientTool.HDMA.Generator2
// Assembly: GradientTool, Version=0.8.2.1, Culture=neutral, PublicKeyToken=null
// MVID: 818AB9B3-796A-4A49-8B90-C00D066A321B
// Assembly location: C:\Users\aless\Downloads\gradient-tool-v0.8.2.1\GradientTool.exe
using System;
using System.Collections.Generic;
#nullable disable
namespace SFXProductions.GradientTool.HDMA;
internal static class Generator2
{
private const int c_col2 = 5;
private const int REG_43x0 = 17152;
private const int REG_43x2 = 17154;
private const int REG_43x4 = 17156;
private const string c_defaultName = "Gradient";
private static ushort ApplyChannelFlag(int n, ChannelType flag)
{
return (ushort) ((ChannelType) n | flag);
}
private static ushort GetNormalModeDataValue(double r, double g, double b, ChannelType channels)
{
int num1 = 0;
double num2 = 0.0;
bool flag;
if ((flag = channels == ChannelType.Brightness) || channels == ChannelType.Grey)
{
num2 = r + g + b;
num1 = 3;
}
else
{
if ((channels & ChannelType.Red) == ChannelType.Red)
{
num2 += r;
++num1;
}
if ((channels & ChannelType.Green) == ChannelType.Green)
{
num2 += g;
++num1;
}
if ((channels & ChannelType.Blue) == ChannelType.Blue)
{
num2 += b;
++num1;
}
}
return Generator2.ApplyChannelFlag(Generator2.GetV5(num2 / (double) num1, flag ? 15 : 31 /*0x1F*/), channels);
}
private static int GetV5(double v, int range = 31 /*0x1F*/)
{
return (int) (v.Clamp() * (double) range + 0.5);
}
private static ushort GetRGBChannelValue(double r, double g, double b)
{
return (ushort) (Generator2.GetV5(r) | Generator2.GetV5(g) << 5 | Generator2.GetV5(b) << 10);
}
internal static void CreateMode0Table(
double[] chR,
double[] chG,
double[] chB,
ChannelType channels,
DataPoint[] result)
{
for (int index = 0; index < result.Length; ++index)
result[index] = new DataPoint()
{
Data1 = Generator2.GetNormalModeDataValue(chR[index], chG[index], chB[index], channels)
};
}
internal static void CreateMode2Table(
double[] chR,
double[] chG,
double[] chB,
ChannelType ch1,
ChannelType ch2,
DataPoint[] result)
{
for (int index = 0; index < result.Length; ++index)
{
double r = chR[index];
double g = chG[index];
double b = chB[index];
result[index] = new DataPoint()
{
Data1 = Generator2.GetNormalModeDataValue(r, g, b, ch1),
Data2 = Generator2.GetNormalModeDataValue(r, g, b, ch2)
};
}
}
internal static void CreateScrollingTable(
double[] chR,
double[] chG,
double[] chB,
DataPoint[] result)
{
for (int index = 0; index < result.Length; ++index)
{
double v1 = chR[index];
double v2 = chG[index];
double v3 = chB[index];
result[index] = new DataPoint()
{
Data1 = Generator2.ApplyChannelFlag(Generator2.GetV5(v1), ChannelType.Red),
Data2 = Generator2.ApplyChannelFlag(Generator2.GetV5(v2), ChannelType.Green),
Data3 = Generator2.ApplyChannelFlag(Generator2.GetV5(v3), ChannelType.Blue)
};
}
}
internal static void CreateMode1Table(
double[] chR,
double[] chG,
double[] chB,
ushort paletteIndex,
DataPoint[] result)
{
for (int index = 0; index < result.Length; ++index)
{
double r = chR[index];
double g = chG[index];
double b = chB[index];
result[index] = new DataPoint()
{
Data1 = paletteIndex,
Data2 = Generator2.GetRGBChannelValue(r, g, b)
};
}
}
private static void DoNormalMode(
ref int srcI,
DataPoint[] src,
List<CompressedDataPoint> dst,
bool allowCountAbove128)
{
DataPoint dataPoint = src[srcI];
CompressedDataPoint compressedDataPoint = new CompressedDataPoint(dataPoint);
for (int index = srcI + 1; index < src.Length && src[index] == dataPoint && (allowCountAbove128 && compressedDataPoint.Count < (int) byte.MaxValue || compressedDataPoint.Count < 128 /*0x80*/); ++index)
++compressedDataPoint.Count;
dst.Add(compressedDataPoint);
srcI += compressedDataPoint.Count;
}
private static bool CheckForContinuousMode(
ref int srcI,
DataPoint[] src,
List<CompressedDataPoint> dst)
{
if (srcI + 2 >= src.Length || !(src[srcI] != src[srcI + 1]) || srcI + 3 >= src.Length || !(src[srcI + 1] != src[srcI + 2]))
return false;
CompressedDataPoint compressedDataPoint = new CompressedDataPoint(src[srcI]);
for (int index = srcI + 1; compressedDataPoint.Data.Count < (int) sbyte.MaxValue && index < src.Length; ++index)
{
DataPoint dataPoint = src[index];
if (index + 2 >= src.Length || dataPoint != src[index + 1])
compressedDataPoint.Data.Add(dataPoint);
else
break;
}
dst.Add(compressedDataPoint);
srcI += compressedDataPoint.Data.Count;
return true;
}
private static List<CompressedDataPoint> CompressTable(
DataPoint[] dataPoints,
bool canUseContinuousMode)
{
List<CompressedDataPoint> dst = new List<CompressedDataPoint>();
int srcI = 0;
while (srcI < dataPoints.Length)
{
if (!canUseContinuousMode || !Generator2.CheckForContinuousMode(ref srcI, dataPoints, dst))
Generator2.DoNormalMode(ref srcI, dataPoints, dst, false);
}
return dst;
}
internal static int GetNChannels(GradientChannels channels)
{
switch (channels)
{
case GradientChannels.RedGreenBlue:
return 3;
case GradientChannels.RedGreen:
case GradientChannels.GreenBlue:
case GradientChannels.RedBlue:
case GradientChannels.CyanRed:
case GradientChannels.YellowBlue:
case GradientChannels.MagentaGreen:
return 2;
case GradientChannels.Red:
case GradientChannels.Green:
case GradientChannels.Blue:
case GradientChannels.Cyan:
case GradientChannels.Yellow:
case GradientChannels.Magenta:
case GradientChannels.Grey:
case GradientChannels.Brightness:
return 1;
default:
throw new ArgumentException("Invalid channels.");
}
}
internal static ChannelType GetChannel(GradientChannels channels, int index)
{
switch (channels)
{
case GradientChannels.RedGreenBlue:
if (index == 0)
return ChannelType.Red;
return index != 1 ? ChannelType.Blue : ChannelType.Green;
case GradientChannels.RedGreen:
return index != 0 ? ChannelType.Green : ChannelType.Red;
case GradientChannels.GreenBlue:
return index != 0 ? ChannelType.Blue : ChannelType.Green;
case GradientChannels.RedBlue:
return index != 0 ? ChannelType.Blue : ChannelType.Red;
case GradientChannels.CyanRed:
return index != 0 ? ChannelType.Red : ChannelType.Cyan;
case GradientChannels.YellowBlue:
return index != 0 ? ChannelType.Blue : ChannelType.Yellow;
case GradientChannels.MagentaGreen:
return index != 0 ? ChannelType.Green : ChannelType.Magenta;
case GradientChannels.Red:
return ChannelType.Red;
case GradientChannels.Green:
return ChannelType.Green;
case GradientChannels.Blue:
return ChannelType.Blue;
case GradientChannels.Cyan:
return ChannelType.Cyan;
case GradientChannels.Yellow:
return ChannelType.Yellow;
case GradientChannels.Magenta:
return ChannelType.Magenta;
case GradientChannels.Grey:
return ChannelType.Grey;
case GradientChannels.Brightness:
return ChannelType.Brightness;
default:
throw new ArgumentException("Invalid channels.");
}
}
public static void GenerateCode(
double[] rBuffer,
double[] gBuffer,
double[] bBuffer,
Settings2 settings,
CodeGen code)
{
uint size = 0;
List<CompressedDataPoint> outTable1 = (List<CompressedDataPoint>) null;
List<CompressedDataPoint> outTable2 = (List<CompressedDataPoint>) null;
List<CompressedDataPoint> outTable3 = (List<CompressedDataPoint>) null;
DataPoint[] tmpBuffer = new DataPoint[rBuffer.Length];
Generator2.DoChan(settings.Channel1, rBuffer, gBuffer, bBuffer, tmpBuffer, ref size, ref outTable1);
Generator2.DoChan(settings.Channel2, rBuffer, gBuffer, bBuffer, tmpBuffer, ref size, ref outTable2);
Generator2.DoChan(settings.Channel3, rBuffer, gBuffer, bBuffer, tmpBuffer, ref size, ref outTable3);
code.WriteBanner();
code.WriteComment(settings.GetGradientTypeBanner());
code.WriteComment("Channels: " + GradientChannelsHelper.GetChannelString(settings.Channels));
code.WriteComment("Table Size: " + size.ToString("N0"));
code.WriteComment("No. of Writes: " + rBuffer.Length.ToString("N0"));
code.WriteComment();
code.WriteComment("Generated by GradientTool");
code.WriteBanner();
Generator2.WriteActivator(settings, code);
string gradientName = settings.Name ?? "Gradient";
Generator2.WriteChan(settings.Channel1, outTable1, code, gradientName);
Generator2.WriteChan(settings.Channel2, outTable2, code, gradientName);
Generator2.WriteChan(settings.Channel3, outTable3, code, gradientName);
}
private static void DoChan(
Channel chan,
double[] rBuffer,
double[] gBuffer,
double[] bBuffer,
DataPoint[] tmpBuffer,
ref uint size,
ref List<CompressedDataPoint> outTable)
{
if (chan == null)
return;
chan.GetRawData(rBuffer, gBuffer, bBuffer, tmpBuffer);
outTable = Generator2.CompressTable(tmpBuffer, chan.CanUseContinuousMode);
size += chan.CalculateTableSize((IList<CompressedDataPoint>) outTable) + 1U;
}
private static void WriteChan(
Channel chan,
List<CompressedDataPoint> table,
CodeGen code,
string gradientName)
{
if (chan == null)
return;
code.AppendLine();
chan.WriteData((IList<CompressedDataPoint>) table, code, gradientName);
}
private static void WriteActivator(Settings2 settings, CodeGen code)
{
if (!settings.GenerateInitializationCode)
return;
code.AppendLine();
if (settings.Channel1 is CombinedChannel)
{
code.WriteComment("GradientTool doesnt generate the code");
code.WriteComment("to initialize scrolling gradients.");
code.WriteComment();
code.WriteComment("See the ASM files in the folder titled");
code.WriteComment("Example, located in the same folder as");
code.WriteComment("GradientTool.");
}
else if (settings.Channel1 is Mode3Channel)
Generator2.WriteActivatorInternal(settings, (ushort) 8451, (ushort) 8451, (ushort) 8451, code);
else if (settings.Channel1 is Mode0Channel)
{
ushort num = settings.Channels != GradientChannels.Brightness ? (ushort) 12800 : (ushort) 0;
Generator2.WriteActivatorInternal(settings, num, num, num, code);
}
else if (settings.Channel1 is Mode2Channel)
{
Generator2.WriteActivatorInternal(settings, (ushort) 12802, (ushort) 12800, (ushort) 12800, code);
}
else
{
code.WriteComment("Something went wrong and the type of");
code.WriteComment("HDMA gradient being generated couldnt");
code.WriteComment("be determined.");
}
}
private static void WriteActivatorInternal(
Settings2 settings,
ushort transferMode0,
ushort transferMode1,
ushort transferMode2,
CodeGen code)
{
string chans = Generator2.GetChans(settings);
code.WriteComment("Set up the HDMA gradient.");
code.WriteComment($"Uses HDMA {chans}{(object) '.'}");
code.AppendLabel("Init" + (settings.Name ?? "Gradient"));
code.AppendPlainText(':');
code.AppendLine();
code.Write16BitMode(5);
code.AppendLine();
code.WriteComment("Set transfer modes.", (true ? 1 : 0) != 0);
code.WriteLDAIfNonzero(transferMode0, 5);
CodeGen codeGen1 = code;
int num1 = 5;
string chanStr1 = Generator2.GetChanStr(settings.Channel1);
int register1 = (int) Generator2.GetRegister(17152, settings.Channel1);
int num2 = (int) transferMode0;
int w1 = num1;
string comment1 = chanStr1;
codeGen1.WriteSTAIfNonzero((ushort) register1, (ushort) num2, w1, comment1);
if (settings.Channel2 != null)
{
if ((int) transferMode1 != (int) transferMode0)
{
CodeGen codeGen2 = code;
int num3 = 5;
int num4 = (int) transferMode1;
int w2 = num3;
codeGen2.WriteLDAIfNonzero((ushort) num4, w2);
}
CodeGen codeGen3 = code;
int num5 = 5;
string chanStr2 = Generator2.GetChanStr(settings.Channel2);
int register2 = (int) Generator2.GetRegister(17152, settings.Channel2);
int num6 = (int) transferMode1;
int w3 = num5;
string comment2 = chanStr2;
codeGen3.WriteSTAIfNonzero((ushort) register2, (ushort) num6, w3, comment2);
if (settings.Channel3 != null)
{
if ((int) transferMode2 != (int) transferMode1)
{
CodeGen codeGen4 = code;
int num7 = 5;
int num8 = (int) transferMode2;
int w4 = num7;
codeGen4.WriteLDAIfNonzero((ushort) num8, w4);
}
CodeGen codeGen5 = code;
int num9 = 5;
string chanStr3 = Generator2.GetChanStr(settings.Channel3);
int register3 = (int) Generator2.GetRegister(17152, settings.Channel3);
int num10 = (int) transferMode2;
int w5 = num9;
string comment3 = chanStr3;
codeGen5.WriteSTAIfNonzero((ushort) register3, (ushort) num10, w5, comment3);
}
}
code.AppendLine();
code.WriteComment("Point to HDMA tables.", (true ? 1 : 0) != 0);
Generator2.WriteChanSourceLoader(settings.Channel1, settings.Name, code);
Generator2.WriteChanSourceLoader(settings.Channel2, settings.Name, code);
Generator2.WriteChanSourceLoader(settings.Channel3, settings.Name, code);
code.AppendLine();
code.Write8BitMode(5);
code.AppendLine();
code.WriteComment("Store program bank to $43x4.", (true ? 1 : 0) != 0);
code.WriteKeywordLine("PHK");
code.WriteKeywordLine("PLA");
Generator2.WriteChanBankLoader(settings.Channel1, code);
Generator2.WriteChanBankLoader(settings.Channel2, code);
Generator2.WriteChanBankLoader(settings.Channel3, code);
code.AppendLine();
CodeGen codeGen6 = code;
bool flag = true;
string comment4 = $"Enable {chans}{(object) '.'}";
int num11 = flag ? 1 : 0;
codeGen6.WriteComment(comment4, num11 != 0);
code.WriteLDA_b_c_bin(Generator2.GetHDMAFlags(settings), 5);
code.WriteTSB((ushort) 3487, 5);
code.AppendLine();
code.AppendHardTab();
code.AppendKeyword("RTS");
code.WriteComment("<-- Can also be RTL.", space: (true ? 1 : 0) != 0);
code.AppendLine();
code.AppendComment("; --- HDMA Tables below this line ---");
}
private static string GetChans(Settings2 settings)
{
if (settings.Channel2 == null)
return "channel " + settings.Channel1.HDMAChannel.ToString();
return settings.Channel3 != null ? $"channels {settings.Channel1.HDMAChannel}, {settings.Channel2.HDMAChannel}, and {settings.Channel3.HDMAChannel}" : $"channels {settings.Channel1.HDMAChannel} and {settings.Channel2.HDMAChannel}";
}
private static string GetChanStr(Channel channel) => "Channel " + channel.HDMAChannel.ToString();
private static ushort GetRegister(int reg, int channel) => (ushort) (reg | (channel & 7) << 4);
private static ushort GetRegister(int reg, Channel channel)
{
return (ushort) (reg | (channel.HDMAChannel & 7) << 4);
}
private static byte GetHDMAFlags(Settings2 settings)
{
int hdmaFlags = 1 << (settings.Channel1.HDMAChannel & 7);
if (settings.Channel2 != null)
{
hdmaFlags |= 1 << (settings.Channel2.HDMAChannel & 7);
if (settings.Channel3 != null)
hdmaFlags |= 1 << (settings.Channel3.HDMAChannel & 7);
}
return (byte) hdmaFlags;
}
private static void WriteChanSourceLoader(Channel channel, string gradientName, CodeGen code)
{
if (channel == null)
return;
string channelLabel = channel.GetChannelLabel(gradientName ?? "Gradient");
CodeGen codeGen1 = code;
int num1 = 5;
string label = channelLabel;
int w1 = num1;
codeGen1.WriteLDA_Label(label, w1);
CodeGen codeGen2 = code;
int num2 = 5;
int register = (int) Generator2.GetRegister(17154, channel);
int w2 = num2;
codeGen2.WriteSTA((ushort) register, w2);
}
private static void WriteChanBankLoader(Channel channel, CodeGen code)
{
if (channel == null)
return;
CodeGen codeGen = code;
int num = 5;
string chanStr = Generator2.GetChanStr(channel);
int register = (int) Generator2.GetRegister(17156, channel);
int w = num;
string comment = chanStr;
codeGen.WriteSTA((ushort) register, w, comment);
}
}