コード例 #1
0
        /// <summary>
        /// Calculates the code for the Brightness HDMA with the desired channel, Table and possibly SA-1 compatible
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="table"></param>
        /// <param name="sa1"></param>
        /// <returns></returns>
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            DMAMode mode = (table[0].Values.Length == 1 ? DMAMode.P : DMAMode.PP);

            ASMCodeBuilder code       = new ASMCodeBuilder();
            int            channelAdd = 16 * channel;

            table.Name = ".BrightTable";

            code.AppendLabel(INITLabel, "Code to be inserted INIT");
            code.OpenNewBlock();
            code.AppendCode("\tREP #$20", "16 bit mode");
            code.AppendCode("\tLDA #$" + (((Registers.Brightness & 0xFF) << 8) + (int)mode).ToString("X4"));
            code.AppendCode("\tSTA $" + (Registers.DMAMode + channelAdd).ToString("X4"));
            code.AppendCode("\tLDA #" + table.Name, "load high and low byte of table address");
            code.AppendCode("\tSTA $" + (Registers.DMALowByte + channelAdd).ToString("X4"));
            code.AppendCode("\tSEP #$20", "back to 8 bit mode");
            code.AppendCode("\tLDA.b #" + table.Name + ">>16", "load bank byte of table address");
            code.AppendCode("\tSTA $" + (Registers.DMABankByte + channelAdd).ToString("X4"));
            code.AppendCode("\tLDA #$" + (1 << channel).ToString("X2"));
            code.AppendCode("\tTSB $" + RAM.HDMAEnable[sa1].ToString("X4"), "enable HDMA channel " + channel);
            code.AppendCode("\tRTS");
            code.CloseBlock();
            code.AppendEmptyLine();

            code.AppendTable(table);

            return(code.ToString());
        }
コード例 #2
0
ファイル: Table.cs プロジェクト: kaizoman666/EffectTool
        public static bool Merge(HDMATable Table1, HDMATable Table2, out HDMATable Merged)
        {
            Merged = null;
            if (Table1.Count != Table2.Count)
            {
                return(false);
            }

            if (Table1.SequenceEqual(Table2, new HDMATableEntryComparer()))
            {
                Merged = new HDMATable();
                for (int i = 0; i < Table1.Count; i++)
                {
                    List <byte> values = new List <byte>();
                    values.AddRange(Table1[i].Values);
                    values.AddRange(Table2[i].Values);
                    Merged.Add(new HDMATableEntry(TableValueType.db, Table1[i].Scanlines, values.ToArray()));
                }
                if (!Merged.HasEnded())
                {
                    Merged.Add(HDMATableEntry.End);
                }
                return(true);
            }
            return(false);
        }
コード例 #3
0
        /// <summary>
        /// Calculates the code for overlapping multiple brightness gradients.
        /// <para>The final code will use the channel of the first BrightnessHDMA object passed.</para>
        /// </summary>
        /// <param name="hdma">An array of BrightnessHDMA object that will be overlapped for the final code.</param>
        /// <returns>The final code.</returns>
        public static string MultiCode(params BrightnessHDMA[] hdma)
        {
            if (hdma == null || hdma.Length == 0)
            {
                return(null);
            }

            int channel = hdma[0].Channel;

            EffectClasses.HDMATable table = new HDMATable(".BrightTable");

            using (Bitmap b = BitmapEffects.OverlapImages(hdma.Select(h => h.EffectImage).ToArray()))
            {
                byte scanlines = 1;
                int  now       = 0;
                int  compare   = 0x0F - (b.GetPixel(0, 0).A / 17);
                for (int y = 1; y < b.Height; y++, scanlines++)
                {
                    now = 0x0F - (b.GetPixel(0, y).A / 17);
                    if (compare != now || scanlines >= 0x80)
                    {
                        table.Add(new HDMATableEntry(TableValueType.db, scanlines, (byte)compare));
                        compare   = now;
                        scanlines = 0;
                    }
                }

                if (table.TotalScanlines != Scanlines)
                {
                    table.Add(new HDMATableEntry(TableValueType.db, scanlines, (byte)now));
                }

                table.Add(HDMATableEntry.End);

                DMAMode        mode       = (table[0].Values.Length == 1 ? DMAMode.P : DMAMode.PP);
                ASMCodeBuilder code       = new ASMCodeBuilder();
                int            channelAdd = 16 * channel;
                table.Name = ".BrightTable";

                code.AppendLabel(INITLabel, "Code to be inserted INIT");
                code.OpenNewBlock();
                code.AppendCode("\tREP #$20", "16 bit mode");
                code.AppendCode("\tLDA #$" + (((Registers.Brightness & 0xFF) << 8) + (int)mode).ToString("X4"));
                code.AppendCode("\tSTA $" + (Registers.DMAMode + channelAdd).ToString("X4"));
                code.AppendCode("\tLDA #" + table.Name, "load high and low byte of table address");
                code.AppendCode("\tSTA $" + (Registers.DMALowByte + channelAdd).ToString("X4"));
                code.AppendCode("\tSEP #$20", "back to 8 bit mode");
                code.AppendCode("\tLDA.b #" + table.Name + ">>16", "load bank byte of table address");
                code.AppendCode("\tSTA $" + (Registers.DMABankByte + channelAdd).ToString("X4"));
                code.AppendCode("\tLDA #$" + (1 << channel).ToString("X2"));
                code.AppendCode("\tTSB $" + RAM.HDMAEnable[RAM.SA1].ToString("X4"), "enable HDMA channel " + channel);
                code.AppendCode("\tRTS");
                code.CloseBlock();
                code.AppendEmptyLine();

                code.AppendTable(table);

                return(code.ToString());
            }
        }
コード例 #4
0
 public PixelationHDMA()
 {
     Values         = new List <PixelScanline>();
     Table          = new HDMATable(".PixelTable");
     ColorMath      = new ColorMath();
     OriginalImages = new BitmapCollection();
 }
コード例 #5
0
ファイル: HDMA.cs プロジェクト: kaizoman666/EffectTool
 public void AppendTable(HDMATable table)
 {
     AppendLabel(table.Name);
     foreach (var entry in table)
     {
         AppendCode(entry.ToString());
     }
 }
コード例 #6
0
 public void FromTable(HDMATable table)
 {
     if (!table.HasEnded())
     {
         table.Add(HDMATableEntry.End);
     }
     Table = table;
     UpdateImage();
 }
コード例 #7
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
        /// <summary>
        /// Draws the image and sets the internal table based on a string array.
        /// Returns every line that couldn't be translated.
        /// </summary>
        /// <param name="Lines">The lines that will be turned into an image</param>
        /// <param name="eightBit">Whether the values should be interpreted as 8 or 5 bit.</param>
        /// <returns>An array of error containing lines.</returns>
        public string[] FromString(string[] Lines, bool eightBit)
        {
            Table = new HDMATable();
            List <string> errorLines = new List <string>();

            foreach (string s in Lines)
            {
                try
                {
                    string[] values = s.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    if (values.Length < 2)
                    {
                        throw new ArgumentException("Too few arguments.");
                    }

                    byte[] bytes = new byte[values.Length - 1];
                    for (int i = 1; i < values.Length; i++)
                    {
                        if (!eightBit)
                        {
                            bytes[i - 1] = (byte)((byte)ColorEffect | (0x1F & values[i].ToHexInt()));
                        }
                        else
                        {
                            bytes[i - 1] = (byte)((byte)ColorEffect | values[i].ToHexInt() / 8);
                        }
                    }
                    if (bytes.Any(b => b < (byte)ColorEffect))
                    {
                        throw new Exception("Wrong Convertion");
                    }

                    Table.Add(new HDMATableEntry(TableValueType.db, (byte)values[0].ToHexInt(), bytes));

                    if (Table.TotalScanlines > Scanlines)
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
#if (DEBUG)
                    Console.WriteLine("ColorHDMA.FromString ex: " + ex.Message);
#endif
                    errorLines.Add(s);
                }
            }

            if (Table.TotalScanlines < Scanlines)
            {
                Table.Add(new HDMATableEntry(TableValueType.db, 1, (byte)ColorEffect));
            }

            Table.Add(HDMATableEntry.End);
            UpdateImage();
            return(errorLines.ToArray());
        }
コード例 #8
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
        public void FromImage(Bitmap image)
        {
            if (Table == null)
            {
                Table = new HDMATable();
            }
            else
            {
                Table.Clear();
            }

            if ((Math.Log((double)ColorEffect) / Math.Log(2)) % 1 != 0)
            {
                throw new ArgumentException("Can't call method with ColorEffect having multiple colors.\nIt's currently set to: " + ColorEffect);
            }

            string color = "";

            if (ColorEffect == ColorHDMAValues.Red)
            {
                color = "R";
            }
            else if (ColorEffect == ColorHDMAValues.Green)
            {
                color = "G";
            }
            else if (ColorEffect == ColorHDMAValues.Blue)
            {
                color = "B";
            }
            else
            {
                throw new ArgumentException("No color selected");
            }

            byte check_color = (byte)(Convert.ToInt32(typeof(Color).GetProperty(color).GetValue(image.GetPixel(0, 0), null)) / 8);

            for (int y = 1, lines = 1; y < image.Height; y++, lines++)
            {
                byte cur_color = (byte)(Convert.ToInt32(typeof(Color).GetProperty(color).GetValue(image.GetPixel(0, y), null)) / 8);
                if (cur_color != check_color || lines >= 0x80)
                {
                    Table.Add(new HDMATableEntry(TableValueType.db, (byte)lines, (byte)((byte)ColorEffect | check_color)));
                    lines       = 0;
                    check_color = cur_color;
                }
            }

            if (Table.TotalScanlines != Scanlines)
            {
                Table.Add(new HDMATableEntry(TableValueType.db, (byte)(Scanlines - Table.TotalScanlines), (byte)((byte)ColorEffect | check_color)));
            }

            Table.Add(HDMATableEntry.End);
            UpdateImage();
        }
コード例 #9
0
        public string[] FromString(string[] lines)
        {
            Table = new HDMATable();
            List <string> errorLines = new List <string>();

            foreach (string s in lines)
            {
                try
                {
                    string[] values = s.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    if (values.Length < 2)
                    {
                        throw new ArgumentException("Too few arguments.");
                    }
                    byte scanlines = (byte)values[0].ToHexInt();

                    if (scanlines > 0x80 && scanlines - 0x80 != values.Length - 1)
                    {
                        throw new ArgumentException("Invalid use of scanline counter $80+");
                    }

                    byte[] bytes = new byte[values.Length - 1];
                    for (int i = 1; i < values.Length; i++)
                    {
                        bytes[i - 1] = (byte)(values[i].ToHexInt().Range(0, 15));
                    }

                    Table.Add(new HDMATableEntry(TableValueType.db, scanlines, bytes));

                    if (Table.TotalScanlines > Scanlines)
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
#if (DEBUG)
                    Console.WriteLine("BrightnessHDMA.FromString ex: " + ex.Message);
#endif
                    errorLines.Add(s);
                }
            }

            if (Table.TotalScanlines < Scanlines)
            {
                Table.Add(new HDMATableEntry(TableValueType.db, 1, 0xF));
            }

            Table.Add(HDMATableEntry.End);
            UpdateImage();
            return(errorLines.ToArray());
        }
コード例 #10
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
        /// <summary>
        ///
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="table"></param>
        /// <returns></returns>
        public override string Code(int Channel, HDMATable Table, bool SA1)
        {
            string tablename = "";

            if (ColorEffect.HasFlag(ColorHDMAValues.Red))
            {
                tablename += "Red";
            }
            if (ColorEffect.HasFlag(ColorHDMAValues.Green))
            {
                tablename += "Green";
            }
            if (ColorEffect.HasFlag(ColorHDMAValues.Blue))
            {
                tablename += "Blue";
            }

            return(ColorHDMA.Code(Channel, Table, SA1, "." + tablename + "Table"));
        }
コード例 #11
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
        /// <summary>
        /// Checks if the color HDMA table contains date that verifies it's need in the final code
        /// </summary>
        /// <returns></returns>
        public bool IsEmpty()
        {
            if (Table == null)
            {
                Table = new HDMATable();
                return(true);
            }

            foreach (HDMATableEntry entry in Table)
            {
                foreach (byte b in entry.Values)
                {
                    if ((b & 0x1F) != 0)
                    {
                        return(false);
                    }
                }
            }
            return(true);
        }
コード例 #12
0
        public override string Code(int channel, HDMATable table, bool SA1)
        {
            Setup();
            ASMCodeBuilder CodeBuilder = new ASMCodeBuilder();

            if (Values.Count == 1 && Values[0].Scanline == Scanlines)
            {
                CodeBuilder.AppendLabel(MAINLabel, "Caution, not INIT");
                CodeBuilder.OpenNewBlock();
                CodeBuilder.AppendCode("LDA #$" + table[0].Values[0].ToString("X2"), "pixelise BGs");
                CodeBuilder.AppendCode("STA $" + Registers.Pixelation.ToString("X4"));
                CodeBuilder.AppendCode("RTS", "Return");
                CodeBuilder.CloseBlock();
                return(CodeBuilder.ToString());
            }

            int channelAdd = 16 * channel;

            CodeBuilder.AppendLabel(INITLabel, "Code to be put in INIT ASM");

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("\tREP #$20");
            CodeBuilder.AppendCode("\tLDA #$" + ((Registers.Pixelation & 0xFF) << 8).ToString("X4"));
            CodeBuilder.AppendCode("\tSTA $" + (Registers.DMAMode + channelAdd).ToString("X4"));
            CodeBuilder.AppendCode("\tLDA #" + table.Name);
            CodeBuilder.AppendCode("\tSTA $" + (Registers.DMALowByte + channelAdd).ToString("X4"));
            CodeBuilder.AppendCode("\tLDY.b #" + table.Name + ">>16");
            CodeBuilder.AppendCode("\tSTY $" + (Registers.DMABankByte + channelAdd).ToString("X4"));
            CodeBuilder.AppendCode("\tSEP #$20");
            CodeBuilder.AppendCode("\tLDA #$" + (1 << channel).ToString("X2"));
            CodeBuilder.AppendCode("\tTSB $" + RAM.HDMAEnable[SA1].ToString("X4"));
            CodeBuilder.AppendCode("\tRTS");
            CodeBuilder.CloseBlock();
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.AppendTable(table);

            return(CodeBuilder.ToString());
            //return PixelationHDMA.Code(channel, table, SA1);
        }
コード例 #13
0
ファイル: HDMA Color.cs プロジェクト: kaizoman666/EffectTool
        public static string Code(int Channel, HDMATable Table, bool SA1, string TableName)
        {
            DMAMode       mode       = (Table[0].Values.Length == 1 ? DMAMode.P : DMAMode.PP);
            StringBuilder sbCode     = new StringBuilder();
            int           channelAdd = 16 * Channel;
            string        tableName  = "." + TableName.TrimStart('.');

            sbCode.AppendLine("\tREP #$20");
            sbCode.AppendLine("\tLDA #$" + (((Registers.FixedColor & 0xFF) << 8) + (int)mode).ToString("X4"));
            sbCode.AppendLine("\tSTA $" + (Registers.DMAMode + channelAdd).ToString("X4"));
            sbCode.AppendLine("\tLDA #" + tableName);
            sbCode.AppendLine("\tSTA $" + (Registers.DMALowByte + channelAdd).ToString("X4"));
            sbCode.AppendLine("\tLDY.b #" + tableName + ">>16");
            sbCode.AppendLine("\tSTY $" + (Registers.DMABankByte + channelAdd).ToString("X4"));
            sbCode.AppendLine("\tSEP #$20");
            sbCode.AppendLine("\tLDA #$" + (1 << Channel).ToString("X2"));
            sbCode.AppendLine("\tTSB $" + RAM.HDMAEnable[SA1].ToString("X4"));
            sbCode.AppendLine("\tRTS");
            sbCode.AppendLine();
            sbCode.Append(Table.ToString(tableName));

            return(sbCode.ToString());
        }
コード例 #14
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
 public static string Code(int Channel, HDMATable Table, string TableName)
 {
     return(ColorHDMA.Code(Channel, Table, RAM.SA1, TableName));
 }
コード例 #15
0
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            bool bothWindows = (Table.Any(t => (t.ValueType == TableValueType.db && (t.Values[2] != 0xFF || t.Values[3] != 0x00))));
            int  mode        = GetMode(false, bothWindows ? DMAMode.PP1P2P3 : DMAMode.PP1);

            int register = Registers.WindowMask1Left;

            if (!bothWindows && OneWindowEvent != null)
            {
                OneWindowEventArgs e = new OneWindowEventArgs(Window.Window1);
                OneWindowEvent(this, e);
                if (e.Cancel)
                {
                    return("");
                }

                register += (int)e.Window;
            }

            if (!bothWindows)
            {
                foreach (HDMATableEntry entry in table)
                {
                    if (entry.ValueType == TableValueType.db)
                    {
                        byte[] values = entry.Values;
                        Array.Resize(ref values, 2);
                        entry.Values = values;
                    }
                }
            }


            int regmode     = ((register & 0xFF) << 8) + mode;
            int baseChannel = 0x4300 + (channel * 0x10);

            ASMCodeBuilder code = new ASMCodeBuilder();

            code.OpenNewBlock();
            code.AppendCode("REP #$20", "Get into 16 bit mode");
            code.AppendCode("LDA #$" + regmode.ToASMString(), "Register $" + register.ToASMString() + " using mode " + mode);
            code.AppendCode("STA $" + baseChannel.ToASMString(), baseChannel.ToASMString() + " = transfer mode, " + (baseChannel + 1).ToASMString() + " = register");
            code.AppendCode("LDA #" + table.Name, "High byte and low byte of table addresse.");
            code.AppendCode("STA $" + (baseChannel + 2).ToASMString(), (baseChannel + 2).ToASMString() + " = low byte, " + (baseChannel + 3).ToASMString() + " = high byte");
            code.AppendCode("SEP #$20", "Back to 8 bit mode");
            code.AppendCode("LDA.b #" + table.Name + ">>16", "Bank byte of table addresse.");
            code.AppendCode("STA $" + (baseChannel + 4).ToASMString(), "= bank byte");
            code.CloseBlock();

            code.OpenNewBlock();
            code.AppendCode("LDA #$" + (1 << channel).ToASMString());
            code.AppendCode("TSB $" + RAM.HDMAEnable[sa1].ToASMString() + "|!addr", "enable HDMA channel " + channel);
            code.CloseBlock();

            code.AppendCode("RTL", "Return");
            code.AppendEmptyLine();

            code.AppendTable(table);

            return(code.ToString());
        }
コード例 #16
0
        /// <summary>
        ///
        /// </summary>
        internal void UseCollection()
        {
            //http://www.codeproject.com/Articles/20018/Gradients-made-easy
            List <ColorPosition> _list = new List <ColorPosition>(DarknessPositions);

            _list.Sort();

            if (_list[0].Position != 0)
            {
                _list.Insert(0, new ColorPosition(0, 0xF));
            }
            if (_list[_list.Count - 1].Position < Scanlines)
            {
                _list.Add(new ColorPosition(Scanlines, 0xF));
            }

            List <float> positions = new List <float>();
            //positions.Add(0.0f);

            int maxpos = _list.Max(cp => cp.Position);

            foreach (ColorPosition cp in _list)
            {
                positions.Add((float)cp.Position / (float)maxpos);
            }
            //positions.Add(1.0f);

            List <float> factors = new List <float>();

            //factors.Add(0.0f);
            foreach (ColorPosition cp in _list)
            {
                factors.Add((float)cp.Orignal8Bit / 15.0f);
            }
            //factors.Add(1.0f);

            Bitmap bm = new Bitmap(1, maxpos);

            using (Graphics g = Graphics.FromImage(bm))
            {
                Rectangle r = new Rectangle(0, 0, bm.Width, maxpos);
                using (LinearGradientBrush lgb = new LinearGradientBrush(r, Color.FromArgb(_list.Min(cp => cp.Orignal8Bit) * 17, 0, 0),
                                                                         Color.FromArgb(_list.Max(cp => cp.Orignal8Bit) * 17, 0, 0), 90.0f))
                {
                    Blend blend = new Blend();
                    blend.Factors   = factors.ToArray();
                    blend.Positions = positions.ToArray();
                    lgb.Blend       = blend;
                    g.FillRectangle(lgb, r);
                }
            }

            byte Compare = (byte)(bm.GetPixel(0, 0).R / 17);

            Table = new HDMATable();

            for (int y = 0, scan = 1; y < maxpos; y++, scan++)
            {
                byte darkness = (byte)(bm.GetPixel(0, y).R / 17);
                if (Compare != darkness || scan >= 0x80 || y == maxpos - 1)
                {
                    Table.Add(new HDMATableEntry(TableValueType.db, (byte)scan, Compare));
                    Compare = darkness;
                    scan    = 0;
                }

                for (int x = 0; x < bm.Width; x++)
                {
                    bm.SetPixel(x, y, Color.FromArgb(255 - darkness * 17, 0, 0, 0));
                }
            }

            Table.Add(HDMATableEntry.End);

            Bitmap retImg = new Bitmap(256, maxpos);

            using (TextureBrush brush = new TextureBrush(bm, WrapMode.Tile))
                using (Graphics gr = Graphics.FromImage(retImg))
                    gr.FillRectangle(brush, 0, 0, retImg.Width, retImg.Height);

            bm.Dispose();
            EffectImage = retImg;
        }
コード例 #17
0
ファイル: HDMA Wave.cs プロジェクト: kaizoman666/EffectTool
        /// <summary>
        /// Generates the code for the desired effect
        /// </summary>
        /// <param name="channel"></param>
        /// <param name="table"></param>
        /// <param name="sa1"></param>
        /// <returns></returns>
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            int Base        = 0x4300 + (channel * 0x10);
            int Register    = (int)Layers;
            int BaseAddress = RAM.Layer1X[sa1] + ((int)Layers - (int)LayerRegister.Layer1_X) * 2;
            int RegMode     = ((Register & 0xFF) << 8) + 0x02;
            int LSRs        = (int)((1.0 / _speed) / 2.0);

            int Tablesize  = (Scanlines / _width) >= 15 ? 15 : (Scanlines / _width);
            int TableInRAM = CountRAMBytes();

            string tableString = "The Table takes up " + TableInRAM + " bytes of the free RAM\n" +
                                 "It ranges from $" + FreeRAM.ToString("X6") + " - $" + (FreeRAM + TableInRAM - 1).ToString("X6") + " (both addresses included)";

            ASMTable codeTable = new ASMTable(".WaveTable");

            for (int i = 0; i <= Tablesize; i++)
            {
                codeTable.Add(new ASMTableEntry((byte)_IArr[i]));
            }

            char xy = (((int)Layers & 0x01) == 0 ? 'Y' : 'X');

            ASMCodeBuilder CodeBuilder = new ASMCodeBuilder();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(INITLabel, "This section is to be used in the INIT code of levelASM");
            CodeBuilder.AppendCode("REP #$20");
            CodeBuilder.AppendCode("LDA #$" + RegMode.ToASMString(), "Use Mode 02 on register " + Register.ToASMString());
            CodeBuilder.AppendCode("STA $" + Base.ToASMString(), "43" + Channel + "0 = Mode, 43" + Channel + "1 = Register");
            CodeBuilder.AppendCode("LDA #$" + (FreeRAM & 0xFFFF).ToASMString(), "Address of HDMA table");
            CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
            CodeBuilder.AppendCode("SEP #$20");
            CodeBuilder.AppendCode("LDA.b #$" + (FreeRAM >> 16).ToASMString(), "Address of HDMA table, get bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 4).ToASMString(), "43" + Channel + "4 = Bank-Byte of table");
            CodeBuilder.AppendCode("LDA #$" + (0x01 << Channel).ToASMString());
            CodeBuilder.AppendCode("TSB $" + RAM.HDMAEnable[sa1].ToASMString(), "Enable HDMA channel " + Channel);
            CodeBuilder.AppendCode("RTS", "End HDMA setup" + MAINSeperator);
            CodeBuilder.CloseBlock();


            CodeBuilder.AppendCommentLine(tableString);
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(MAINLabel, "This section is to be used in the MAIN code of levelASM");
            CodeBuilder.AppendCode("LDY #$00", "Y will be the loop counter.");
            CodeBuilder.AppendCode("LDX #$00", "X the index for writing the table to the RAM");
            CodeBuilder.AppendCode("LDA $" + RAM.FrameCounter[sa1].ToASMString(), "Speed of waves");
            CodeBuilder.AppendCode("LSR #" + LSRs, "Slowing down A");
            CodeBuilder.AppendCode("STA $00", "Save for later use.");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("PHB : PHK : PLB", "Preservev bank");
            CodeBuilder.AppendLabel(".Loop", "Jump back if not finished writing table");
            CodeBuilder.AppendCode("LDA #$" + _width.ToASMString(), "Set scanline height");
            CodeBuilder.AppendCode("STA $" + FreeRAM.ToASMString() + ",x", "for each wave");
            CodeBuilder.AppendCode("TYA", "Transfer Y to A, to calculate next index");
            CodeBuilder.AppendCode("ADC $00", "Add frame counter");
            CodeBuilder.AppendCode("AND #$" + Tablesize.ToASMString());
            CodeBuilder.AppendCode("PHY", "Preserve loop counter");
            CodeBuilder.AppendCode("TAY", "Get the index in Y");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("LDA.w " + codeTable.Name + ",y", "Load in wave value");
            CodeBuilder.AppendCode("LSR", "Half only");
            CodeBuilder.AppendCode("CLC", "Clear Carry for addition");
            CodeBuilder.AppendCode("ADC $" + (BaseAddress).ToASMString(), "Add value to layer " + xy + " position (low byte)");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 1).ToASMString() + ",x", "store to HDMA table (low byte)");
            CodeBuilder.AppendCode("LDA $" + (BaseAddress + 1).ToASMString(), "Get high byte of X position");
            CodeBuilder.AppendCode("ADC #$00", "Add value to layer X position (low byte)");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 2).ToASMString() + ",x", "store to HDMA table (high byte)");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendCode("PLY", "Pull original loop counter");
            CodeBuilder.AppendCode("CPY #$" + (Scanlines / _width).ToASMString(), "Compare if we have written enough HDMA entries.");
            CodeBuilder.AppendCode("BPL .End", "If bigger, end HDMA");
            CodeBuilder.AppendCode("INX", "Increase X, so that in the next loop, it writes the new table data...");
            CodeBuilder.AppendCode("INX", "... at the end of the old one instead of overwritting it.");
            CodeBuilder.AppendCode("INX");
            CodeBuilder.AppendCode("INY", "Increase loop counter");
            CodeBuilder.AppendCode("BRA .Loop", "Repeat loop");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(".End", "Jump here when at the end of HDMA");
            CodeBuilder.AppendCode("PLB", "Pull back data bank.");
            CodeBuilder.AppendCode("LDA #$00", "End HDMA by writting 00...");
            CodeBuilder.AppendCode("STA $" + (FreeRAM + 3).ToASMString() + ",x", "...at the end of the table.");
            CodeBuilder.AppendCode("RTS");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendTable(codeTable);
            CodeBuilder.CloseBlock();

            return(CodeBuilder.ToString());           // +"\n\n" + tableString;
        }
コード例 #18
0
ファイル: HDMA Color.cs プロジェクト: dtothefourth/EffectTool
        public static string Code(ColorHDMA red, ColorHDMA green, ColorHDMA blue,
                                  PickSingleChannel single, PickMultiChannel multi, PickMultiChannel tripple)
        {
            bool redEmpty   = red.IsEmpty();
            bool greenEmpty = green.IsEmpty();
            bool blueEmpty  = blue.IsEmpty();

            if (redEmpty && blueEmpty && greenEmpty)
            {
                //fixme Exception
                throw new ArgumentException("Cannot generate code from the provided arguments");
            }

            if (redEmpty && blueEmpty)
            {
                return(green.Code(single()));
            }
            if (greenEmpty && blueEmpty)
            {
                return(red.Code(single()));
            }
            if (redEmpty && greenEmpty)
            {
                return(blue.Code(single()));
            }

            int[] newChannels = new int[] { 3, 4, 5 };
            Dictionary <string, HDMATable> dicTable = new Dictionary <string, HDMATable>();
            HDMATable merged = null;

            if (greenEmpty)
            {
                if (HDMATable.Merge(red.Table, blue.Table, out merged))
                {
                    return(ColorHDMA.Code(single(), merged, ".RedBlueTable"));
                }
                else
                {
                    newChannels = multi();
                    dicTable.Add(".RedTable", red.Table);
                    dicTable.Add(".BlueTable", blue.Table);
                }
            }
            else if (redEmpty)
            {
                if (HDMATable.Merge(green.Table, blue.Table, out merged))
                {
                    return(ColorHDMA.Code(single(), merged, ".GreenBlueTable"));
                }
                else
                {
                    newChannels = multi();
                    dicTable.Add(".GreenTable", green.Table);
                    dicTable.Add(".BlueTable", blue.Table);
                }
            }
            else if (blueEmpty)
            {
                if (HDMATable.Merge(green.Table, red.Table, out merged))
                {
                    return(ColorHDMA.Code(single(), merged, ".RedGreenTable"));
                }
                else
                {
                    newChannels = multi();
                    dicTable.Add(".GreenTable", green.Table);
                    dicTable.Add(".RedTable", red.Table);
                }
            }
            else
            {
                if (HDMATable.Merge(green.Table, red.Table, out merged))
                {
                    newChannels = multi();
                    dicTable.Add(".RedGreenTable", merged);
                    dicTable.Add(".BlueTable", blue.Table);
                }
                else if (HDMATable.Merge(green.Table, blue.Table, out merged))
                {
                    newChannels = multi();
                    dicTable.Add(".GreenBlueTable", merged);
                    dicTable.Add(".RedTable", red.Table);
                }
                else if (HDMATable.Merge(red.Table, blue.Table, out merged))
                {
                    newChannels = multi();
                    dicTable.Add(".RedBlueTable", merged);
                    dicTable.Add(".GreenTable", red.Table);
                }
                else
                {
                    newChannels = tripple();
                    dicTable.Add(".RedTable", red.Table);
                    dicTable.Add(".GreenTable", green.Table);
                    dicTable.Add(".BlueTable", blue.Table);
                }
            }

            if (dicTable.Count != newChannels.Length)
            {
                throw new ArgumentException("Number of channels doesn't match number of tables.");
            }

            Func <KeyValuePair <string, HDMATable>, string> getTablename = old => "." + old.Key.TrimStart('.');

            int           channelTrigger = 0;
            StringBuilder sbCode         = new StringBuilder();

            //sbCode.AppendLine("init:");
            sbCode.AppendLine("\tREP #$20");

            for (int i = 0; i < dicTable.Count; i++)
            {
                KeyValuePair <string, HDMATable> tablePair = dicTable.ElementAt(i);
                DMAMode mode       = (tablePair.Value[0].Values.Length == 1 ? DMAMode.P : DMAMode.PP);
                int     channelAdd = 16 * newChannels[i];
                string  tableName  = getTablename(tablePair);

                sbCode.AppendLine("\tLDA #$" + (((Registers.FixedColor & 0xFF) << 8) + (int)mode).ToString("X4"));
                sbCode.AppendLine("\tSTA $" + (Registers.DMAMode + channelAdd).ToString("X4"));
                sbCode.AppendLine("\tLDA #" + tableName);
                sbCode.AppendLine("\tSTA $" + (Registers.DMALowByte + channelAdd).ToString("X4"));
                sbCode.AppendLine("\tLDY.b #" + tableName + ">>16");
                sbCode.AppendLine("\tSTY $" + (Registers.DMABankByte + channelAdd).ToString("X4"));

                channelTrigger += (1 << newChannels[i]);
            }

            sbCode.AppendLine("\tSEP #$20");
            sbCode.AppendLine("\tLDA #$" + channelTrigger.ToString("X2"));
            sbCode.AppendLine("\tTSB $" + RAM.HDMAEnable[RAM.SA1].ToString("X4") + "|!addr");
            sbCode.AppendLine("\tRTL");

            for (int i = 0; i < dicTable.Count; i++)
            {
                KeyValuePair <string, HDMATable> tablePair = dicTable.ElementAt(i);
                string tableName = getTablename(tablePair);
                sbCode.AppendLine();
                sbCode.Append(tablePair.Value.ToString(tableName));
            }

            return(sbCode.ToString());
        }
コード例 #19
0
ファイル: Table.cs プロジェクト: kaizoman666/EffectTool
        /// <summary>
        /// Creates a HDMATable instance that has the exact same values as this one
        /// </summary>
        /// <returns>The object that can be casted to an HDMATable</returns>
        public object Clone()
        {
            HDMATable table = new HDMATable(this.Name, this._entries);

            return(table);
        }
コード例 #20
0
ファイル: HDMA.cs プロジェクト: kaizoman666/EffectTool
 /// <summary>
 ///
 /// </summary>
 protected HDMA()
 {
     Table = new HDMATable();
 }
コード例 #21
0
ファイル: HDMA.cs プロジェクト: kaizoman666/EffectTool
 /// <summary>
 ///
 /// </summary>
 /// <param name="table"></param>
 /// <returns></returns>
 public virtual string Code(HDMATable table)
 {
     return(Code(this.Channel, table, RAM.SA1));
 }
コード例 #22
0
        public bool CheckAndSplitMask(Bitmap mask, ColorMath math)
        {
            //array of with array for each line.
            //each line has entrys with the color and the start position of that color in that line
            ColPos[][] C_Arr = new ColPos[Scanlines][];

            BitmapData data = mask.LockBits(new Rectangle(new Point(0, 0), mask.Size), ImageLockMode.ReadWrite, mask.PixelFormat);

            byte[] bytes = new byte[data.Height * data.Stride];
            System.Runtime.InteropServices.Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

            for (int y = 0; y < mask.Height; y++)
            {
                Color         ColorToCheck = BitmapEffects.GetPixel(data, bytes, 0, y);         //mask.GetPixel(0, y);
                List <ColPos> CList        = new List <ColPos>();
                CList.Add(new ColPos(ColorToCheck, 0));

                for (int x = 1; x < mask.Width; x++)
                {
                    Color c = BitmapEffects.GetPixel(data, bytes, x, y);
                    if (ColorToCheck == c)                     //mask.GetPixel(x, y))
                    {
                        continue;
                    }

                    ColorToCheck = c;                     //mask.GetPixel(x, y);
                    CList.Add(new ColPos(ColorToCheck, x));
                }
                C_Arr[y] = CList.ToArray();
            }

            mask.UnlockBits(data);

            //if more then two black/white transitions appear in (any) line
            bool black3 = C_Arr.Any((CA => CA.Count(c => c.Color.Name == "ff000000") > 2));
            bool white3 = C_Arr.Any((CA => CA.Count(c => c.Color.Name == "ffffffff") > 2));

            //3 transitions in both won't work eg. black-white-black-white-black-white
            if (black3 && white3)
            {
                return(false);
            }

            int[] BlackLines;
            int[] WhiteLines;

            //get all the lines with 3 black transitions.
            //can't be more then 3 because that would result in more then 3 white trans. in the same line.
            IEnumerable <ColPos[]> Puff = C_Arr.Where((CA => CA.Count(c => c.Color.Name == "ff000000") > 2));

            //an array of indeces to those lines.
            BlackLines = new int[Puff.Count()];
            int i = 0;

            foreach (ColPos[] cp in Puff)
            {
                BlackLines[i] = Array.IndexOf(C_Arr, cp);
                i++;
            }

            //same for white.
            Puff       = C_Arr.Where((CA => CA.Count(c => c.Color.Name == "ffffffff") > 2));
            WhiteLines = new int[Puff.Count()];
            i          = 0;
            foreach (ColPos[] cp in Puff)
            {
                WhiteLines[i] = Array.IndexOf(C_Arr, cp);
                i++;
            }

            Bitmap w1 = BitmapEffects.FromColor(Color.White, 256, 224);
            Bitmap w2 = BitmapEffects.FromColor(Color.White, 256, 224);

            BitmapData w1Data = w1.LockBits(new Rectangle(0, 0, w1.Width, w1.Height), ImageLockMode.ReadWrite, w1.PixelFormat);
            BitmapData w2Data = w2.LockBits(new Rectangle(0, 0, w2.Width, w2.Height), ImageLockMode.ReadWrite, w2.PixelFormat);

            byte[] w1Bytes = new byte[w1Data.Height * w1Data.Stride];
            byte[] w2Bytes = new byte[w2Data.Height * w2Data.Stride];
            System.Runtime.InteropServices.Marshal.Copy(w1Data.Scan0, w1Bytes, 0, w1Bytes.Length);
            System.Runtime.InteropServices.Marshal.Copy(w2Data.Scan0, w2Bytes, 0, w2Bytes.Length);


            Table = new HDMATable(".windowTable");
            HDMATableEntry entry     = null;
            HDMATableEntry lastEntry = null;

            //if any line in this image requires 3 black and 2 white, one window (bm1) has to be inverted.
            bool WindowInverted = C_Arr.Any(cp => (cp.Count(c => c.Color.Name == "ff000000") == 3 &&
                                                   cp.Count(c => c.Color.Name == "ffffffff") == 2));

            for (int y = 0; y < Scanlines; y++)
            {
                entry = new HDMATableEntry(TableValueType.db, (byte)(1 + y - Table.TotalScanlines),
                                           0xFF, 0x00, 0xFF, 0x00);

                int countBlack = C_Arr[y].Count(cp => cp.Color.Name == "ff000000");
                int countWhite = C_Arr[y].Count(cp => cp.Color.Name == "ffffffff");

                Func <int, int, int, bool> BlackFromTill = (window, from, till) =>
                {
                    if (till == 0x100)
                    {
                        till = 0xFF;
                    }

                    if (window == 1)
                    {
                        for (int x = from; x < till; x++)
                        {
                            BitmapEffects.SetPixel(w1Data, ref w1Bytes, x, y, Color.Black);
                        }
                        entry.Values[0] = (byte)from;
                        entry.Values[1] = (byte)till;
                        return(true);
                    }
                    else if (window == 2)
                    {
                        for (int x = from; x < till; x++)
                        {
                            BitmapEffects.SetPixel(w2Data, ref w2Bytes, x, y, Color.Black);
                        }
                        entry.Values[2] = (byte)from;
                        entry.Values[3] = (byte)till;
                        return(true);
                    }
                    return(false);
                };

                if (countBlack == 1 && countWhite == 0)
                {
                    // whole line black.
                    // if window get's inverted, line can be left unchanged.
                    if (!WindowInverted)
                    {
                        BlackFromTill(1, 0, w1.Width);                          // if not, whole line black
                    }
                }
                else if (countBlack == 2 && countWhite == 1)
                {
                    //outer black, inner white (black-white-black)

                    if (WindowInverted)                                               //if window 1 is inverted it can be done using one window.
                    {
                        BlackFromTill(1, C_Arr[y][1].Position, C_Arr[y][2].Position); //The part white in the mask will be black in w1
                    }
                    else                                                              //window 1 not inveted:
                    {
                        BlackFromTill(1, C_Arr[y][0].Position, C_Arr[y][1].Position); // first black part of mask in window 1,
                        BlackFromTill(2, C_Arr[y][2].Position, w2.Width);             // and the second in window 2.
                    }
                }
                else if (countBlack == 3 && countWhite == 2)
                {
                    //black-white-black-white-black
                    //1 window inverted, the other not (not possible otherwise).
                    //meaning window 1 will be inverted.

                    BlackFromTill(1, C_Arr[y][1].Position, C_Arr[y][4].Position);                       // windows 1 will be black from the beginning of the first white
                    BlackFromTill(2, C_Arr[y][2].Position, C_Arr[y][3].Position);                       // till the end of the second. Windows 2 is the middle black part.
                }

                //else if (countBlack == 3 && countWhite == 3)
                //... IMPOSSIBRU <.<

                else if (countBlack == 2 && countWhite == 3)
                {
                    //white-black-white-black-white
                    //both windows have to be uninverted. (or playing with XOR setting)

                    BlackFromTill(1, C_Arr[y][1].Position, C_Arr[y][2].Position);                       // window 1 black for first black part of mask
                    BlackFromTill(2, C_Arr[y][3].Position, C_Arr[y][4].Position);                       // windows 2 black for second part.
                }
                else if (countBlack == 1 && countWhite == 2)
                {
                    //outer white inner black (white-black-white)

                    if (WindowInverted)                                               //if windows 1 is inverted, we have to use window 2 and set window 1 black on the whole line
                    {
                        BlackFromTill(1, 0, w1.Width);                                // window 1 completly black
                        BlackFromTill(2, C_Arr[y][1].Position, C_Arr[y][2].Position); // window 2 black where mask is black.
                    }
                    else
                    {
                        BlackFromTill(1, C_Arr[y][1].Position, C_Arr[y][2].Position);                           // if not inverted, simply use window 1.
                    }
                }
                else if (countBlack == 0 && countWhite == 1)
                {
                    //whole line visible
                    if (WindowInverted)
                    {
                        BlackFromTill(1, 0, w1.Width);                                          // if window 1 inverted, whole line black
                    }
                }
                else if (countBlack == 2 && countWhite == 2)
                {
                    //problem: unknown if black-white-black-white or white-black-white-black
                    #region 2/2
                    if (C_Arr[y][0].Color.Name == "ff000000")                             //if fisrt part black then B-W-B-W
                    {
                        if (WindowInverted)                                               //inverted:
                        {
                            BlackFromTill(1, C_Arr[y][1].Position, w1.Width);             // the -W-B-W area will be black, so inverted makes the first bar black
                            BlackFromTill(2, C_Arr[y][2].Position, C_Arr[y][3].Position); // window 2 simply makes second bar black
                        }
                        else                                                              //not inverted
                        {
                            BlackFromTill(1, C_Arr[y][0].Position, C_Arr[y][1].Position); // first bar in window 1
                            BlackFromTill(2, C_Arr[y][2].Position, C_Arr[y][3].Position); // guess what
                        }
                    }
                    else                                                                  // first bar not black, thus W-B-W-B
                    {
                        if (WindowInverted)                                               //inverted:
                        {
                            BlackFromTill(1, C_Arr[y][0].Position, C_Arr[y][3].Position); // the W-B-W- area will be black, inverting makes the last bar black.
                            BlackFromTill(2, C_Arr[y][1].Position, C_Arr[y][2].Position); // window 2 will be black where the first bar is.
                        }
                        else                                                              //not inverted
                        {
                            BlackFromTill(1, C_Arr[y][1].Position, C_Arr[y][2].Position); // first bar in window 2
                            BlackFromTill(2, C_Arr[y][3].Position, w2.Width);             // ...
                        }
                    }
                    #endregion
                }
                else if (countBlack == 1 && countWhite == 1)
                {
                    //problem: unknown if black-white or white-black
                    if (C_Arr[y][0].Color.Name == "ff000000")                             //first bar is black thus B-W
                    {
                        if (WindowInverted)                                               //inverted:
                        {
                            BlackFromTill(1, C_Arr[y][1].Position, w1.Width);             //set second bar (white) to black due to inverting
                        }
                        else                                                              //not inverted
                        {
                            BlackFromTill(1, C_Arr[y][0].Position, C_Arr[y][1].Position); //first bar (black) in window one to black
                        }
                    }
                    else                                                                  //first bar not black thus W-B
                    {
                        if (WindowInverted)                                               //inverted:
                        {
                            BlackFromTill(1, C_Arr[y][0].Position, C_Arr[y][1].Position); // set white part black;
                        }
                        else                                                              //not inverted
                        {
                            BlackFromTill(1, C_Arr[y][1].Position, w1.Width);             //set second bar black.
                        }
                    }
                }


                if ((lastEntry != null && !entry.Values.SequenceEqual(lastEntry.Values)) || entry.Scanlines == 0x81)
                {
                    Table.Add(lastEntry);
                    entry.Scanlines = 1;
                }
                lastEntry = (HDMATableEntry)entry.Clone();
            }                              //end of for-loop

            Table.Add(lastEntry);          //the last last entry
            Table.Add(HDMATableEntry.End); //the actual end.

            System.Runtime.InteropServices.Marshal.Copy(w1Bytes, 0, w1Data.Scan0, w1Bytes.Length);
            System.Runtime.InteropServices.Marshal.Copy(w2Bytes, 0, w2Data.Scan0, w2Bytes.Length);
            w1.UnlockBits(w1Data);
            w2.UnlockBits(w2Data);

            math.WindowingMask1 = w1;
            math.WindowingMask2 = w2;

            math.Window1Inverted = WindowInverted ? (WindowingLayers)0x3F : 0;

            return(true);
        }
コード例 #23
0
ファイル: HDMA.cs プロジェクト: kaizoman666/EffectTool
 /// <summary>
 ///
 /// </summary>
 /// <param name="channel"></param>
 /// <param name="table"></param>
 /// <returns></returns>
 public abstract string Code(int channel, HDMATable table, bool sa1);
コード例 #24
0
        public override string Code(int channel, HDMATable table, bool sa1)
        {
            int Base        = 0x4300 + (channel * 0x10);
            int Register    = (int)Layers;
            int BaseAddress = RAM.Layer1X[sa1] + ((int)Layers - (int)LayerRegister.Layer1_X) * 2;
            int RegMode     = ((Register & 0xFF) << 8) + GetMode(true, DMAMode.PP);

            var       grouped    = Bars.GroupBy(b => b.Multiplier);
            HDMATable _table     = new HDMATable("ParallaxTable_" + DateTime.Now.ToString("HHmmssfff"));
            int       tableInRAM = grouped.Count() * 2;

            Dictionary <int, int> multiplierAddressMapping = new Dictionary <int, int>();
            int addresseForOne = 0;             //address that has the scrollrate of 1 to finish the table.


            string tableString = "The Table takes up " + tableInRAM + " bytes of the free RAM\n" +
                                 "It ranges from $" + FreeRAM.ToString("X6") + " - $" + (FreeRAM + tableInRAM - 1).ToString("X6") + " (both addresses included)";

            ASMCodeBuilder CodeBuilder = new ASMCodeBuilder();

            if (Original.Height > Scanlines)
            {
                CodeBuilder.AppendCommentLine("IMPORTANT! Please edit the JMP command below for the level you use this on");
            }
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(INITLabel, "This section is to be used in the INIT code of levelASM");
            CodeBuilder.AppendCode("REP #$20");
            CodeBuilder.AppendCode("LDA #$" + RegMode.ToASMString(), "Use indeirect and mode " + (int)DMAMode.PP + " on register " + Register.ToASMString());
            CodeBuilder.AppendCode("STA $" + Base.ToASMString(), "43" + Channel + "0 = Mode, 43" + Channel + "1 = Register");

            if (Original.Height <= Scanlines)
            {
                CodeBuilder.AppendCode("LDA #" + _table.Name, "Address of HDMA table, get high and low byte");
                CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
            }

            CodeBuilder.AppendCode("SEP #$20");
            CodeBuilder.AppendCode("LDA.b #" + _table.Name + ">>16", "Address of HDMA table, get bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 4).ToASMString(), "43" + Channel + "4 = Bank-Byte of table");

            CodeBuilder.AppendCode("LDA #$" + (FreeRAM >> 16).ToASMString(), "Address of indirect table in RAM bank byte");
            CodeBuilder.AppendCode("STA $" + (Base + 7).ToASMString(), "43" + Channel + "4 = Bank-Byte of indirect table");

            CodeBuilder.AppendCode("LDA #$" + (0x01 << Channel).ToASMString());
            CodeBuilder.AppendCode("TSB $" + RAM.HDMAEnable[sa1].ToASMString() + "|!addr", "Enable HDMA channel " + Channel);

            if (Original.Height > Scanlines)
            {
                CodeBuilder.AppendCode("JMP level105_" + MAINLabel.TrimStart('.'), "Jump to main code" + MAINSeperator);
            }
            else
            {
                CodeBuilder.AppendCode("RTL", "Return" + MAINSeperator);
            }
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendCommentLine(tableString);
            CodeBuilder.AppendEmptyLine();

            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendLabel(MAINLabel, "This section is to be used in the MAIN code of levelASM");
            CodeBuilder.AppendCode("REP #$20", "16 bit action starts here. (To load the x position of the BG)");
            CodeBuilder.CloseBlock();

            //index for HDMA table entry calculation
            if (Original.Height > Scanlines)
            {
                CodeBuilder.OpenNewBlock();
                CodeBuilder.AppendCode("LDA $" + (BaseAddress + 2).ToASMString(), "Get Y position of BG");
                CodeBuilder.AppendCode("ASL", "times 2");
                CodeBuilder.AppendCode("CLC : ADC $" + (BaseAddress + 2).ToASMString(), "+1 = times 3");
                CodeBuilder.AppendCode("CLC : ADC #" + _table.Name + "+3", "plus Address of HDMA table +3");
                //CodeBuilder.AppendCode("INC : INC : INC", "I have no idea why, but the result is off by 1 entry (3 bytes) so this is to fix it.");
                CodeBuilder.AppendCode("STA $" + (Base + 2).ToASMString(), "43" + Channel + "2 = Low-Byte of table, 43" + Channel + "3 = High-Byte of table");
                CodeBuilder.CloseBlock();
            }

            CodeBuilder.AppendEmptyLine();
            int i = 0;

            //grouped by multiplier
            foreach (var bar in grouped)
            {
                CodeBuilder.OpenNewBlock();
                if (bar.Key != 0.0)
                {
                    CodeBuilder.AppendCode("LDA $" + BaseAddress.ToASMString(), "Load BG x Position");
                }
                CodeBuilder.AppendCode(ParallaxHDMAEntry.LsrAsl(bar.Key), "Multiplied by " + bar.Key);
                var windGroup = bar.GroupBy(b => b.Autospeed);

                foreach (var singleBar in windGroup)
                {
                    //if there is no wind, don't add or preserve A
                    if (singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        CodeBuilder.AppendCode("PHA", "Preserve A (current multiplication result)");
                        CodeBuilder.AppendCode("CLC : ADC #$" + singleBar.Key.ToString("X4"), "Add rate.");
                    }
                    CodeBuilder.AppendCode("STA $" + (FreeRAM + i).ToASMString(), "Store to FreeRAM for indirect HDMA");
                    //also don't restore A if there is no wind.
                    if (singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        CodeBuilder.AppendCode("PLA", "Restore A (current multiplication result)");
                    }

                    //keep track of the address for normal scrolling behaviour (multiplier = 1, no auto scroll)
                    if (bar.Key == 1.0 && singleBar.ElementAt(0).Autoscroll&& singleBar.Key != 0)
                    {
                        addresseForOne = FreeRAM + i;
                    }

                    //remember which address has this specs in dictionary with hashcode
                    multiplierAddressMapping.Add(singleBar.ElementAt(0).GetHashCode(), FreeRAM + i);
                    i += 2;
                }
                CodeBuilder.CloseBlock();
            }

            //if the normal scrolling hasn't been set yet, make one.
            if (addresseForOne == 0)
            {
                CodeBuilder.OpenNewBlock();
                CodeBuilder.AppendCode("LDA $" + BaseAddress.ToASMString(), "Load BG x Position");
                CodeBuilder.AppendCode("STA $" + (FreeRAM + i).ToASMString(), "Store to FreeRAM for indirect HDMA");
                CodeBuilder.CloseBlock();
                addresseForOne = FreeRAM + i;
                i += 2;
            }

            //build the table
            foreach (var bar in Bars)
            {
                //fetch indirect HDMA address
                int adr = multiplierAddressMapping[bar.GetHashCode()] & 0xFFFF;
                //split it
                byte low  = (byte)(adr & 0xFF);
                byte high = (byte)((adr >> 8) & 0xFF);

                //make as many 1 scanline high entries as needed.
                var entry = new HDMATableEntry(TableValueType.dw, 1, low, high);
                _table.AddRange(Enumerable.Repeat <HDMATableEntry>(entry, bar.Scanline));
            }

            //if there aren't enough entries for the whole screen yet, fill it up with scrollrate 1.
            if (_table.Count < Original.Height)
            {
                //fetch indirect HDMA address for normal scrolling
                int adr = addresseForOne & 0xFFFF;
                //split it
                byte low  = (byte)(adr & 0xFF);
                byte high = (byte)((adr >> 8) & 0xFF);

                var entry = new HDMATableEntry(TableValueType.dw, 1, low, high);
                _table.AddRange(Enumerable.Repeat <HDMATableEntry>(entry, Original.Height - _table.Count));
            }

            //cut down table
            for (int l = _table.Count - 1; l >= Original.Height; l--)
            {
                _table.RemoveAt(l);
            }

            //add end.
            _table.Add(HDMATableEntry.End);

            CodeBuilder.AppendCode("SEP #$20", "Back to 8bit");
            CodeBuilder.AppendCode("RTL", "Return");
            CodeBuilder.CloseBlock();

            CodeBuilder.AppendEmptyLine();
            CodeBuilder.OpenNewBlock();
            CodeBuilder.AppendTable(_table);
            CodeBuilder.CloseBlock();

            return(CodeBuilder.ToString());           // +"\n\n" + tableString;
        }