BizHawk/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/PPU.cs

364 lines
13 KiB
C#

using System;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Vectrex
{
public class PPU
{
public VectrexHawk Core { get; set; }
public bool zero_sig, ramp_sig, blank_sig, off_screen;
public byte vec_scale, x_vel, y_vel, bright;
public double x_pos, y_pos;
public int skip;
public uint bright_int_1, bright_int_2, bright_int_3;
public static uint br = 0xFFFFFFFF;
// lines to draw in a frame and vairables to go to new line
public double[] draw_lines = new double[1024 * 4 * 4];
public uint[] line_brights = new uint[1024 * 3 * 4];
public bool[] line_vis = new bool[1024 * 4];
public double[] draw_lines_old_screen = new double[1024 * 4 * 4];
public uint[] line_brights_old_screen = new uint[1024 * 3 * 4];
public bool[] line_vis_old_screen = new bool[1024 * 4];
public int line_pointer_old_screen;
public int line_pointer;
public bool blank_old, zero_old;
public byte x_vel_old, y_vel_old;
public uint bright_int_1_old;
public void tick()
{
//Console.WriteLine(ramp_sig + " " + zero_sig + " " + blank_sig + " " + Core.cpu.TotalExecutedCycles + " " + (x_vel - 128.0) + " " + x_pos
//+ " " + (y_vel - 128.0) + " " + y_pos + " " + Core.t1_counter + " " + vec_scale);
if (ramp_sig && !zero_sig)
{
if (skip == 0)
{
x_pos = x_pos + (x_vel - 128.0) / 256.0 * (vec_scale + 2);
y_pos = y_pos - (y_vel - 128.0) / 256.0 * (vec_scale + 2);
}
else
{
skip--;
}
off_screen = false;
if (x_pos > 257) { off_screen = true; if (x_pos > (257 + 256)) { x_pos = (257 + 256); } }
if (x_pos < 2) { off_screen = true; if (x_pos < (2 - 256)) { x_pos = (2 - 256); } }
if (y_pos > 385) { off_screen = true; if (y_pos > (385 + 256)) { y_pos = (385 + 256); } }
if (y_pos < 2) { off_screen = true; if (y_pos < (2 - 256)) { y_pos = (2 - 256); } }
}
else if (zero_sig)
{
x_pos = 128 + 2;
y_pos = 192 + 2;
}
/*
if (!blank_sig && !off_screen)
{
Core._vidbuffer[(int)(Math.Round(x_pos) + 260 * Math.Round(y_pos))] |= (int)(br & bright_int_1);
Core._vidbuffer[(int)(Math.Round(x_pos) + 1 + 260 * Math.Round(y_pos))] |= (int)(br & bright_int_2);
Core._vidbuffer[(int)(Math.Round(x_pos) - 1 + 260 * Math.Round(y_pos))] |= (int)(br & bright_int_2);
Core._vidbuffer[(int)(Math.Round(x_pos) + 260 * (Math.Round(y_pos) + 1))] |= (int)(br & bright_int_2);
Core._vidbuffer[(int)(Math.Round(x_pos) + 260 * (Math.Round(y_pos) - 1))] |= (int)(br & bright_int_2);
Core._vidbuffer[(int)(Math.Round(x_pos) + 2 + 260 * Math.Round(y_pos))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) - 2 + 260 * Math.Round(y_pos))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) + 260 * (Math.Round(y_pos) + 2))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) + 260 * (Math.Round(y_pos) - 2))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) + 1 + 260 * (Math.Round(y_pos) + 1))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) + 1 + 260 * (Math.Round(y_pos) - 1))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) - 1 + 260 * (Math.Round(y_pos) + 1))] |= (int)(br & bright_int_3);
Core._vidbuffer[(int)(Math.Round(x_pos) - 1 + 260 * (Math.Round(y_pos) - 1))] |= (int)(br & bright_int_3);
}
*/
}
public void draw_screen()
{
// screen is 2 times the internal size of the image
double start_x = 0;
double end_x = 0;
double start_y = 0;
double end_y = 0;
uint c_bright = 0;
for (int i = 0; i < line_pointer; i++)
{
if (line_vis[i] == true)
{
start_x = draw_lines[i * 4];
start_y = draw_lines[i * 4 + 1];
end_x = draw_lines[i * 4 + 2];
end_y = draw_lines[i * 4 + 3];
c_bright = line_brights[i * 3];
double steps = 0;
double max_x = Math.Abs(end_x - start_x);
double max_y = Math.Abs(end_y - start_y);
bool draw_this_line = true;
if ((start_x < 2) && (end_x < 2)) { draw_this_line = false; }
if ((start_y < 2) && (end_y < 2)) { draw_this_line = false; }
if ((start_x > 257) && (end_x > 257)) { draw_this_line = false; }
if ((start_y > 385) && (end_y > 385)) { draw_this_line = false; }
if (draw_this_line)
{
// truncate lines to only be on screen
if ((start_x >= 2) && (end_x < 2)) { max_x = start_x - 2; end_x = 2; }
if ((end_x >= 2) && (start_x < 2)) { max_x = end_x - 2; start_x = 2; }
if ((start_x <= 257) && (end_x > 257)) { max_x = 257 - start_x; end_x = 257; }
if ((end_x <= 257) && (start_x >= 257)) { max_x = 257 - end_x; start_x = 257; }
if ((start_y >= 2) && (end_y < 2)) { max_y = start_y - 2; end_y = 2; }
if ((end_y >= 2) && (start_y < 2)) { max_y = end_y - 2; start_y = 2; }
if ((start_y <= 385) && (end_y > 385)) { max_y = 385 - start_y; end_y = 257; }
if ((end_y <= 385) && (start_y >= 385)) { max_y = 385 - end_y; start_y = 385; }
// screen size is double internal size
start_x *= 2;
end_x *= 2;
start_y *= 2;
end_y *= 2;
max_x *= 2;
max_y *= 2;
steps = Math.Max(max_x, max_y) + 1;
double x_step = (end_x - start_x) / steps;
double y_step = (end_y - start_y) / steps;
for (int j = 0; j <= steps; j++)
{
Core._vidbuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
// at minimum need to make 3 pixels thick to be represetnative of a real vectrex, add more for glow
Core._vidbuffer[(int)(Math.Round(start_x + x_step * j) + 1 + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
Core._vidbuffer[(int)(Math.Round(start_x + x_step * j) - 1 + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
Core._vidbuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * (Math.Round(start_y + y_step * j) + 1))] |= (int)(br & c_bright);
Core._vidbuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * (Math.Round(start_y + y_step * j) - 1))] |= (int)(br & c_bright);
}
}
}
}
// copy all the data to the old screen arrays to save it for loading states
for (int i = 0; i < line_pointer; i++)
{
draw_lines_old_screen[i * 4] = draw_lines[i * 4];
draw_lines_old_screen[i * 4 + 1] = draw_lines[i * 4 + 1];
draw_lines_old_screen[i * 4 + 2] = draw_lines[i * 4 + 2];
draw_lines_old_screen[i * 4 + 3] = draw_lines[i * 4 + 3];
line_brights_old_screen[i * 3] = line_brights[i * 3];
line_brights_old_screen[i * 3 + 1] = line_brights[i * 3 + 1];
line_brights_old_screen[i * 3 + 2] = line_brights[i * 3 + 2];
line_vis_old_screen[i] = line_vis[i];
}
line_pointer_old_screen = line_pointer;
// reset pointer back to zero but keep current starting point
draw_lines[0] = draw_lines[line_pointer * 4];
draw_lines[1] = draw_lines[line_pointer * 4 + 1];
line_vis[0] = line_vis[line_pointer];
line_brights[0] = line_brights[line_pointer * 3];
line_pointer = 0;
}
public void draw_old_screen()
{
// screen is 2 times the internal size of the image
double start_x = 0;
double end_x = 0;
double start_y = 0;
double end_y = 0;
uint c_bright = 0;
for (int i = 0; i < line_pointer_old_screen; i++)
{
if (line_vis_old_screen[i] == true)
{
start_x = draw_lines_old_screen[i * 4];
start_y = draw_lines_old_screen[i * 4 + 1];
end_x = draw_lines_old_screen[i * 4 + 2];
end_y = draw_lines_old_screen[i * 4 + 3];
c_bright = line_brights_old_screen[i * 3];
double steps = 0;
double max_x = Math.Abs(end_x - start_x);
double max_y = Math.Abs(end_y - start_y);
bool draw_this_line = true;
if ((start_x < 2) && (end_x < 2)) { draw_this_line = false; }
if ((start_y < 2) && (end_y < 2)) { draw_this_line = false; }
if ((start_x > 257) && (end_x > 257)) { draw_this_line = false; }
if ((start_y > 385) && (end_y > 385)) { draw_this_line = false; }
if (draw_this_line)
{
// truncate lines to only be on screen
if ((start_x >= 2) && (end_x < 2)) { max_x = start_x - 2; end_x = 2; }
if ((end_x >= 2) && (start_x < 2)) { max_x = end_x - 2; start_x = 2; }
if ((start_x <= 257) && (end_x > 257)) { max_x = 257 - start_x; end_x = 257; }
if ((end_x <= 257) && (start_x >= 257)) { max_x = 257 - end_x; start_x = 257; }
if ((start_y >= 2) && (end_y < 2)) { max_y = start_y - 2; end_y = 2; }
if ((end_y >= 2) && (start_y < 2)) { max_y = end_y - 2; start_y = 2; }
if ((start_y <= 385) && (end_y > 385)) { max_y = 385 - start_y; end_y = 257; }
if ((end_y <= 385) && (start_y >= 385)) { max_y = 385 - end_y; start_y = 385; }
// screen size is double internal size
start_x *= 2;
end_x *= 2;
start_y *= 2;
end_y *= 2;
max_x *= 2;
max_y *= 2;
steps = Math.Max(max_x, max_y) + 1;
double x_step = (end_x - start_x) / steps;
double y_step = (end_y - start_y) / steps;
for (int j = 0; j <= steps; j++)
{
Core._framebuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
// at minimum need to make 3 pixels thick to be represetnative of a real vectrex, add more for glow
Core._framebuffer[(int)(Math.Round(start_x + x_step * j) + 1 + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
Core._framebuffer[(int)(Math.Round(start_x + x_step * j) - 1 + 260 * 2 * Math.Round(start_y + y_step * j))] |= (int)(br & c_bright);
Core._framebuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * (Math.Round(start_y + y_step * j) + 1))] |= (int)(br & c_bright);
Core._framebuffer[(int)(Math.Round(start_x + x_step * j) + 260 * 2 * (Math.Round(start_y + y_step * j) - 1))] |= (int)(br & c_bright);
}
}
}
}
}
public void new_draw_line()
{
if (((ramp_sig && !zero_sig) && ((x_vel != x_vel_old) || (y_vel != y_vel_old))) ||
(blank_sig != blank_old) ||
(bright_int_1 != bright_int_1_old) ||
(zero_sig != zero_old))
{
draw_lines[line_pointer * 4 + 2] = x_pos;
draw_lines[line_pointer * 4 + 3] = y_pos;
line_pointer++;
draw_lines[line_pointer * 4] = x_pos;
draw_lines[line_pointer * 4 + 1] = y_pos;
line_brights[line_pointer * 3] = bright_int_1;
line_brights[line_pointer * 3 + 1] = bright_int_2;
line_brights[line_pointer * 3 + 2] = bright_int_3;
line_vis[line_pointer] = !blank_sig;
}
if (ramp_sig && !zero_sig)
{
x_vel_old = x_vel;
y_vel_old = y_vel;
}
zero_old = zero_sig;
blank_old = blank_sig;
bright_int_1_old = bright_int_1;
}
public void Reset()
{
zero_sig = true;
blank_sig = true;
ramp_sig = false;
vec_scale = x_vel = y_vel = bright = 0;
x_pos = 128 + 2;
y_pos = 192 + 2;
line_pointer = 0;
blank_old = zero_old = true;
x_vel_old = y_vel_old = 0;
bright_int_1_old = 0;
// initial line array values
draw_lines[line_pointer * 5] = x_pos;
draw_lines[line_pointer * 5 + 1] = y_pos;
line_brights[line_pointer * 3] = 0;
line_brights[line_pointer * 3 + 1] = 0;
line_brights[line_pointer * 3 + 2] = 0;
line_vis[line_pointer] = !blank_sig;
}
public void SyncState(Serializer ser)
{
ser.Sync(nameof(zero_sig), ref zero_sig);
ser.Sync(nameof(blank_sig), ref blank_sig);
ser.Sync(nameof(ramp_sig), ref ramp_sig);
ser.Sync(nameof(off_screen), ref off_screen);
ser.Sync(nameof(vec_scale), ref vec_scale);
ser.Sync(nameof(x_vel), ref x_vel);
ser.Sync(nameof(y_vel), ref y_vel);
ser.Sync(nameof(bright), ref bright);
ser.Sync(nameof(x_pos), ref x_pos);
ser.Sync(nameof(y_pos), ref y_pos);
ser.Sync(nameof(skip), ref skip);
ser.Sync(nameof(bright_int_1), ref bright_int_1);
ser.Sync(nameof(bright_int_2), ref bright_int_2);
ser.Sync(nameof(bright_int_3), ref bright_int_3);
ser.Sync(nameof(draw_lines), ref draw_lines, false);
ser.Sync(nameof(line_brights), ref line_brights, false);
ser.Sync(nameof(line_vis), ref line_vis, false);
ser.Sync(nameof(line_pointer), ref line_pointer);
ser.Sync(nameof(blank_old), ref blank_old);
ser.Sync(nameof(zero_old), ref zero_old);
ser.Sync(nameof(x_vel_old), ref x_vel_old);
ser.Sync(nameof(y_vel_old), ref y_vel_old);
ser.Sync(nameof(bright_int_1_old), ref bright_int_1_old);
ser.Sync(nameof(draw_lines_old_screen), ref draw_lines_old_screen, false);
ser.Sync(nameof(line_brights_old_screen), ref line_brights_old_screen, false);
ser.Sync(nameof(line_vis_old_screen), ref line_vis_old_screen, false);
ser.Sync(nameof(line_pointer_old_screen), ref line_pointer_old_screen);
}
}
}