1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
2022-01-02 20:29:25 +11:00

189 lines
5.0 KiB
Python
Executable File

"""
The Imlac display.
A temporary version that outputs a PPM graphics image.
The Imlac dislay X and Y registers are of size 11 bits. The most significant
6 bits are the MSB and the least significant 5 bits are the LSB. A DLXA (or
DLYA) loads the display X (or Y) register from the 10 bits of valu, with bit
10 of the X/Y register being set to 0.
The virtual display is 2048x2048 pixels, but the physical display is
1024x1024 pixels.
"""
from Globals import *
# if we don't have log.py, don't crash
try:
import log
log = log.Log('test.log', log.Log.DEBUG)
except ImportError:
def log(*args, **kwargs):
pass
# the widget version
__version__ = '0.0'
# type of events
DisplayStop = 1
################################################################################
# The actual pymlac display widget.
# This version is just a debug version that creates PPM files.
################################################################################
class Display(object):
# BackgroundColour = 'black'
# DrawColour = '#ffff88'
SYNC_HZ = 40
SYNC_40HZ_CYCLE_COUNT = int(CYCLES_PER_SECOND / SYNC_HZ)
BackgroundColour = 1
DrawColour = 0
# max coordinates of pymlac physical display
ScaleMaxX = 1024
ScaleMaxY = 1024
def __init__(self):
# create and initialise the image array
# reference .array[y*ScaleMaxX + x]
self.array = [self.BackgroundColour] * self.ScaleMaxY * self.ScaleMaxX
# set internal state
self.running = 0
self.cycle_count = 0
self.Sync40hz = 1
self.next_file_num = 0
# 'dirty' flag set after writing
self.dirty = False
log('Display: instance created')
def write(self):
"""Write display array to PPM file."""
self.next_file_num += 1
filename = 'pymlac_%06d.pbm' % self.next_file_num
with open(filename, 'wb') as handle:
# output header data
handle.write(bytes('P1\n', 'utf-8'))
handle.write(bytes('# created by pymlac %s\n' % __version__, 'utf-8'))
handle.write(bytes('%d %d\n' % (self.ScaleMaxX, self.ScaleMaxY), 'utf-8'))
# output graphics data
for v in self.array:
handle.write(bytes('%d\n' % v, 'utf-8'))
self.dirty = False
log('Display: array written to file %s' % filename)
def draw(self, x1, y1, x2, y2, dotted=False):
"""Draw a line on the screen.
x1, y1 start coordinates
x2, y2 end coordinates
dotted True if dotted line, else False (IGNORED)
Algorithm from:
http://csourcecodes.blogspot.com/2016/06/bresenhams-line-drawing-algorithm-generalized-c-program.html
"""
# convert virtual coords to physical
x1 = x1 // 2
y1 = y1 // 2
x2 = x2 // 2
y2 = y2 // 2
# invert the Y axis
y1 = self.ScaleMaxY - y1
y2 = self.ScaleMaxY - y2
# draw the line (Bresenham algorithm)
x = x1
y = y1
dx = abs(x2 - x1)
dy = abs(y2 - y1)
s1 = 1 if x2 > x1 else -1 # sign(x2 - x1)
s2 = 1 if y2 > y1 else -1 # sign(y2 - y1)
swap = False
self.array[(y-1)*self.ScaleMaxX + x - 1] = self.DrawColour
if dy > dx:
(dx, dy) = (dy, dx)
swap = True
p = 2*dy - dx
for i in range(0, dx):
self.array[(y-1)*self.ScaleMaxX + x - 1] = self.DrawColour
while p >= 0:
p = p - 2*dx
if swap:
x += s1
else:
y += s2
p = p + 2*dy
if swap:
y += s2
else:
x += s1
i += 1
# set display flag to "changed"
self.dirty = True
def clear(self):
"""Clear the display."""
log('Display: clearing the display')
# write display to next PPM file first
if self.dirty:
self.write()
self.array = [self.BackgroundColour] * self.ScaleMaxY * self.ScaleMaxX
self.dirty = False
def syncclear(self):
self.Sync40hz = 0
self.cycle_count = self.SYNC_40HZ_CYCLE_COUNT
def ready(self):
return self.Sync40hz
def tick(self, cycles):
"""Advance the internal state by given cycles."""
self.cycle_count -= cycles
if self.cycle_count <= 0:
self.Sync40hz = 1
self.cycle_count = 0
def close(self):
"""Close display, writing data if 'dirty'."""
if self.dirty:
self.write()
if __name__ == '__main__':
"""Test case - draw radial lines."""
d = Display()
granularity = 32
for x in range(0, 2048, granularity):
d.draw(x, 0, 1023, 1023)
for y in range(0, 2048, granularity):
d.draw(2048, y, 1023, 1023)
for x in range(2048, 0, -granularity):
d.draw(x, 2048, 1023, 1023)
for y in range(2048, 0, -granularity):
d.draw(0, y, 1023, 1023)
d.clear()
d.close()