Skip to content

Commit

Permalink
New, more correct, object oriented, and maintainable renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
qkmaxware committed Jan 18, 2024
1 parent fb7a603 commit cb954c2
Show file tree
Hide file tree
Showing 46 changed files with 3,114 additions and 90 deletions.
77 changes: 77 additions & 0 deletions Gameboy.Player.Godot/BitmapTextureRect.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using Godot;
using System;
using Qkmaxware.Emulators.Gameboy;
using Qkmaxware.Emulators.Gameboy.Hardware;
using LcdBitmap = Qkmaxware.Emulators.Gameboy.Hardware.Bitmap;

namespace Qkmaxware.Emulators.Gameboy.Player;

public partial class BitmapTextureRect : TextureRect {

[Export]
[ExportGroup("Colour Pallet/Background")]
public Color BgWhite = new Color(1, 1, 1);
[Export]
public Color BgLightGrey = new Color(0.6f, 0.6f, 0.6f);
[Export]
public Color BgDarkGrey = new Color(0.3f, 0.3f, 0.3f);
[Export]
public Color BgBlack = new Color(0, 0, 0);

[Export]
[ExportGroup("Colour Pallet/Object 0")]
public Color Obj0White = new Color(1, 1, 1);
[Export]
public Color Obj0LightGrey = new Color(0.6f, 0.6f, 0.6f);
[Export]
public Color Obj0DarkGrey = new Color(0.3f, 0.3f, 0.3f);
[Export]
public Color Obj0Black = new Color(0, 0, 0);

[Export]
[ExportGroup("Colour Pallet/Object 1")]
public Color Obj1White = new Color(1, 1, 1);
[Export]
public Color Obj1LightGrey = new Color(0.6f, 0.6f, 0.6f);
[Export]
public Color Obj1DarkGrey = new Color(0.3f, 0.3f, 0.3f);
[Export]
public Color Obj1Black = new Color(0, 0, 0);

private ImageTexture texture;

public void Redraw(LcdBitmap bmp) {
var pixels = Image.Create(width: bmp.Width, height: bmp.Height, useMipmaps: false, format: Image.Format.Rgb8);

for (var col = 0; col < bmp.Height; col++) {
for (var row = 0; row < bmp.Width; row++) {
pixels.SetPixel(row, col, bmp[row, col] switch {
ColourPallet.BackgroundDark => BgBlack,
ColourPallet.Object0Dark => Obj0Black,
ColourPallet.Object1Dark => Obj1Black,

ColourPallet.BackgroundMedium => BgDarkGrey,
ColourPallet.Object0Medium => Obj0DarkGrey,
ColourPallet.Object1Medium => Obj1DarkGrey,

ColourPallet.BackgroundLight => BgLightGrey,
ColourPallet.Object0Light => Obj0LightGrey,
ColourPallet.Object1Light => Obj1LightGrey,

ColourPallet.BackgroundWhite => BgWhite,
ColourPallet.Object0White => Obj0White,
ColourPallet.Object1White => Obj1White,

_ => BgBlack,
});
}
}

if (texture is null) {
texture = ImageTexture.CreateFromImage(pixels);
} else {
texture.Update(pixels);
}
this.Texture = texture;
}
}
37 changes: 37 additions & 0 deletions Gameboy.Player.Godot/Debuggers/Disassembler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Godot;
using System;
using System.Linq;
using Qkmaxware.Emulators.Gameboy.Hardware;
using Qkmaxware.Vm.LR35902;

namespace Qkmaxware.Emulators.Gameboy.Player;

public partial class Disassembler : Control {

[Export] public TextureRenderer Player;

private RichTextLabel text;

private Qkmaxware.Vm.LR35902.Disassembler disassembler = new Qkmaxware.Vm.LR35902.Disassembler(Endianness.LittleEndian);

// Called when the node enters the scene tree for the first time.
public override void _Ready() {
text = this.GetNode<RichTextLabel>("ScrollContainer/RichTextLabel");
}

public void Refresh() {
text.Text = string.Empty;
var cart = Player?.Console?.GetCartridge();
if (cart is not null) {
var bytes = cart.GetBytes().Skip(0x014F); // End of header at: 0x014F = 335
foreach (var instr in disassembler.Disassemble(bytes)) {
if (instr.Operation is not null) {
var argString = string.Join(' ', instr.Arguments.Select(x => x.ToString("X4")));
text.Text += $"0x{instr.Address:X4} {instr.Operation.Name} {argString}" + System.Environment.NewLine;
} else {
text.Text += $"0x{instr.Address:X4} {instr.Opcode:X2}";
}
}
}
}
}
43 changes: 43 additions & 0 deletions Gameboy.Player.Godot/Debuggers/Disassembler.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
[gd_scene load_steps=3 format=3 uid="uid://cs764ed0jafqu"]

[ext_resource type="Script" path="res://Debuggers/Disassembler.cs" id="1_bgd2f"]
[ext_resource type="Texture2D" uid="uid://divrqb47wvwvt" path="res://reload.png" id="3_5ffph"]

[node name="Disassembler" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_bgd2f")

[node name="ScrollContainer" type="ScrollContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 59.0
grow_horizontal = 2
grow_vertical = 2
horizontal_scroll_mode = 0

[node name="RichTextLabel" type="RichTextLabel" parent="ScrollContainer"]
layout_mode = 2
size_flags_horizontal = 3
fit_content = true
autowrap_mode = 0

[node name="Reload" type="Button" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -95.0
offset_bottom = 31.0
grow_horizontal = 0
text = "Reload"
icon = ExtResource("3_5ffph")
expand_icon = true

[connection signal="pressed" from="Reload" to="." method="Refresh"]
40 changes: 40 additions & 0 deletions Gameboy.Player.Godot/Debuggers/Map Debugger.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[gd_scene load_steps=4 format=3 uid="uid://2uytp7r2ouod"]

[ext_resource type="Script" path="res://Debuggers/MapDebugger.cs" id="1_gnyfy"]
[ext_resource type="Script" path="res://BitmapTextureRect.cs" id="2_0ayh7"]
[ext_resource type="Texture2D" uid="uid://divrqb47wvwvt" path="res://reload.png" id="3_fd1ro"]

[node name="Map Debugger" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_gnyfy")

[node name="Rect" type="TextureRect" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_top = 34.0
grow_horizontal = 2
grow_vertical = 2
expand_mode = 1
stretch_mode = 5
script = ExtResource("2_0ayh7")

[node name="Reload" type="Button" parent="."]
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -95.0
offset_bottom = 31.0
grow_horizontal = 0
text = "Reload"
icon = ExtResource("3_fd1ro")
expand_icon = true

[connection signal="pressed" from="Reload" to="." method="Refresh"]
36 changes: 36 additions & 0 deletions Gameboy.Player.Godot/Debuggers/MapDebugger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Godot;
using System;
using Qkmaxware.Emulators.Gameboy.Hardware;

namespace Qkmaxware.Emulators.Gameboy.Player;

public enum MapType {
Background, Window
}

public partial class MapDebugger : Control {

[Export] public TextureRenderer Player;
[Export] public MapType Map;

private BitmapTextureRect rect;

// Called when the node enters the scene tree for the first time.
public override void _Ready() {
this.rect = GetNode<BitmapTextureRect>("Rect");
}

public void Refresh() {
var ppu = Player?.Console?.GPU;
if (ppu is IDebuggablePpu debug) {
switch (Map) {
case MapType.Background:
rect?.Redraw(debug.BackgroundMap.ToBitmap());
break;
case MapType.Window:
rect?.Redraw(debug.WindowMap.ToBitmap());
break;
}
}
}
}
101 changes: 101 additions & 0 deletions Gameboy.Player.Godot/Debuggers/PaletteDebugger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using Godot;
using System;
using System.Linq;
using System.Collections.Generic;
using Qkmaxware.Emulators.Gameboy.Hardware;

namespace Qkmaxware.Emulators.Gameboy.Player;

public partial class PaletteDebugger : Control {

[Export] public TextureRenderer Player;

private ColorRect[][] bg;
private ColorRect[][] obj;

// Called when the node enters the scene tree for the first time.
public override void _Ready() {
bg = new ColorRect[1][];
bg[0] = new ColorRect[4];
for (var i = 0; i < 4; i++) {
var b00 = Convert.ToString(i, 2).PadLeft(2, '0');
bg[0][i] = this.GetNode<ColorRect>("ScrollContainer/HSplitContainer/Background/VBoxContainer/HBoxContainer/"+b00);
}

obj = new ColorRect[2][];
obj[0] = new ColorRect[4];
obj[1] = new ColorRect[4];
for (var i = 0; i < 4; i++) {
var b00 = Convert.ToString(i, 2).PadLeft(2, '0');
obj[0][i] = this.GetNode<ColorRect>("ScrollContainer/HSplitContainer/Objects/VBoxContainer/HBoxContainer1/"+b00);
obj[1][i] = this.GetNode<ColorRect>("ScrollContainer/HSplitContainer/Objects/VBoxContainer/HBoxContainer2/"+b00);
}
}

public void Refresh() {
var ppu = Player?.Console?.GPU;
if (ppu is IDebuggablePpu debug) {
HashSet<ColourPallet> bgcolours = new HashSet<ColourPallet>();
foreach (var palette in debug.BackgroundPalettes.Zip(bg)) {
foreach (var pair in palette.First.Zip(palette.Second)) {
var palettedColour = pair.First;
var rgb = palettedColour switch {
ColourPallet.BackgroundDark => new Color(0,0,0,1),
ColourPallet.Object0Dark => new Color(0,0,0,1),
ColourPallet.Object1Dark => new Color(0,0,0,1),

ColourPallet.BackgroundMedium => new Color(0.3f,0.3f,0.3f,1),
ColourPallet.Object0Medium => new Color(0.3f,0.3f,0.3f,1),
ColourPallet.Object1Medium => new Color(0.3f,0.3f,0.3f,1),

ColourPallet.BackgroundLight => new Color(0.6f,0.6f,0.6f,1),
ColourPallet.Object0Light => new Color(0.6f,0.6f,0.6f,1),
ColourPallet.Object1Light => new Color(0.6f,0.6f,0.6f,1),

ColourPallet.BackgroundWhite => new Color(1f,1f,1f,1),
ColourPallet.Object0White => new Color(1f,1f,1f,1),
ColourPallet.Object1White => new Color(1f,1f,1f,1),

_ => new Color(0,0,0,1),
};
bgcolours.Add(palettedColour);
pair.Second.Color = rgb;
}
}
if (bgcolours.Count < 1) {
GD.PushError("Background palette is mono-colour.");
}

HashSet<ColourPallet> objcolours = new HashSet<ColourPallet>();
foreach (var palette in debug.ObjectPalettes.Zip(obj)) {
foreach (var pair in palette.First.Zip(palette.Second)) {
var palettedColour = pair.First;
var rgb = palettedColour switch {
ColourPallet.BackgroundDark => new Color(0,0,0,1),
ColourPallet.Object0Dark => new Color(0,0,0,1),
ColourPallet.Object1Dark => new Color(0,0,0,1),

ColourPallet.BackgroundMedium => new Color(0.3f,0.3f,0.3f,1),
ColourPallet.Object0Medium => new Color(0.3f,0.3f,0.3f,1),
ColourPallet.Object1Medium => new Color(0.3f,0.3f,0.3f,1),

ColourPallet.BackgroundLight => new Color(0.6f,0.6f,0.6f,1),
ColourPallet.Object0Light => new Color(0.6f,0.6f,0.6f,1),
ColourPallet.Object1Light => new Color(0.6f,0.6f,0.6f,1),

ColourPallet.BackgroundWhite => new Color(1f,1f,1f,1),
ColourPallet.Object0White => new Color(1f,1f,1f,1),
ColourPallet.Object1White => new Color(1f,1f,1f,1),

_ => new Color(0,0,0,1),
};
objcolours.Add(palettedColour);
pair.Second.Color = rgb;
}
}
if (objcolours.Count < 1) {
GD.PushError("Object palette is mono-colour.");
}
}
}
}
Loading

0 comments on commit cb954c2

Please sign in to comment.