hostile-takeover/SpiffLib/tbitmapsr.cs
2014-07-06 17:47:28 -07:00

1888 lines
50 KiB
C#

using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
namespace SpiffLib {
class TBitmapSR {
enum Op {
EvenData1, // 0
EvenData1_Inc, // 1
EvenData2, // 2
EvenData2_Inc, // 3
EvenData3, // 4
EvenData3_Inc, // 5
EvenData4, // 6
EvenData4_Inc, // 7
EvenData5, // 8
EvenData5_Inc, // 9
EvenData6, // 10
EvenData6_Inc, // 11
EvenData7, // 12
EvenData7_Inc, // 13
EvenData8, // 14
EvenData8_Inc, // 15
EvenData9, // 16
EvenData9_Inc, // 17
EvenData10, // 18
EvenData10_Inc, // 19
EvenData11, // 20
EvenData11_Inc, // 21
EvenData12, // 22
EvenData12_Inc, // 23
EvenData13, // 24
EvenData13_Inc, // 25
EvenData14, // 26
EvenData14_Inc, // 27
EvenData15, // 28
EvenData15_Inc, // 29
EvenData16, // 30
EvenData16_Inc, // 31
EvenData17, // 32
EvenData17_Inc, // 33
EvenData18, // 34
EvenData18_Inc, // 35
EvenData19, // 36
EvenData19_Inc, // 37
EvenData20, // 38
EvenData20_Inc, // 39
EvenData21, // 40
EvenData21_Inc, // 41
EvenData22, // 42
EvenData22_Inc, // 43
EvenData23, // 44
EvenData23_Inc, // 45
EvenData24, // 46
EvenData24_Inc, // 47
EvenData25, // 48
EvenData25_Inc, // 49
EvenData26, // 50
EvenData26_Inc, // 51
EvenData27, // 52
EvenData27_Inc, // 53
EvenData28, // 54
EvenData28_Inc, // 55
EvenData29, // 56
EvenData29_Inc, // 57
EvenData30, // 58
EvenData30_Inc, // 59
EvenData31, // 60
EvenData31_Inc, // 61
EvenData32, // 62
EvenData32_Inc, // 63
OddData1, // 64
OddData1_Inc, // 65
OddData2, // 66
OddData2_Inc, // 67
OddData3, // 68
OddData3_Inc, // 69
OddData4, // 70
OddData4_Inc, // 71
OddData5, // 72
OddData5_Inc, // 73
OddData6, // 74
OddData6_Inc, // 75
OddData7, // 76
OddData7_Inc, // 77
OddData8, // 78
OddData8_Inc, // 79
OddData9, // 80
OddData9_Inc, // 81
OddData10, // 82
OddData10_Inc, // 83
OddData11, // 84
OddData11_Inc, // 85
OddData12, // 86
OddData12_Inc, // 87
OddData13, // 88
OddData13_Inc, // 89
OddData14, // 90
OddData14_Inc, // 91
OddData15, // 92
OddData15_Inc, // 93
OddData16, // 94
OddData16_Inc, // 95
OddData17, // 96
OddData17_Inc, // 97
OddData18, // 98
OddData18_Inc, // 99
OddData19, // 100
OddData19_Inc, // 101
OddData20, // 102
OddData20_Inc, // 103
OddData21, // 104
OddData21_Inc, // 105
OddData22, // 106
OddData22_Inc, // 107
OddData23, // 108
OddData23_Inc, // 109
OddData24, // 110
OddData24_Inc, // 111
OddData25, // 112
OddData25_Inc, // 113
OddData26, // 114
OddData26_Inc, // 115
OddData27, // 116
OddData27_Inc, // 117
OddData28, // 118
OddData28_Inc, // 119
OddData29, // 120
OddData29_Inc, // 121
OddData30, // 122
OddData30_Inc, // 123
OddData31, // 124
OddData31_Inc, // 125
OddData32, // 126
OddData32_Inc, // 127
Side1, // 128
Side2, // 129
Side3, // 130
Side4, // 131
Side5, // 132
Side6, // 133
Side7, // 134
Side8, // 135
Side9, // 136
Side10, // 137
Side11, // 138
Side12, // 139
Side13, // 140
Side14, // 141
Side15, // 142
Side16, // 143
Side17, // 144
Side18, // 145
Side19, // 146
Side20, // 147
Side21, // 148
Side22, // 149
Side23, // 150
Side24, // 151
Side25, // 152
Side26, // 153
Side27, // 154
Side28, // 155
Side29, // 156
Side30, // 157
Side31, // 158
Side32, // 159
Shadow1, // 160
Shadow2, // 161
Shadow3, // 162
Shadow4, // 163
Shadow5, // 164
Shadow6, // 165
Shadow7, // 166
Shadow8, // 167
Shadow9, // 168
Shadow10, // 169
Shadow11, // 170
Shadow12, // 171
Shadow13, // 172
Shadow14, // 173
Shadow15, // 174
Shadow16, // 175
Shadow17, // 176
Shadow18, // 177
Shadow19, // 178
Shadow20, // 179
Shadow21, // 180
Shadow22, // 181
Shadow23, // 182
Shadow24, // 183
Shadow25, // 184
Shadow26, // 185
Shadow27, // 186
Shadow28, // 187
Shadow29, // 188
Shadow30, // 189
Shadow31, // 190
Shadow32, // 191
EvenDataLB, // 192
EvenDataLB_Inc, // 193
EvenDataLW, // 194
EvenDataLW_Inc, // 195
EvenDataLWB, // 196
EvenDataLWB_Inc, // 197
EvenDataL, // 198
EvenDataL_Inc, // 199
OddDataLB, // 200
OddDataLB_Inc, // 201
OddDataLW, // 202
OddDataLW_Inc, // 203
OddDataLWB, // 204
OddDataLWB_Inc, // 205
OddDataL, // 206
OddDataL_Inc, // 207
SideN, // 208
ShadowN, // 209
TransparentN, // 210
EndScan, // 211
Error, // 212
EvenDataStart = 0,
EvenDataEnd = 63,
OddDataStart = 64,
OddDataEnd = 127,
SideStart = 128,
SideEnd = 159,
ShadowStart = 160,
ShadowEnd = 191,
EvenDataNStart = 192,
EvenDataNEnd = 199,
OddDataNStart = 200,
OddDataNEnd = 207
};
enum OpType { None, Data, Side, Shadow, Transparent };
struct Frame {
public ArrayList alsArunsEven;
public ArrayList alsArunsOdd;
}
struct Run {
public int cp;
public ColorType ct;
public Align align;
public int[] aiclr;
public bool fNeedSrcAlign;
}
struct RunArgs {
public Op op;
public int cpSrc;
public int cpArgs;
public int cpDst;
}
class CompileResults {
public ArrayList alsIclr;
public ArrayList alsRa;
public int[,] aaiiclrEven;
public int[,] aairaEven;
public int[,] aaiiclrOdd;
public int[,] aairaOdd;
}
int m_cx;
int m_cy;
Palette m_pal;
ArrayList m_alsFrames = new ArrayList();
CompileResults m_crLast;
static Color m_clrShadow = Color.FromArgb(156, 212, 248);
static Color m_clrTransparent = Color.FromArgb(255, 0, 255);
static int s_iclrShadow = -1;
static int s_iclrTransparent = -2;
static int s_iclrNotAssigned = -3;
static int s_iclrSideFirst = 16;
static int s_iclrSideLast = 20;
static int s_cpSideOpFixedMax = 32;
static int s_cpShadowOpFixedMax = 32;
static int s_cpDataOpFixedMax = 32;
static Op[] s_mpcpTrailingOpDataEven = { Op.EvenDataL, Op.EvenDataLB, Op.EvenDataLW, Op.EvenDataLWB };
static Op[] s_mpcpTrailingOpDataOdd = { Op.OddDataL, Op.OddDataLB, Op.OddDataLW, Op.OddDataLWB };
public TBitmapSR(Palette pal) {
m_cx = -1;
m_cy = -1;
m_pal = pal;
}
public void Dispose() {
}
public void AddFrame(Bitmap bm) {
if (m_cx == -1) {
m_cx = bm.Width;
m_cy = bm.Height;
}
if (m_cx != bm.Width || m_cy != bm.Height)
throw new Exception("Bitmap different width and height!");
// Get color converted scanlines for this bitmap
int[][] aaiclrScans = GetScans(bm);
// Add ScanRecords for each scan
Frame frame = new Frame();
frame.alsArunsEven = new ArrayList();
frame.alsArunsOdd = new ArrayList();
for (int y = 0; y < m_cy; y++) {
frame.alsArunsEven.Add(GetRuns(Align.Even, aaiclrScans[y]));
frame.alsArunsOdd.Add(GetRuns(Align.Odd, aaiclrScans[y]));
}
// Add this frame
m_alsFrames.Add(frame);
}
unsafe int[][] GetScans(Bitmap bm) {
// Special colors
int[][] aaiclrScans = new int[m_cy][];
// Lock down bits for speed
Rectangle rc = new Rectangle(0, 0, m_cx, m_cy);
BitmapData bmd = bm.LockBits(rc, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
byte *pbBase = (byte *)bmd.Scan0.ToPointer();
for (int y = 0; y < m_cy; y++) {
int[] aiclrScan = new int[m_cx];
for (int x = 0; x < m_cx; x++) {
// Get color
byte *pb = pbBase + y * bmd.Stride + x * 3;
Color clr = Color.FromArgb(pb[2], pb[1], pb[0]);
// Transparent and shadow don't exist in the output palette
// so they have special values.
if (clr == m_clrTransparent) {
aiclrScan[x] = s_iclrTransparent;
continue;
}
if (clr == m_clrShadow) {
aiclrScan[x] = s_iclrShadow;
continue;
}
// Find closest entry in this palette
aiclrScan[x] = m_pal.FindClosestEntry(clr);
}
aaiclrScans[y] = aiclrScan;
}
bm.UnlockBits(bmd);
return aaiclrScans;
}
ColorType GetColorType(int iclr) {
if (iclr == s_iclrTransparent)
return ColorType.Transparent;
if (iclr == s_iclrShadow)
return ColorType.Shadow;
if (iclr >= s_iclrSideFirst && iclr <= s_iclrSideLast)
return ColorType.Side;
return ColorType.Data;
}
Run[] GetRuns(Align alignScan, int[] aiclrScan) {
// First calc and remember the runs
ArrayList alsCtRuns = new ArrayList();
ArrayList alsCounts = new ArrayList();
ColorType ctRun = ColorType.Unknown;
int iiclrFirst = 0;
for (int iiclr = 0; iiclr < aiclrScan.Length; iiclr++) {
// Classify color
ColorType ctCurrent = GetColorType(aiclrScan[iiclr]);
// Continue if we're in a run
if (ctRun == ctCurrent)
continue;
// We've encountered a color of a different type.
// If we're leaving a side run or if we're entering a data run, then check if side colors are
// close ahead. If they are then enter a side run or stay in the existing side run for
// efficiency's sake.
if (ctCurrent == ColorType.Data) {
for (int iiclrT = iiclr + 1; iiclrT < iiclr + 6; iiclrT++) {
// If we've run out of pixels, continue the side run if that's what we're in
if (iiclrT >= aiclrScan.Length) {
if (ctRun == ColorType.Side)
ctCurrent = ColorType.Side;
break;
}
// If we encountered a side color, don't switch
ColorType ctT = GetColorType(aiclrScan[iiclrT]);
if (ctT == ColorType.Side) {
ctCurrent = ColorType.Side;
break;
}
// If we've hit something other than data, it's cheaper to stay with the side run than
// switch to a small data run.
if (ctT != ColorType.Data) {
if (ctRun == ColorType.Side)
ctCurrent = ColorType.Side;
break;
}
}
if (ctRun == ctCurrent)
continue;
}
// Add the run type and the count of pixels this is
if (ctRun != ColorType.Unknown) {
alsCtRuns.Add(ctRun);
alsCounts.Add(iiclr - iiclrFirst);
Debug.Assert((int)alsCounts[alsCounts.Count - 1] <= 255);
}
// Start a run with this color type
iiclrFirst = iiclr;
ctRun = ctCurrent;
}
// Add the last run
alsCtRuns.Add(ctRun);
alsCounts.Add(aiclrScan.Length - iiclrFirst);
Debug.Assert((int)alsCounts[alsCounts.Count - 1] <= 255);
// Now all the scan is classified in terms of runs of color types. Now create runs.
ArrayList alsRun = new ArrayList();
int iiclrRun = 0;
for (int i = 0; i < alsCtRuns.Count; i++) {
if (i == alsCtRuns.Count - 1 && (ColorType)alsCtRuns[i] == ColorType.Transparent)
break;
AddRun(alsRun, alignScan, iiclrRun, aiclrScan, (int)alsCounts[i], (ColorType)alsCtRuns[i]);
iiclrRun += (int)alsCounts[i];
}
// Add terminator
Run run;
run.ct = ColorType.EndScan;
run.cp = 0;
run.align = Align.None;
run.aiclr = null;
run.fNeedSrcAlign = false;
alsRun.Add(run);
// All done
return (Run[])alsRun.ToArray(typeof(Run));
}
void AddRun(ArrayList alsRun, Align alignScan, int iiclrRun, int[] aiclrScan, int cpRun, ColorType ctRun) {
// Figure out the alignment of this run at the dst if drawn
Align alignDst;
if (alignScan == Align.Even) {
alignDst = (iiclrRun & 1) != 0 ? Align.Odd : Align.Even;
} else {
alignDst = (iiclrRun & 1) == 0 ? Align.Odd : Align.Even;
}
// Copy run data, figure required alignment
int[] aiclrRun = null;
Align alignRun = Align.None;
switch (ctRun) {
case ColorType.Data:
// Always aligned; needed to ensure word / dword copies
alignRun = alignDst;
goto CopyRun;
case ColorType.Side:
CopyRun:
aiclrRun = new int[cpRun];
for (int iiclr = iiclrRun; iiclr < iiclrRun + cpRun; iiclr++)
aiclrRun[iiclr - iiclrRun] = aiclrScan[iiclr];
break;
case ColorType.Shadow:
break;
case ColorType.Transparent:
break;
default:
Debug.Assert(false);
break;
}
// Add this run
Run run;
run.ct = ctRun;
run.cp = cpRun;
run.align = alignRun;
run.aiclr = aiclrRun;
run.fNeedSrcAlign = false;
alsRun.Add(run);
}
struct RunDataInstance {
public Run[] arun;
public int[] aiclr;
public Align align;
}
RunDataInstance[] PermuteRunData(Run[] arun, int cMax) {
ArrayList alsRdInst = new ArrayList();
Permute2(Align.Even, 0, arun, new int[0], alsRdInst, cMax);
Permute2(Align.Odd, 0, arun, new int[0], alsRdInst, cMax);
return (RunDataInstance[])alsRdInst.ToArray(typeof(RunDataInstance));
}
void Permute2(Align align, int irun, Run[] arun, int[] aiclr, ArrayList alsRdInst, int cMax) {
if (irun >= arun.Length) {
RunDataInstance rdinst;
rdinst.arun = (Run[])arun.Clone();
rdinst.aiclr = (int[])aiclr.Clone();
rdinst.align = align;
alsRdInst.Add(rdinst);
return;
}
// Determine arguments
RunArgs ra = GetRunArg(arun[irun]);
int nArg = GetCountArg(ra);
if (arun[irun].align != Align.None) {
// Forced alignment
ArrayList alsIclr = new ArrayList();
alsIclr.AddRange(aiclr);
Align alignDst;
if (align == Align.Even) {
alignDst = (aiclr.Length & 1) != 0 ? Align.Odd : Align.Even;
} else {
alignDst = (aiclr.Length & 1) == 0 ? Align.Odd : Align.Even;
}
arun[irun].fNeedSrcAlign = false;
if (nArg != -1) {
if (alignDst == arun[irun].align) {
arun[irun].fNeedSrcAlign = true;
alsIclr.Add(s_iclrNotAssigned);
}
alsIclr.Add(nArg);
} else {
if (alignDst != arun[irun].align) {
arun[irun].fNeedSrcAlign = true;
alsIclr.Add(s_iclrNotAssigned);
}
}
alsIclr.AddRange(arun[irun].aiclr);
Permute2(align, irun + 1, arun, (int[])alsIclr.ToArray(typeof(int)), alsRdInst, cMax);
return;
} else {
// No adjust
ArrayList alsIclr = new ArrayList();
alsIclr.AddRange(aiclr);
if (nArg != -1)
alsIclr.Add(nArg);
if (arun[irun].aiclr != null)
alsIclr.AddRange(arun[irun].aiclr);
arun[irun].fNeedSrcAlign = false;
Permute2(align, irun + 1, arun, (int[])alsIclr.ToArray(typeof(int)), alsRdInst, cMax);
if (cMax != -1 && alsRdInst.Count >= cMax)
return;
#if false
//This saves a modest amount of space however currently we're not supporting _Incs of all ops.
// With adjust
alsIclr = new ArrayList();
alsIclr.AddRange(aiclr);
alsIclr.Add(s_iclrNotAssigned);
if (fCountArg)
alsIclr.Add(arun[irun].cp - 1);
arun[irun].fNeedSrcAlign = true;
if (arun[irun].aiclr != null)
alsIclr.AddRange(arun[irun].aiclr);
Permute2(align, irun + 1, arun, (int[])alsIclr.ToArray(typeof(int)), alsRdInst, cMax);
#endif
}
}
int CompileImageData(ArrayList alsIclr, Run[] arun, bool fSmallest) {
// Get all permutations possible of run data
RunDataInstance[] ardinst = PermuteRunData(arun, fSmallest ? -1 : 1);
// Match the best permutation with existing data
int iiclrStart;
int ird = AddBestRunDataInstance(alsIclr, ardinst, out iiclrStart);
RunDataInstance rdinst = ardinst[ird];
// Patch the passed arun with the matched run
for (int irun = 0; irun < arun.Length; irun++)
arun[irun] = rdinst.arun[irun];
// Return where the data starts
//temp
// Debug.Assert(iiclrStart == MatchImageData(rdinst.align, rdinst.aiclr, alsIclr));
return iiclrStart;
}
int AddBestRunDataInstance(ArrayList alsIclr, RunDataInstance[] ardinst, out int iiclrStart) {
// Match against all permutations
int irdLowest = 0;
int iiclrLowest = alsIclr.Count;
for (int ird = 0; ird < ardinst.Length; ird++) {
RunDataInstance rdinst = ardinst[ird];
int iiclrMatch = MatchImageData(rdinst.align, rdinst.aiclr, alsIclr);
if (iiclrMatch < iiclrLowest) {
iiclrLowest = iiclrMatch;
irdLowest = ird;
}
}
// Contained or partial match
if (iiclrLowest < alsIclr.Count) {
// Patch s_iclrNotAssigned in dst since we can reuse them
RunDataInstance rdinst = ardinst[irdLowest];
int iiclr = 0;
for (; iiclr < rdinst.aiclr.Length && iiclr + iiclrLowest < alsIclr.Count; iiclr++) {
if ((int)alsIclr[iiclrLowest + iiclr] == s_iclrNotAssigned)
alsIclr[iiclrLowest + iiclr] = rdinst.aiclr[iiclr];
Debug.Assert(rdinst.aiclr[iiclr] == s_iclrNotAssigned || rdinst.aiclr[iiclr] == (int)alsIclr[iiclrLowest + iiclr]);
}
// Add the rest if needed
for (; iiclr < rdinst.aiclr.Length; iiclr++) {
Debug.Assert(iiclrLowest + iiclr == alsIclr.Count);
alsIclr.Add(rdinst.aiclr[iiclr]);
}
iiclrStart = iiclrLowest;
return irdLowest;
}
// No best match; add the smallest
int irdSmallest = 0;
int cbSmallest = 0x7fff;
Align alignDst = (alsIclr.Count & 1) != 0 ? Align.Odd : Align.Even;
for (int ird = 0; ird < ardinst.Length; ird++) {
RunDataInstance rdinst = ardinst[ird];
int cbT = rdinst.aiclr.Length;
//temp
#if true
if (alignDst != rdinst.align)
continue;
#endif
if (alignDst != rdinst.align)
cbT++;
if (cbT < cbSmallest) {
irdSmallest = ird;
cbSmallest = cbT;
}
}
// Add the data
if (alignDst != ardinst[irdSmallest].align)
alsIclr.Add(s_iclrNotAssigned);
int iiclrDst = alsIclr.Count;
alsIclr.AddRange(ardinst[irdSmallest].aiclr);
iiclrStart = iiclrDst;
return irdSmallest;
}
int MatchImageData(Align align, int[] aiclr, ArrayList alsIclr) {
//temp
#if false
// Find a full or partial (off the end) match
bool fMatch = false;
for (int iiclrDst = 0; iiclrDst < alsIclr.Count; iiclrDst++) {
// Proper alignment?
Align alignDst = (iiclrDst & 1) != 0 ? Align.Odd : Align.Even;
if (align != alignDst)
continue;
// Match
fMatch = true;
for (int iiclrSrc = 0; iiclrSrc < aiclr.Length; iiclrSrc++) {
// Partial match?
int iiclrDstT = iiclrDst + iiclrSrc;
if (iiclrDstT >= alsIclr.Count)
return iiclrDst;
// Continue matching
if (aiclr[iiclrSrc] == s_iclrNotAssigned)
continue;
if ((int)alsIclr[iiclrDstT] == s_iclrNotAssigned)
continue;
if (aiclr[iiclrSrc] == (int)alsIclr[iiclrDstT])
continue;
fMatch = false;
break;
}
if (fMatch)
return iiclrDst;
}
#endif
// No match
return alsIclr.Count;
}
int GetCountArg(RunArgs ra) {
switch (ra.op) {
case Op.EvenDataLB:
case Op.EvenDataLB_Inc:
Debug.Assert(((ra.cpDst - 1) & 3) == 0);
return (63 - (ra.cpDst - 1) / 4) * 2;
case Op.EvenDataLW:
case Op.EvenDataLW_Inc:
Debug.Assert(((ra.cpDst - 2) & 3) == 0);
return (63 - (ra.cpDst - 2) / 4) * 2;
case Op.EvenDataLWB:
case Op.EvenDataLWB_Inc:
Debug.Assert(((ra.cpDst - 3) & 3) == 0);
return (63 - (ra.cpDst - 3) / 4) * 2;
case Op.EvenDataL:
case Op.EvenDataL_Inc:
Debug.Assert(((ra.cpDst - 0) & 3) == 0);
return (64 - (ra.cpDst - 0) / 4) * 2;
case Op.OddDataLB:
case Op.OddDataLB_Inc:
Debug.Assert(((-1 + ra.cpDst - 1) & 3) == 0);
return (63 - (-1 + ra.cpDst - 1) / 4) * 2;
case Op.OddDataLW:
case Op.OddDataLW_Inc:
Debug.Assert(((-1 + ra.cpDst - 2) & 3) == 0);
return (63 - (-1 + ra.cpDst - 2) / 4) * 2;
case Op.OddDataLWB:
case Op.OddDataLWB_Inc:
Debug.Assert(((-1 + ra.cpDst - 3) & 3) == 0);
return (63 - (-1 + ra.cpDst - 3) / 4) * 2;
case Op.OddDataL:
case Op.OddDataL_Inc:
Debug.Assert(((-1 + ra.cpDst - 0) & 3) == 0);
return (63 - (-1 + ra.cpDst - 0) / 4) * 2;
case Op.SideN:
case Op.ShadowN:
Debug.Assert(ra.cpDst < 64);
return (64 - ra.cpDst) * 6 / 2;
case Op.TransparentN:
return ra.cpDst;
}
return -1;
}
RunArgs GetRunArg(Run run) {
// Figure out the appropriate op for this run
Op op = Op.Error;
switch (run.ct) {
case ColorType.Transparent:
op = Op.TransparentN;
Debug.Assert(run.aiclr == null);
break;
case ColorType.Side:
if (run.cp <= s_cpSideOpFixedMax) {
op = Op.SideStart + run.cp - 1;
} else {
op = Op.SideN;
}
Debug.Assert(run.aiclr != null);
Debug.Assert(run.aiclr.Length == run.cp);
break;
case ColorType.Shadow:
if (run.cp <= s_cpShadowOpFixedMax) {
op = Op.ShadowStart + run.cp - 1;
} else {
op = Op.ShadowN;
}
Debug.Assert(run.aiclr == null);
break;
case ColorType.Data:
if (run.cp <= s_cpDataOpFixedMax) {
if (run.align == Align.Even) {
op = (Op)((int)Op.EvenDataStart + (run.cp - 1) * 2 + (run.fNeedSrcAlign ? 1 : 0));
} else if (run.align == Align.Odd) {
op = (Op)((int)Op.OddDataStart + (run.cp - 1) * 2 + (run.fNeedSrcAlign ? 1 : 0));
} else {
Debug.Assert(false);
}
} else {
if (run.align == Align.Even) {
op = s_mpcpTrailingOpDataEven[run.aiclr.Length % 4];
} else {
op = s_mpcpTrailingOpDataOdd[(run.aiclr.Length - 1)% 4];
}
op += (run.fNeedSrcAlign ? 1 : 0);
}
Debug.Assert(run.aiclr != null);
Debug.Assert(run.aiclr.Length == run.cp);
break;
case ColorType.EndScan:
op = Op.EndScan;
Debug.Assert(run.aiclr == null);
break;
default:
op = Op.Error;
Debug.Assert(false);
break;
}
// Make RunArgs
RunArgs ra;
ra.op = op;
ra.cpDst = run.cp;
ra.cpSrc = 0;
ra.cpArgs = 0;
if (run.aiclr != null)
ra.cpSrc += run.aiclr.Length;
if (run.fNeedSrcAlign) {
ra.cpArgs++;
ra.cpSrc++;
}
if (GetCountArg(ra) != -1) {
ra.cpSrc++;
ra.cpArgs++;
}
return ra;
}
RunArgs[] MakeRunArgs(Run[] arun) {
ArrayList alsRa = new ArrayList();
foreach (Run run in arun)
alsRa.Add(GetRunArg(run));
return (RunArgs[])alsRa.ToArray(typeof(RunArgs));
}
int CompileRunArgs(ArrayList alsRa, Run[] arun) {
RunArgs[] ara = MakeRunArgs(arun);
//temp
#if false
// Incorporate the run args into the list. Match against existing args if possible
bool fMatch = false;
int iraDst = 0;
for (; iraDst < alsRa.Count; iraDst++) {
fMatch = true;
for (int iraSrc = 0; iraSrc < ara.Length; iraSrc++) {
int iraDstT = iraSrc + iraDst;
if (iraDstT >= alsRa.Count) {
for (; iraSrc < ara.Length; iraSrc++)
alsRa.Add(ara[iraSrc]);
fMatch = true;
break;
}
RunArgs raSrc = ara[iraSrc];
RunArgs raDst = (RunArgs)alsRa[iraDstT];
if (raSrc.cpDst != raDst.cpDst || raSrc.op != raDst.op) {
fMatch = false;
break;
}
}
if (fMatch)
break;
}
if (!fMatch)
alsRa.AddRange(ara);
return iraDst;
#else
int iraDst = alsRa.Count;
alsRa.AddRange(ara);
return iraDst;
#endif
}
public void Compile(bool fSmallest) {
CompileResults cr = new CompileResults();
cr.alsIclr = new ArrayList();
cr.alsRa = new ArrayList();
cr.aaiiclrEven = new int[m_alsFrames.Count, m_cy];
cr.aairaEven = new int[m_alsFrames.Count, m_cy];
cr.aaiiclrOdd = new int[m_alsFrames.Count, m_cy];
cr.aairaOdd = new int[m_alsFrames.Count, m_cy];
for (int iFrame = 0; iFrame < m_alsFrames.Count; iFrame++) {
Frame frame = (Frame)m_alsFrames[iFrame];
for (int y = 0; y < m_cy; y++) {
cr.aaiiclrEven[iFrame, y] = CompileImageData(cr.alsIclr, (Run[])frame.alsArunsEven[y], fSmallest);
cr.aairaEven[iFrame, y] = CompileRunArgs(cr.alsRa, (Run[])frame.alsArunsEven[y]);
}
for (int y = 0; y < m_cy; y++) {
cr.aaiiclrOdd[iFrame, y] = CompileImageData(cr.alsIclr, (Run[])frame.alsArunsOdd[y], fSmallest);
cr.aairaOdd[iFrame, y] = CompileRunArgs(cr.alsRa, (Run[])frame.alsArunsOdd[y]);
}
}
m_crLast = cr;
}
byte[] Serialize() {
// word type;
//struct TBitmapSRHeader {
// word cx;
// word cy;
// word cra;
// word ibra;
// word cFrames;
// Frame aframe[1];
//};
if (m_crLast == null)
throw new Exception("Compile image first!");
CompileResults cr = m_crLast;
int ibSrStart = 2 + 2 + 2 + 2 + 2 + 4 * m_alsFrames.Count;
int cbSr = m_alsFrames.Count * (m_cy * 4 + m_cy * 4);
int ibRaStart = ibSrStart + cbSr;
int cbRa = cr.alsRa.Count * 4;
int ibDataStart = ibRaStart + cbRa;
// Write header info
BinaryWriter bwtr = new BinaryWriter(new MemoryStream());
bwtr.Write(Misc.SwapUShort((ushort)TbmType.SkipRun)); // not counted in offsets
bwtr.Write(Misc.SwapUShort((ushort)m_cx));
bwtr.Write(Misc.SwapUShort((ushort)m_cy));
bwtr.Write(Misc.SwapUShort((ushort)cr.alsRa.Count));
bwtr.Write(Misc.SwapUShort((ushort)ibRaStart));
bwtr.Write(Misc.SwapUShort((ushort)m_alsFrames.Count));
// Write isrEven, isrOdd for each frame
int isr = 0;
foreach (Frame frame in m_alsFrames) {
bwtr.Write(Misc.SwapUShort((ushort)(isr + ibSrStart)));
isr += frame.alsArunsEven.Count * 4;
bwtr.Write(Misc.SwapUShort((ushort)(isr + ibSrStart)));
isr += frame.alsArunsOdd.Count * 4;
}
// Write sr's (ScanRecords) for each frame
for (int iFrame = 0; iFrame < m_alsFrames.Count; iFrame++) {
Frame frame = (Frame)m_alsFrames[iFrame];
for (int y = 0; y < m_cy; y++) {
long pos = bwtr.BaseStream.Position - 2;
bwtr.Write(Misc.SwapUShort((ushort)(cr.aaiiclrEven[iFrame, y] + ibDataStart - pos)));
bwtr.Write(Misc.SwapUShort((ushort)(cr.aairaEven[iFrame, y] * 4)));
}
for (int y = 0; y < m_cy; y++) {
long pos = bwtr.BaseStream.Position - 2;
bwtr.Write(Misc.SwapUShort((ushort)(cr.aaiiclrOdd[iFrame, y] + ibDataStart - pos)));
bwtr.Write(Misc.SwapUShort((ushort)(cr.aairaOdd[iFrame, y] * 4)));
}
}
// Write Ras
foreach (RunArgs ra in cr.alsRa) {
bwtr.Write((byte)ra.op);
bwtr.Write((byte)ra.cpSrc);
bwtr.Write((byte)ra.cpArgs);
bwtr.Write((byte)ra.cpDst);
}
// Write iclrData
foreach (int iclr in cr.alsIclr)
bwtr.Write((byte)iclr);
// Done
byte[] ab = new Byte[bwtr.BaseStream.Length];
bwtr.BaseStream.Seek(0, SeekOrigin.Begin);
bwtr.BaseStream.Read(ab, 0, ab.Length);
bwtr.Close();
return ab;
}
#if false
// From runs version
public Bitmap CreateBitmap(int iFrame, bool fEven, bool fAsRuns) {
Bitmap bm = new Bitmap(m_cx, m_cy);
Graphics gMem = Graphics.FromImage(bm);
gMem.Clear(Color.FromArgb(0, 255, 255));
Frame frame = (Frame)m_alsFrames[iFrame];
ArrayList alsArun = fEven ? frame.alsArunsEven : frame.alsArunsOdd;
int y = 0;
int nColor = 0;
foreach(Run[] arun in alsArun) {
int x = 0;
foreach (Run run in arun) {
// Next run
if (run.ct == ColorType.EndScan) {
y++;
break;
}
// Transparency
if (run.ct == ColorType.Transparent) {
for (int xT = x; xT < x + run.cp; xT++)
bm.SetPixel(xT, y, Color.FromArgb(0, 255, 255));
x += run.cp;
continue;
}
// Colorize
if (fAsRuns) {
nColor ^= 1;
Color clr = nColor != 0 ? Color.FromArgb(255, 0, 0) : Color.FromArgb(0, 0, 255);
for (int xT = x; xT < x + run.cp; xT++)
bm.SetPixel(xT, y, clr);
x += run.cp;
} else {
switch (run.ct) {
case ColorType.Data:
case ColorType.Side:
for (int xT = x; xT < x + run.cp; xT++)
bm.SetPixel(xT, y, m_pal[run.aiclr[xT - x]]);
x += run.cp;
break;
case ColorType.Shadow:
for (int xT = x; xT < x + run.cp; xT++)
bm.SetPixel(xT, y, Color.FromArgb(255, 255, 0)); // Color.FromArgb(156, 212, 248));
x += run.cp;
break;
}
}
}
}
gMem.Dispose();
return bm;
}
#else
// From compiled version
public Bitmap CreateBitmap(int iFrame, bool fEven, bool fAsRuns) {
if (m_crLast == null)
throw new Exception("Compile image first!");
CompileResults cr = m_crLast;
Bitmap bm = new Bitmap(m_cx, m_cy);
Graphics gMem = Graphics.FromImage(bm);
gMem.Clear(Color.FromArgb(0, 255, 255));
Frame frame = (Frame)m_alsFrames[iFrame];
int[,] aaiiclr = fEven ? cr.aaiiclrEven : cr.aaiiclrOdd;
int[,] aaira = fEven ? cr.aairaEven : cr.aairaOdd;
int xOrigin = fEven ? 0 : 1;
int nColor = 0;
for (int y = 0; y < m_cy; y++) {
int x = 0;
int iiclr = aaiiclr[iFrame, y];
int irun = aaira[iFrame, y];
while (true) {
RunArgs ra = (RunArgs)cr.alsRa[irun++];
if (ra.op == Op.EndScan)
break;
// Colorize
if (fAsRuns) {
nColor ^= 1;
Color clr = nColor != 0 ? Color.FromArgb(255, 0, 0) : Color.FromArgb(0, 0, 255);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, clr);
x += ra.cpDst;
} else {
// Transparency
if (ra.op == Op.TransparentN) {
Debug.Assert((int)cr.alsIclr[iiclr++] == ra.cpDst);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, Color.FromArgb(0, 255, 255));
x += ra.cpDst;
continue;
}
if (ra.op >= Op.EvenDataStart && ra.op <= Op.EvenDataEnd) {
Debug.Assert(((int)ra.op - (int)Op.EvenDataStart) / 2 + 1 == ra.cpDst);
if (((int)ra.op & 1) != 0)
iiclr++;
Debug.Assert(((x + xOrigin) & 1) == 0 && (iiclr & 1) == 0);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, m_pal[(int)cr.alsIclr[iiclr++]]);
x += ra.cpDst;
continue;
}
if (ra.op >= Op.OddDataStart && ra.op <= Op.OddDataEnd) {
Debug.Assert(((int)ra.op - (int)Op.OddDataStart) / 2 + 1 == ra.cpDst);
if (((int)ra.op & 1) != 0)
iiclr++;
Debug.Assert(((x + xOrigin) & 1) != 0 && (iiclr & 1) != 0);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, m_pal[(int)cr.alsIclr[iiclr++]]);
x += ra.cpDst;
continue;
}
if (ra.op >= Op.EvenDataNStart && ra.op <= Op.OddDataNEnd) {
if (((int)ra.op & 1) != 0)
iiclr++;
iiclr++;
Debug.Assert(((x + xOrigin) & 1) == (iiclr & 1));
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, m_pal[(int)cr.alsIclr[iiclr++]]);
x += ra.cpDst;
continue;
}
if (ra.op >= Op.SideStart && ra.op <= Op.SideEnd) {
Debug.Assert((int)ra.op - (int)Op.Side1 + 1 == ra.cpDst);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, m_pal[(int)cr.alsIclr[iiclr++]]);
x += ra.cpDst;
continue;
}
if (ra.op == Op.SideN) {
Debug.Assert((int)cr.alsIclr[iiclr++] == ra.cpDst);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, m_pal[(int)cr.alsIclr[iiclr++]]);
x += ra.cpDst;
continue;
}
if (ra.op >= Op.ShadowStart && ra.op <= Op.ShadowEnd) {
Debug.Assert((int)ra.op - (int)Op.Shadow1 + 1 == ra.cpDst);
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, Color.FromArgb(255, 255, 0));
x += ra.cpDst;
continue;
}
if (ra.op == Op.ShadowN) {
for (int xT = x; xT < x + ra.cpDst; xT++)
bm.SetPixel(xT, y, Color.FromArgb(255, 255, 0));
x += ra.cpDst;
continue;
}
Debug.Assert(false);
}
}
}
gMem.Dispose();
return bm;
}
#endif
public void PrintStats() {
if (m_crLast == null)
throw new Exception("Compile image first!");
CompileResults cr = m_crLast;
int cRuns = 0;
int cSkips = 0;
int cRunsInScan = 0;
int cScans = 0;
foreach (Frame frame in m_alsFrames) {
foreach (Run[] arun in frame.alsArunsEven) {
cScans++;
foreach (Run run in arun) {
cRunsInScan++;
cRuns++;
if (run.ct == ColorType.Transparent)
cSkips++;
}
}
foreach (Run[] arun in frame.alsArunsOdd) {
cScans++;
foreach (Run run in arun) {
cRunsInScan++;
cRuns++;
if (run.ct == ColorType.Transparent)
cSkips++;
}
}
}
Console.WriteLine("Runs: " + cRuns);
Console.WriteLine("Skips: " + cSkips);
Console.WriteLine("Avg runs per image: " + (float)cRuns / 2.0 / (float)m_alsFrames.Count);
Console.WriteLine("Avg runs per scan: " + (float)cRunsInScan / (float)cScans);
Console.WriteLine("RunArgs size: " + cr.alsRa.Count * 4);
Console.WriteLine("RunData size: " + cr.alsIclr.Count);
Console.WriteLine("SR size: " + m_cy * 4 * m_alsFrames.Count * 2);
}
public void Save(string strFile) {
if (m_crLast == null)
throw new Exception("Compile image first!");
BinaryWriter bwtr = new BinaryWriter(new FileStream(strFile, FileMode.Create, FileAccess.Write));
bwtr.Write(Serialize());
bwtr.Close();
}
public static void EmitOpEnum() {
TextWriter tw = Console.Out;
tw.WriteLine("enum Op {");
int iop = 0;
int iopEvenDataStart = iop;
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++) {
tw.WriteLine("\tEvenData" + cp + ", // " + iop++);
tw.WriteLine("\tEvenData" + cp + "_Inc, // " + iop++);
}
int iopEvenDataEnd = iop - 1;
int iopOddDataStart = iop;
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++) {
tw.WriteLine("\tOddData" + cp + ", // " + iop++);
tw.WriteLine("\tOddData" + cp + "_Inc, // " + iop++);
}
int iopOddDataEnd = iop - 1;
int iopSideStart = iop;
for (int cp = 1; cp <= s_cpSideOpFixedMax; cp++) {
tw.WriteLine("\tSide" + cp + ", // " + iop++);
//tw.WriteLine("\tSide" + cp + "_Inc, // " + iop++);
}
int iopSideEnd = iop - 1;
int iopShadowStart = iop;
for (int cp = 1; cp <= s_cpShadowOpFixedMax; cp++) {
tw.WriteLine("\tShadow" + cp + ", // " + iop++);
//tw.WriteLine("\tShadow" + cp + "_Inc, // " + iop++);
}
int iopShadowEnd = iop - 1;
tw.WriteLine("\tEvenDataLB, // " + iop++);
tw.WriteLine("\tEvenDataLB_Inc, // " + iop++);
tw.WriteLine("\tEvenDataLW, // " + iop++);
tw.WriteLine("\tEvenDataLW_Inc, // " + iop++);
tw.WriteLine("\tEvenDataLWB, // " + iop++);
tw.WriteLine("\tEvenDataLWB_Inc, // " + iop++);
tw.WriteLine("\tEvenDataL, // " + iop++);
tw.WriteLine("\tEvenDataL_Inc, // " + iop++);
tw.WriteLine("\tOddDataLB, // " + iop++);
tw.WriteLine("\tOddDataLB_Inc, // " + iop++);
tw.WriteLine("\tOddDataLW, // " + iop++);
tw.WriteLine("\tOddDataLW_Inc, // " + iop++);
tw.WriteLine("\tOddDataLWB, // " + iop++);
tw.WriteLine("\tOddDataLWB_Inc, // " + iop++);
tw.WriteLine("\tOddDataL, // " + iop++);
tw.WriteLine("\tOddDataL_Inc, // " + iop++);
tw.WriteLine("\tSideN, // " + iop++);
//tw.WriteLine("\tSideN_Inc, // " + iop++);
tw.WriteLine("\tShadowN, // " + iop++);
//tw.WriteLine("\tShadowN_Inc, // " + iop++);
tw.WriteLine("\tTransparentN, // " + iop++);
//tw.WriteLine("\tTransparentN_Inc, // " + iop++);
tw.WriteLine("\tEndScan, // " + iop++);
tw.WriteLine("\tError, // " + iop++);
tw.WriteLine("\tEvenDataStart = " + iopEvenDataStart + ",");
tw.WriteLine("\tEvenDataEnd = " + iopEvenDataEnd + ",");
tw.WriteLine("\tOddDataStart = " + iopOddDataStart + ",");
tw.WriteLine("\tOddDataEnd = " + iopOddDataEnd + ",");
tw.WriteLine("\tSideStart = " + iopSideStart + ",");
tw.WriteLine("\tSideEnd = " + iopSideEnd + ",");
tw.WriteLine("\tShadowStart = " + iopShadowStart + ",");
tw.WriteLine("\tShadowEnd = " + iopShadowEnd);
tw.WriteLine("};");
tw.Close();
}
public static void EmitHandlers() {
//TextWriter tw = new StreamWriter(new MemoryStream());
TextWriter tw = Console.Out;
StringCollection strc = new StringCollection();
//tw.WriteLine(".text");
tw.WriteLine("");
// Fixed data handlers
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++)
EmitDataHandler(tw, cp, Align.Even, false, strc);
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++)
EmitDataHandler(tw, cp, Align.Odd, false, strc);
// Clipped fixed data handlers
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++)
EmitDataHandler(tw, cp, Align.Even, true, strc);
for (int cp = 1; cp <= s_cpDataOpFixedMax; cp++)
EmitDataHandler(tw, cp, Align.Odd, true, strc);
// Fixed side handlers
for (int cp = 1; cp <= s_cpSideOpFixedMax; cp++)
EmitSideHandler(tw, cp, strc);
// Fixed shadow handlers
for (int cp = 1; cp <= s_cpShadowOpFixedMax; cp++)
EmitShadowHandler(tw, cp, strc);
// Non-fixed data handlers
EmitDataNHandler(tw, "EvenDataLB", Align.Even, 63 * 4 + 1, strc);
EmitDataNHandler(tw, "EvenDataLW", Align.Even, 63 * 4 + 2, strc);
EmitDataNHandler(tw, "EvenDataLWB", Align.Even, 63 * 4 + 2 + 1, strc);
EmitDataNHandler(tw, "EvenDataL", Align.Even, 64 * 4, strc);
EmitDataNHandler(tw, "OddDataLB", Align.Odd, 1 + 63 * 4 + 1, strc);
EmitDataNHandler(tw, "OddDataLW", Align.Odd, 1 + 63 * 4 + 2, strc);
EmitDataNHandler(tw, "OddDataLWB", Align.Odd, 1 + 63 * 4 + 2 + 1, strc);
EmitDataNHandler(tw, "OddDataL", Align.Odd, 1 + 63 * 4, strc);
// Table
strc.Add("SideN");
strc.Add("ShadowN");
strc.Add("TransparentN");
strc.Add("EndScan");
tw.WriteLine(".data");
tw.WriteLine(".even");
tw.WriteLine(".globl gapfnRunOps");
tw.WriteLine("gapfnRunOps:");
for (int i = 0; i < strc.Count; i++) {
string str = ".long " + strc[i];
str = str.PadRight(40) + "| " + i + " - " + ((Op)i).ToString();
tw.WriteLine(str);
}
tw.WriteLine("");
// Clip tables
EmitLeftClipTables(tw);
EmitRightClipTables(tw);
tw.Close();
}
static OpType GetOpType(Op op) {
if (op >= Op.EvenDataStart && op <= Op.EvenDataEnd)
return OpType.Data;
if (op >= Op.OddDataStart && op <= Op.OddDataEnd)
return OpType.Data;
if (op >= Op.EvenDataNStart && op <= Op.EvenDataNEnd)
return OpType.Data;
if (op >= Op.OddDataNStart && op <= Op.OddDataNEnd)
return OpType.Data;
if (op >= Op.SideStart && op <= Op.SideEnd)
return OpType.Side;
if (op == Op.SideN)
return OpType.Side;
if (op >= Op.ShadowStart && op <= Op.ShadowEnd)
return OpType.Shadow;
if (op == Op.ShadowN)
return OpType.Shadow;
if (op == Op.TransparentN)
return OpType.Transparent;
Debug.Assert(false);
return OpType.None;
}
static Align GetOpRightAlignment(Op op) {
// If it's not data, we don't know the alignment
if (GetOpType(op) != OpType.Data)
return Align.None;
if (op >= Op.EvenDataStart && op <= Op.EvenDataEnd) {
int cp = (int)(op - (int)Op.EvenDataStart) / 2 + 1;
return (cp & 1) != 0 ? Align.Odd : Align.Even;
}
if (op >= Op.OddDataStart && op <= Op.OddDataEnd) {
int cp = (int)(op - (int)Op.OddDataStart) / 2 + 1;
return (cp & 1) != 0 ? Align.Even : Align.Odd;
}
switch (op) {
case Op.EvenDataLB:
case Op.EvenDataLB_Inc:
return Align.Odd;
case Op.EvenDataLW:
case Op.EvenDataLW_Inc:
return Align.Even;
case Op.EvenDataLWB:
case Op.EvenDataLWB_Inc:
return Align.Odd;
case Op.EvenDataL:
case Op.EvenDataL_Inc:
return Align.Even;
case Op.OddDataLB:
case Op.OddDataLB_Inc:
return Align.Odd;
case Op.OddDataLW:
case Op.OddDataLW_Inc:
return Align.Even;
case Op.OddDataLWB:
case Op.OddDataLWB_Inc:
return Align.Odd;
case Op.OddDataL:
case Op.OddDataL_Inc:
return Align.Even;
}
Debug.Assert(false);
return Align.None;
}
static Align GetOpLeftAlignment(Op op) {
// If it's not data, we don't know the alignment
if (GetOpType(op) != OpType.Data)
return Align.None;
if (op >= Op.EvenDataStart && op <= Op.EvenDataEnd)
return Align.Even;
if (op >= Op.OddDataStart && op <= Op.OddDataEnd)
return Align.Odd;
switch (op) {
case Op.EvenDataLB:
case Op.EvenDataLB_Inc:
return Align.Even;
case Op.EvenDataLW:
case Op.EvenDataLW_Inc:
return Align.Even;
case Op.EvenDataLWB:
case Op.EvenDataLWB_Inc:
return Align.Even;
case Op.EvenDataL:
case Op.EvenDataL_Inc:
return Align.Even;
case Op.OddDataLB:
case Op.OddDataLB_Inc:
return Align.Odd;
case Op.OddDataLW:
case Op.OddDataLW_Inc:
return Align.Odd;
case Op.OddDataLWB:
case Op.OddDataLWB_Inc:
return Align.Odd;
case Op.OddDataL:
case Op.OddDataL_Inc:
return Align.Odd;
}
Debug.Assert(false);
return Align.None;
}
static void EmitLeftClipTables(TextWriter tw) {
// Emit gmpopapfnLeftClip
tw.WriteLine(".globl gmpopapfnLeftClip");
tw.WriteLine("gmpopapfnLeftClip:");
for (Op op = Op.EvenData1; op < Op.EndScan; op++) {
string strT = null;
switch (GetOpType(op)) {
case OpType.Data:
if (GetOpRightAlignment(op) == Align.Even) {
strT = ".long gmpcpRightpfnREEData";
} else {
strT = ".long gmpcpRightpfnREOData";
}
break;
case OpType.Side:
strT = ".long gmpcppfnSide";
break;
case OpType.Shadow:
strT = ".long gmpcppfnShadow";
break;
case OpType.Transparent:
strT = ".long gmpcppfnTransparent";
break;
default:
Debug.Assert(false);
break;
}
if (strT != null)
tw.WriteLine(strT.PadRight(40) + "| " + (int)op + " - " + op.ToString());
}
tw.WriteLine("");
// gmpcpRightpfnREEData (REE == Right Edge Even)
tw.WriteLine("gmpcpRightpfnREEData:");
for (int cpRight = 0; cpRight < 256; cpRight++) {
if (cpRight == 0) {
tw.WriteLine(".long 0");
continue;
}
Align alignLeftEdge = (cpRight & 1) != 0 ? Align.Odd : Align.Even;
switch (alignLeftEdge) {
case Align.Even:
if (cpRight <= s_cpDataOpFixedMax) {
tw.WriteLine(".long EvenData" + cpRight + "_Clip");
} else {
tw.WriteLine(".long EvenDataN_Clip");
}
break;
case Align.Odd:
if (cpRight <= s_cpDataOpFixedMax) {
tw.WriteLine(".long OddData" + cpRight + "_Clip");
} else {
tw.WriteLine(".long OddDataN_Clip");
}
break;
}
}
tw.WriteLine("");
// gmpcpRightpfnREOData (REO == Right Edge Odd)
tw.WriteLine("gmpcpRightpfnREOData:");
for (int cpRight = 0; cpRight < 256; cpRight++) {
if (cpRight == 0) {
tw.WriteLine(".long 0");
continue;
}
Align alignLeftEdge = (cpRight & 1) != 0 ? Align.Even : Align.Odd;
switch (alignLeftEdge) {
case Align.Even:
if (cpRight <= s_cpDataOpFixedMax) {
tw.WriteLine(".long EvenData" + cpRight + "_Clip");
} else {
tw.WriteLine(".long EvenDataN_Clip");
}
break;
case Align.Odd:
if (cpRight <= s_cpDataOpFixedMax) {
tw.WriteLine(".long OddData" + cpRight + "_Clip");
} else {
tw.WriteLine(".long OddDataN_Clip");
}
break;
}
}
tw.WriteLine("");
// gmpcppfnSide
tw.WriteLine("gmpcppfnSide:");
for (int cpRight = 0; cpRight < 256; cpRight++) {
if (cpRight == 0) {
tw.WriteLine(".long 0");
continue;
}
if (cpRight <= s_cpSideOpFixedMax) {
tw.WriteLine(".long Side" + cpRight + "_Clip");
} else {
tw.WriteLine(".long SideN_Clip");
}
}
tw.WriteLine("");
// gmpcppfnShadow
tw.WriteLine("gmpcppfnShadow:");
for (int cpRight = 0; cpRight < 256; cpRight++) {
if (cpRight == 0) {
tw.WriteLine(".long 0");
continue;
}
if (cpRight <= s_cpShadowOpFixedMax) {
tw.WriteLine(".long Shadow" + cpRight);
} else {
tw.WriteLine(".long ShadowN_Clip");
}
}
tw.WriteLine("");
//gmpcppfnTransparent
tw.WriteLine("gmpcppfnTransparent:");
for (int cpRight = 0; cpRight < 256; cpRight++) {
if (cpRight == 0) {
tw.WriteLine(".long 0");
continue;
}
tw.WriteLine(".long TransparentN_Clip");
}
tw.WriteLine("");
}
static void EmitRightClipTables(TextWriter tw) {
// Emit gmpopapfnRightClip
tw.WriteLine(".globl gmpopapfnRightClip");
tw.WriteLine("gmpopapfnRightClip:");
for (Op op = Op.EvenData1; op < Op.EndScan; op++) {
string strT = null;
switch (GetOpType(op)) {
case OpType.Data:
if (GetOpLeftAlignment(op) == Align.Even) {
strT = ".long gmpcpLeftpfnLEEData";
} else {
strT = ".long gmpcpLeftpfnLEOData";
}
break;
case OpType.Side:
strT = ".long gmpcppfnSide";
break;
case OpType.Shadow:
strT = ".long gmpcppfnShadow";
break;
case OpType.Transparent:
strT = ".long gmpcppfnTransparent";
break;
default:
Debug.Assert(false);
break;
}
if (strT != null)
tw.WriteLine(strT.PadRight(40) + "| " + (int)op + " - " + op.ToString());
}
tw.WriteLine("");
// gmpcpLeftpfnLEEData (LEE == Left Edge Even)
tw.WriteLine("gmpcpLeftpfnLEEData:");
for (int cpLeft = 0; cpLeft < 256; cpLeft++) {
if (cpLeft == 0) {
tw.WriteLine(".long 0");
continue;
}
if (cpLeft <= s_cpDataOpFixedMax) {
tw.WriteLine(".long EvenData" + cpLeft + "_Clip");
} else {
tw.WriteLine(".long EvenDataN_Clip");
}
}
tw.WriteLine("");
// gmpcpLeftpfnLEOData (LEO == Left Edge Odd)
tw.WriteLine("gmpcpLeftpfnLEOData:");
for (int cpLeft = 0; cpLeft < 256; cpLeft++) {
if (cpLeft == 0) {
tw.WriteLine(".long 0");
continue;
}
if (cpLeft <= s_cpDataOpFixedMax) {
tw.WriteLine(".long OddData" + cpLeft + "_Clip");
} else {
tw.WriteLine(".long OddDataN_Clip");
}
}
tw.WriteLine("");
}
static void EmitDataNHandler(TextWriter tw, string strLabel, Align align, int cp, StringCollection strc) {
strc.Add(strLabel);
strc.Add(strLabel + "_Inc");
tw.WriteLine(strLabel + "_Inc:");
tw.WriteLine("\taddq.w #1,%a0");
tw.WriteLine(strLabel + ":");
tw.WriteLine("\tmove.b (%a0)+,%d0");
if (align == Align.Odd) {
tw.WriteLine("\tmove.b (%a0)+,(%a1)+");
cp--;
align = Align.Even;
}
tw.WriteLine("\tjmp 2(%pc,%d0.w)");
EmitAlignedDataCopy(tw, cp, align);
tw.WriteLine("\tmove.l (%a2)+,%a3");
tw.WriteLine("\tjmp (%a3)");
tw.WriteLine("");
}
static void EmitShadowHandler(TextWriter tw, int cp, StringCollection strc) {
string strLabel = "Shadow" + cp;
strc.Add(strLabel);
tw.WriteLine(strLabel + ":");
while (cp-- != 0) {
tw.WriteLine("\tmove.b (%a1),%d0");
tw.WriteLine("\tmove.b (%a5,%d0.w),(%a1)+");
}
tw.WriteLine("\tmove.l (%a2)+,%a3");
tw.WriteLine("\tjmp (%a3)");
tw.WriteLine("");
}
static void EmitSideHandler(TextWriter tw, int cp, StringCollection strc) {
string strLabel = "Side" + cp;
strc.Add(strLabel);
tw.WriteLine(strLabel + "_Clip:");
tw.WriteLine("\tadd.w %d2,%a0");
tw.WriteLine(strLabel + ":");
while (cp-- != 0) {
tw.WriteLine("\tmove.b (%a0)+,%d0");
tw.WriteLine("\tmove.b (%a4,%d0.w),(%a1)+");
}
tw.WriteLine("\tmove.l (%a2)+,%a3");
tw.WriteLine("\tjmp (%a3)");
tw.WriteLine("");
}
static void EmitDataHandler(TextWriter tw, int cp, Align align, bool fClip, StringCollection strc) {
string strLabel = (align == Align.Even ? "EvenData" : "OddData") + cp;
if (!fClip) {
string strLabelInc = strLabel + "_Inc";
strc.Add(strLabel);
strc.Add(strLabelInc);
tw.WriteLine(strLabelInc + ":");
tw.WriteLine("\taddq.w #1,%a0");
tw.WriteLine(strLabel + ":");
} else {
tw.WriteLine(strLabel + "_Clip:");
tw.WriteLine("\tadd.w %d2,%a0");
}
EmitAlignedDataCopy(tw, cp, align);
tw.WriteLine("\tmove.l (%a2)+,%a3");
tw.WriteLine("\tjmp (%a3)");
tw.WriteLine("");
}
static void EmitAlignedDataCopy(TextWriter tw, int cp, Align align) {
Align alignWrite = align;
while (cp != 0) {
if (alignWrite == Align.Odd) {
tw.WriteLine("\tmove.b (%a0)+,(%a1)+");
cp--;
alignWrite = Align.Even;
continue;
}
switch (cp) {
case 1:
tw.WriteLine("\tmove.b (%a0)+,(%a1)+");
alignWrite = Align.Odd;
cp -= 1;
Debug.Assert(cp == 0);
break;
case 2:
tw.WriteLine("\tmove.w (%a0)+,(%a1)+");
cp -= 2;
break;
case 3:
tw.WriteLine("\tmove.w (%a0)+,(%a1)+");
tw.WriteLine("\tmove.b (%a0)+,(%a1)+");
alignWrite = Align.Odd;
cp -= 3;
Debug.Assert(cp == 0);
break;
case 4:
tw.WriteLine("\tmove.l (%a0)+,(%a1)+");
cp -= 4;
break;
default:
tw.WriteLine("\tmove.l (%a0)+,(%a1)+");
cp -= 4;
break;
}
}
}
// Emit code to draw the image. This is for data collection purposes at the moment
public void EmitCode(string str, Align align) {
TextWriter tw = Console.Out;
tw.WriteLine(".section code4,\"x\"");
tw.WriteLine(".even");
tw.WriteLine(".globl " + str);
tw.WriteLine(str + ":");
tw.WriteLine("\tlea " + str + "_data(%pc),%a0");
tw.WriteLine("\tmove.w #" + (m_cy - 1) + ",%d1");
Frame frame = (Frame)m_alsFrames[0];
ArrayList aalsRuns;
if (align == Align.Even) {
aalsRuns = frame.alsArunsEven;
} else {
aalsRuns = frame.alsArunsOdd;
}
int xEmitLast = 0;
int yEmitLast = 0;
ArrayList alsIclr = new ArrayList();
for (int y = 0; y < m_cy; y++) {
int x = 0;
Run[] arun = (Run[])aalsRuns[y];
foreach (Run run in arun) {
if (run.ct == ColorType.EndScan)
break;
Align alignDst;
if (align == Align.Even) {
alignDst = (x & 1) != 0 ? Align.Odd : Align.Even;
} else {
alignDst = (x & 1) == 0 ? Align.Odd : Align.Even;
}
Align alignSrc = (alsIclr.Count & 1) != 0 ? Align.Odd : Align.Even;
int cp;
// First destination stepping
switch (run.ct) {
case ColorType.Data:
case ColorType.Shadow:
case ColorType.Side:
if (y - yEmitLast > 1) {
int cyStep = y - yEmitLast;
if (cyStep <= 8) {
tw.WriteLine("\tsubq.w #" + cyStep + ",%d1");
} else {
tw.WriteLine("\tsub.w #" + cyStep + ",%d1");
}
tw.WriteLine("\tbpl.b 1f");
tw.WriteLine("\trts");
tw.WriteLine("1:");
int cbStep = ((y - yEmitLast) - 1) * 160 + (160 - xEmitLast) + x;
tw.WriteLine("\tadd.w #" + cbStep + ",%a1");
} else if (y - yEmitLast == 1) {
tw.WriteLine("\tdbra %d1,1f");
tw.WriteLine("\trts");
tw.WriteLine("1:");
int cbStep = ((y - yEmitLast) - 1) * 160 + (160 - xEmitLast) + x;
tw.WriteLine("\tadd.w #" + cbStep + ",%a1");
} else if (y == yEmitLast) {
int cbStep = x - xEmitLast;
if (cbStep <= 8) {
if (cbStep > 0)
tw.WriteLine("\taddq.w #" + cbStep + ",%a1");
} else {
tw.WriteLine("\tadd.w #" + cbStep + ",%a1");
}
}
break;
}
// Now handle run handling code
switch (run.ct) {
case ColorType.Data:
if (alignSrc != alignDst) {
alsIclr.Add(s_iclrNotAssigned);
tw.WriteLine("\taddq.w #1,%a0");
alignSrc = alignDst;
}
alsIclr.AddRange(run.aiclr);
EmitAlignedDataCopy(tw, run.cp, alignDst);
x += run.cp;
xEmitLast = x;
yEmitLast = y;
break;
case ColorType.Shadow:
cp = run.cp;
while (cp-- != 0) {
tw.WriteLine("\tmove.b (%a1),%d0");
tw.WriteLine("\tmove.b 0.b(%a5,%d0.w),(%a1)+");
}
x += run.cp;
xEmitLast = x;
yEmitLast = y;
break;
case ColorType.Side:
alsIclr.AddRange(run.aiclr);
cp = run.cp;
while (cp-- != 0) {
tw.WriteLine("\tmove.b (%a0)+,%d0");
tw.WriteLine("\tmove.b 0.b(%a4,%d0.w),(%a1)+");
}
x += run.cp;
xEmitLast = x;
yEmitLast = y;
break;
case ColorType.Transparent:
x += run.cp;
break;
}
}
}
tw.WriteLine("\trts");
tw.WriteLine("");
// Emit data:
tw.WriteLine(".even");
tw.WriteLine(str + "_data:");
foreach (int iclr in alsIclr)
tw.WriteLine(".byte " + iclr);
tw.Close();
}
public int FrameCount {
get {
return m_alsFrames.Count;
}
}
}
}