summaryrefslogtreecommitdiff
path: root/Emulator/Chip/DisplayDevice.cs
blob: a18dbd4769827c6ad058cf0b4e99264c998bcd91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
namespace Q1.Emulator.Chip;

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

public class DisplayDevice : RamDevice
{
    public           Texture2D? OutputTexture;
    private readonly u16        _paletteSize;
    private readonly u16        _displayWidth;
    private readonly u16        _displayHeight;
    private          Color[]    textureData;

    public DisplayDevice(u16 paletteSize, u16 displayWidth, u16 displayHeight, u16 addressableStart)
        : base(addressableStart, DisplayDevice.DetermineSize(paletteSize, displayWidth, displayHeight))
    {
        this._paletteSize   = paletteSize;
        this._displayWidth  = displayWidth;
        this._displayHeight = displayHeight;
        this.textureData    = new Color[this._displayWidth * this._displayHeight];
    }

    private static u16 DetermineSize(u16 paletteSize, u16 displayWidth, u16 displayHeight)
    {
        return (u16) ((paletteSize * 3) + (displayWidth * displayHeight));
    }

    public override void Clock()
    {
        Color[] palette = this.ReadPalette();
        ref8 pixelData = this.Memory.AsSpan((u16) (this._paletteSize * 3), (u16) (this._displayWidth * this._displayHeight));
        // Console.WriteLine($"DisplayDevice.Clock: @{(this.AddressableStart + this._paletteSize * 3):X4} palette size={this._paletteSize} display size={this._displayWidth}x{this._displayHeight}");
        for (u16 i = 0; i < this.textureData.Length; i++)
        {
            u8 pixelValue = pixelData[i];
            this.textureData[i] = palette[pixelValue % this._paletteSize];
        }

        if (this.OutputTexture != null)
            this.OutputTexture.SetData(this.textureData);
    }

    private Color[] ReadPalette()
    {
        ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
        Color[] colors = new Color[this._paletteSize + 1];
        colors[0] = Color.Transparent;

        for (u16 i = 0; i < this._paletteSize; i++)
        {
            u16 offset = (u16) (i * 3);
            byte r = paletteData[offset];
            byte g = paletteData[offset + 1];
            byte b = paletteData[offset + 2];
            colors[(u16) (i             + 1)] = new Color(r, g, b);
        }

        return colors;
    }

    public void SetPalette(Color[] palette)
    {
        if (palette.Length != this._paletteSize)
            throw new ArgumentException($"Palette must have {this._paletteSize} colors.");

        ref8 paletteData = this.Memory.AsSpan(0, (u16) (this._paletteSize * 3));
        for (u16 i = 0; i < this._paletteSize; i++)
        {
            u16 offset = (u16) (i * 3);
            paletteData[offset]     = palette[i].R;
            paletteData[offset + 1] = palette[i].G;
            paletteData[offset + 2] = palette[i].B;
        }
    }
}