1
0
mirror of https://github.com/rzzzwilson/pymlac.git synced 2025-06-10 09:32:41 +00:00
2016-06-08 18:46:06 +07:00

220 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
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 display is 2048x2048 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 display
ScaleMaxX = 2048
ScaleMaxY = 2048
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.ppm' % 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)
"""
log('Display: drawing (%d,%d) to (%d,%d)' % (x1, y1, x2, y2))
self.dirty = True
# draw a straight line using Bresenam
self.bresenham(x1, y1, x2, y2)
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()
# original algorithm from:
# http://www.idav.ucdavis.edu/education/GraphicsNotes/Bresenhams-Algorithm.pdf
# Let ∆x = x2 x1
# Let ∆y = y2 y1
# Let j = y1
# Let ε = ∆y ∆x
#
# for i = x1 to x21
# illuminate (i, j)
# if (ε ≥ 0)
# j += 1
# ε = ∆x
# end if
# i += 1
# ε += ∆y
# next i
#
# finish
def bresenham(self, x1, y1, x2, y2):
"""Bresenham algorithm to draw from (x1,y1) to (x2,y2)."""
dx = x2 - x1
dy = y2 - y1
# Determine how steep the line is
is_steep = abs(dy) > abs(dx)
# Rotate line
if is_steep:
x1, y1 = y1, x1
x2, y2 = y2, x2
# Swap start and end points if necessary and store swap state
swapped = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
swapped = True
# Recalculate differentials
dx = x2 - x1
dy = y2 - y1
# Calculate error
error = int(dx / 2.0)
ystep = 1 if y1 < y2 else -1
# Iterate over bounding box generating points between start and end
y = y1
for x in range(x1, x2 + 1):
(xx, yy) = (y, x) if is_steep else (x, y)
yyy = self.ScaleMaxX - yy
self.array[yyy*self.ScaleMaxX + xx] = self.DrawColour
error -= abs(dy)
if error < 0:
y += ystep
error += dx
if __name__ == '__main__':
"""Test case - draw radial lines."""
d = Display()
d.draw(0, 0, 1023, 1023)
d.draw(255, 0, 1023-255, 1023)
d.draw(511, 0, 1023-511, 1023)
d.draw(767, 0, 1023-767, 1023)
d.draw(1023, 0, 0, 1023)
d.draw(0, 255, 1023, 1023-255)
d.draw(0, 511, 1023, 1023-511)
d.draw(0, 767, 1023, 1023-767)
d.clear()
d.draw(0, 0, 1023, 1023)
d.draw(255, 0, 1023-255, 1023)
d.draw(511, 0, 1023-511, 1023)
d.draw(767, 0, 1023-767, 1023)
d.draw(1023, 0, 0, 1023)
d.draw(0, 255, 1023, 1023-255)
d.draw(0, 511, 1023, 1023-511)
d.draw(0, 767, 1023, 1023-767)
d.close()