Esempio n. 1
0
        /// <summary>
        /// Draw the frame buffer to the screen.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        unsafe void Gpu_Paint(object sender, PaintEventArgs e)
        {
            paintCycle++;
            if (DesignMode)
            {
                e.Graphics.DrawString("Design Mode", this.Font, TextBrush, 0, 0);
                return;
            }

            // Read the Master Control Register
            byte MCRegister = VICKY.ReadByte(0);             // Reading address $AF:0000
            byte MCRHigh    = (byte)(VICKY.ReadByte(1) & 3); // Reading address $AF:0001

            int  resX           = 640;
            int  resY           = 480;
            bool isPixelDoubled = false;

            switch (MCRHigh)
            {
            case 1:
                resX = 800;
                resY = 600;
                break;

            case 2:
                resX           = 320;
                resY           = 240;
                isPixelDoubled = true;
                break;

            case 3:
                resX           = 400;
                resY           = 300;
                isPixelDoubled = true;
                break;
            }

            pixVals = new byte[resX];
            int top = 0; // top gets modified if error messages are displayed
            //Graphics g = Graphics.FromImage(frameBuffer);
            Graphics g = e.Graphics;
            byte     ColumnsVisible = (byte)(resX / CHAR_WIDTH);  //byte ColumnsVisible = RAM.ReadByte(MemoryMap.COLS_VISIBLE);
            byte     LinesVisible   = (byte)(resY / CHAR_HEIGHT); //byte LinesVisible = RAM.ReadByte(MemoryMap.LINES_VISIBLE);

            if (MCRegister == 0 || (MCRegister & 0x80) == 0x80)
            {
                g.DrawString("Graphics Mode disabled", this.Font, TextBrush, 0, 0);
                return;
            }
            else if ((MCRegister & 0x1) == 0x1)
            {
                if (ColumnsVisible < 1 || ColumnsVisible > MAX_TEXT_COLS)
                {
                    DrawTextWithBackground("ColumnsVisible invalid:" + ColumnsVisible.ToString(), g, Color.Black, 0, top);
                    top += 12;
                }
                if (LinesVisible < 1 || LinesVisible > MAX_TEXT_LINES)
                {
                    DrawTextWithBackground("LinesVisible invalid:" + LinesVisible.ToString(), g, Color.Black, 0, top);
                    top += 12;
                }
            }


            if (drawing)
            {
                // drop the frame
                System.Console.WriteLine("Skipped Frame");
                return;
            }
            drawing = true;

            // Check if SOF is enabled
            if (MCRegister != 0 && MCRegister != 0x80)
            {
                StartOfFrame?.Invoke();
            }

            g.CompositingMode    = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
            g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
            // Bilinear interpolation has effect very similar to real HW
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            //e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;

            // Determine if we display a border
            byte border_register = VICKY.ReadByte(MemoryMap.BORDER_CTRL_REG - MemoryMap.VICKY_BASE_ADDR);
            bool displayBorder   = (border_register & 1) != 0;

            int borderXSize = displayBorder ? VICKY.ReadByte(MemoryMap.BORDER_X_SIZE - MemoryMap.VICKY_BASE_ADDR) : 0;
            int borderYSize = displayBorder ? VICKY.ReadByte(MemoryMap.BORDER_Y_SIZE - MemoryMap.VICKY_BASE_ADDR) : 0;
            //this may get corrected in Vicky in the near future.
            // if (isPixelDoubled)
            //{
            //    borderXSize >>= 1; // divide by 2
            //    borderYSize >>= 1; // divide by 2
            //}

            //Rectangle rect = new Rectangle(0, 0, resX, resY);
            Rectangle  rect          = new Rectangle(0, 0, resX - 1, resY - 1);
            BitmapData bitmapData    = frameBuffer.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
            int *      bitmapPointer = (int *)bitmapData.Scan0.ToPointer();

            // Load the SOL register - a lines
            int SOLRegAddr   = MemoryMap.VKY_LINE_IRQ_CTRL_REG - MemoryMap.VICKY_BASE_ADDR;
            int SOLLine0Addr = MemoryMap.VKY_LINE0_CMP_VALUE_LO - MemoryMap.VICKY_BASE_ADDR;
            int SOLLine1Addr = MemoryMap.VKY_LINE1_CMP_VALUE_LO - MemoryMap.VICKY_BASE_ADDR;

            // Reset LUT Cache
            lutCache = new int[256 * 8]; // 8 LUTs


            for (int line = 0; line < resY; line++)
            {
                // Handle SOL interrupts
                byte SOLRegister = VICKY.ReadByte(SOLRegAddr);
                if ((SOLRegister & 1) != 0)
                {
                    int SOLLine0 = VICKY.ReadWord(SOLLine0Addr);
                    if (line == SOLLine0)
                    {
                        StartOfLine?.Invoke();
                    }
                }
                if ((SOLRegister & 2) != 0)
                {
                    int SOLLine1 = VICKY.ReadWord(SOLLine1Addr);
                    if (line == SOLLine1)
                    {
                        StartOfLine?.Invoke();
                    }
                }

                bool gammaCorrection = (MCRegister & 0x40) == 0x40;

                // Default background color to border color
                // In Text mode, the border color is stored at $AF:0005.
                byte borderRed   = VICKY.ReadByte(5);
                byte borderGreen = VICKY.ReadByte(6);
                byte borderBlue  = VICKY.ReadByte(7);
                if (gammaCorrection)
                {
                    borderRed   = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + 0x200 + borderRed);   //gammaCorrection[0x200 + borderGreen];
                    borderGreen = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + 0x100 + borderGreen); //gammaCorrection[0x100 + borderGreen];
                    borderBlue  = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + borderBlue);          // gammaCorrection[borderBlue];
                }
                int borderColor = (int)(0xFF000000 + (borderBlue << 16) + (borderGreen << 8) + borderRed);

                if (tileEditorMode)
                {
                    borderColor = Color.LightGray.ToArgb();
                }
                //int offset = line * 640;
                int *ptr = bitmapPointer + line * STRIDE;
                if (line < borderYSize || line >= resY - borderYSize)
                {
                    for (int x = 0; x < resX; x++)
                    {
                        //System.Runtime.InteropServices.Marshal.WriteInt32(bitmapPointer, (offset + x) * 4, borderColor);
                        ptr[x] = borderColor;
                    }
                }
                else
                {
                    // Graphics Mode
                    int backgroundColor = unchecked ((int)0xFF000000);
                    if ((MCRegister & 0x4) == 0x4)
                    {
                        byte backRed   = VICKY.ReadByte(MemoryMap.BACKGROUND_COLOR_B - MemoryMap.VICKY_BASE_ADDR);
                        byte backGreen = VICKY.ReadByte(MemoryMap.BACKGROUND_COLOR_G - MemoryMap.VICKY_BASE_ADDR);
                        byte backBlue  = VICKY.ReadByte(MemoryMap.BACKGROUND_COLOR_R - MemoryMap.VICKY_BASE_ADDR);
                        if (gammaCorrection)
                        {
                            backRed   = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + 0x200 + backRed);   // gammaCorrection[0x200 + backRed];
                            backGreen = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + 0x100 + backGreen); //gammaCorrection[0x100 + backGreen];
                            backBlue  = VICKY.ReadByte(MemoryMap.GAMMA_BASE_ADDR - MemoryMap.VICKY_BASE_ADDR + backBlue);          //gammaCorrection[backBlue];
                        }
                        backgroundColor = (int)(0xFF000000 + (backBlue << 16) + (backGreen << 8) + backRed);
                    }

                    for (int x = 0; x < resX; x++)
                    {
                        int resetValue = x < borderXSize || x >= resX - borderXSize ? borderColor : backgroundColor;
                        ptr[x] = resetValue;
                    }

                    // Bitmap Mode - draw the layers in revers order from back to front
                    if ((MCRegister & 0x4) == 0x4 || tileEditorMode)
                    {
                        // Layer 12 - sprite layer 6
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 6, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 11 - bitmap 1
                        if ((MCRegister & 0x8) == 0x8)
                        {
                            DrawBitmap(bitmapPointer, gammaCorrection, 1, displayBorder, backgroundColor, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 10 - sprite layer 5
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 5, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 9 - tilemap layer 3
                        if ((MCRegister & 0x10) == 0x10)
                        {
                            DrawTiles(bitmapPointer, gammaCorrection, ColumnsVisible, 3, displayBorder, borderXSize, line, resX);
                        }
                        // Layer 8 - sprite layer 4
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 4, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 7 - tilemap layer 2
                        if ((MCRegister & 0x10) == 0x10)
                        {
                            DrawTiles(bitmapPointer, gammaCorrection, ColumnsVisible, 2, displayBorder, borderXSize, line, resX);
                        }
                        // Layer 6 - sprite layer 3
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 3, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 5 - tilemap layer 1
                        if ((MCRegister & 0x10) == 0x10)
                        {
                            DrawTiles(bitmapPointer, gammaCorrection, ColumnsVisible, 1, displayBorder, borderXSize, line, resX);
                        }
                        // Layer 4 - sprite layer 2
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 2, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 3 - tilemap layer 0
                        if ((MCRegister & 0x10) == 0x10)
                        {
                            DrawTiles(bitmapPointer, gammaCorrection, ColumnsVisible, 0, displayBorder, borderXSize, line, resX);
                        }
                        // Layer 2 - sprite layer 1
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 1, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 1 - bitmap layer 0
                        if ((MCRegister & 0x8) == 0x8)
                        {
                            DrawBitmap(bitmapPointer, gammaCorrection, 0, displayBorder, backgroundColor, borderXSize, borderYSize, line, resX, resY);
                        }
                        // Layer 0 - sprite layer 0
                        if ((MCRegister & 0x20) != 0)
                        {
                            DrawSprites(bitmapPointer, gammaCorrection, 0, displayBorder, borderXSize, borderYSize, line, resX, resY);
                        }
                    }
                    // Draw the text
                    if ((MCRegister & 7) == 0x1 || (MCRegister & 7) == 3 || (MCRegister & 7) == 7)
                    {
                        if (top == 0)
                        {
                            DrawBitmapText(bitmapPointer, MCRegister, gammaCorrection, ColumnsVisible, LinesVisible, borderXSize, borderYSize, line, resX, resY);
                        }
                    }
                }
                if (!TileEditorMode)
                {
                    DrawMouse(bitmapPointer, gammaCorrection, line, resX, resY);
                }
            }
            frameBuffer.UnlockBits(bitmapData);
            g.DrawImage(frameBuffer, ClientRectangle, rect, GraphicsUnit.Pixel);
            //e.Graphics.DrawImageUnscaled(frameBuffer, rect);  // Use this to debug
            drawing = false;
        }
Esempio n. 2
0
        private void DrawTiles(ref BitmapData bd, int layer, int bitmapWidth, bool bkgrnd)
        {
            // There are four possible tilesets to choose from
            int addrTileset = MemoryMap.TILE_CONTROL_REGISTER_ADDR + layer * 8;
            int reg         = VICKY.ReadByte(addrTileset - MemoryMap.VICKY_BASE_ADDR);

            // if the set is not enabled, we're done.
            if ((reg & 0x01) == 00)
            {
                return;
            }
            // This is hard coded for now
            int  lines    = 52;
            int  lutIndex = (reg & 14) >> 1; // 8 possible LUTs
            bool striding = (reg & 0x80) == 0x80;

            int tilesetAddress = VICKY.ReadLong(addrTileset + 1 - MemoryMap.VICKY_BASE_ADDR);
            int strideX        = striding ? 256 : VICKY.ReadWord(addrTileset + 4 - MemoryMap.VICKY_BASE_ADDR);
            int strideY        = VICKY.ReadWord(addrTileset + 6 - MemoryMap.VICKY_BASE_ADDR);

            // Now read the tilemap
            int    tilemapAddress = 0xAF5000 + 0x800 * layer;
            IntPtr p = bd.Scan0;

            int colOffset   = bkgrnd ? (80 - ColumnsVisible) / 2 * charWidth / tileSize: 0;
            int lineOffset  = bkgrnd ? (60 - lines) / 2 * charHeight / tileSize : 0;
            int borderXSize = VICKY.ReadByte(0xAF_0008 - MemoryMap.VICKY_BASE_ADDR);
            int borderYSize = VICKY.ReadByte(0xAF_0009 - MemoryMap.VICKY_BASE_ADDR);

            for (int tileRow = lineOffset; tileRow < (30 - lineOffset); tileRow++)
            {
                if (tileRow * 16 < borderYSize || tileRow * 16 > (480 - borderYSize))
                {
                    continue;
                }
                for (int tileCol = colOffset; tileCol < (40 - colOffset); tileCol++)
                {
                    if (tileCol * 16 < borderXSize || (tileCol + 1) * 16 > (640 - borderXSize))
                    {
                        continue;
                    }
                    int tile       = VICKY.ReadByte(tilemapAddress + tileCol + tileRow * 64 - MemoryMap.VICKY_BASE_ADDR);
                    int pixelIndex = 0;
                    int value      = 0;

                    // Tiles are 16 x 16
                    for (int line = 0; line < 16; line++)
                    {
                        int offset = tilesetAddress + ((tile / 16) * 256 * 16 + (tile % 16) * 16) + line * strideX;
                        for (int col = 0; col < 16; col++)
                        {
                            // Lookup the pixel in the tileset
                            pixelIndex = VRAM.ReadByte(offset + col);
                            if (pixelIndex != 0)
                            {
                                value = (int)graphicsLUT[lutIndex * 256 + pixelIndex];
                                if (gammaCorrection != null)
                                {
                                    //value = (int)((blue << 16) + (green << 8) + red + 0xFF000000);
                                    value = (int)((gammaCorrection[(value & 0x00FF0000) >> 0x10] << 0x10) +
                                                  (gammaCorrection[0x100 + ((value & 0x0000FF00) >> 0x08)] << 0x08) +
                                                  (gammaCorrection[0x200 + (value & 0x000000FF)]) + 0xFF000000);
                                }

                                System.Runtime.InteropServices.Marshal.WriteInt32(p, (line * bitmapWidth + col + tileCol * 16 + tileRow * 16 * 640) * 4, value);
                            }
                        }
                    }
                }
            }
        }