Skip to content

Commit b0560fd

Browse files
authored
Merge pull request #284 from boriel/chore/add_scrview_tool
Add a simple .SCR viewer
2 parents 2db1fea + 31b0e62 commit b0560fd

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

tools/scrview.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
import pygame
6+
from typing import List, Tuple
7+
8+
9+
WIDTH = 256 # ZX Spectrum screen width in pixels
10+
HEIGHT = 192 # ZX Spectrum screen height in pixels
11+
SCALE = 4 # Scale
12+
13+
14+
# Colors
15+
BLACK = 0
16+
BLUE = 1
17+
RED = 2
18+
MAGENTA = 3
19+
GREEN = 4
20+
CYAN = 5
21+
YELLOW = 6
22+
WHITE = 7
23+
24+
BRIGHT_OFFSET = 20
25+
SCREEN_AREA_SIZE = 6144
26+
27+
28+
# PALETTE[<color>] will return the expected color. Add 0x28 to increase bright
29+
PALETTE = [
30+
(0, 0, 0),
31+
(0, 0, 0xD7),
32+
(0xD7, 0, 0),
33+
(0xD7, 0, 0xD7),
34+
(0, 0xD7, 0),
35+
(0, 0xD7, 0xD7),
36+
(0xD7, 0xD7, 0),
37+
(0xD7, 0xD7, 0xD7)
38+
]
39+
40+
41+
TABLE = None # Table of bytes to tuple of binaries
42+
43+
44+
def to_bin(x: int):
45+
result = []
46+
47+
for i in range(8):
48+
result.insert(0, x & 1)
49+
x >>= 1
50+
51+
return result
52+
53+
54+
def get_attr(data: List[int], offset) -> int:
55+
""" For a given offset in the drawing region, return the attribute.
56+
This is a bit tricky for the speccy as the screen memory is not linear
57+
"""
58+
k = (offset >> 3) & 0x300
59+
r = offset & 0xFF
60+
return data[SCREEN_AREA_SIZE + k + r]
61+
62+
63+
def get_xy_coord(offset: int) -> Tuple[int, int]:
64+
""" Given an offset, return the x, y coordinate
65+
of that byte in the display """
66+
x = (offset & 0x1F) << 3 # mod 32
67+
y0 = (offset >> 5) & 0xC0 # offset / 2048
68+
y1 = (offset >> 8) & 0x07 # offset / 256
69+
y2 = (offset >> 2) & 0x38 # offset / 8
70+
y = y0 + y1 + y2
71+
return x * SCALE, y * SCALE
72+
73+
74+
def plot_byte(screen, data: List[int], offset: int):
75+
""" Draws a pixel at the given X, Y coordinate
76+
"""
77+
global TABLE
78+
79+
byte_ = TABLE[data[offset]]
80+
attr = get_attr(data, offset)
81+
82+
ink_ = attr & 0x7
83+
paper_ = (attr >> 3) & 0x7
84+
bright = (attr >> 6) & 0x1
85+
86+
paper = tuple(x + bright for x in PALETTE[paper_])
87+
ink = tuple(x + bright for x in PALETTE[ink_])
88+
palette = [paper, ink]
89+
90+
x0, y0 = get_xy_coord(offset)
91+
92+
for x, bit_ in enumerate(byte_):
93+
screen.fill(palette[bit_], pygame.Rect(x0 + x * SCALE, y0, SCALE, SCALE))
94+
95+
96+
def paint(data: List[int]):
97+
pygame.init()
98+
screen = pygame.display.set_mode([WIDTH * SCALE, HEIGHT * SCALE])
99+
100+
for i in range(SCREEN_AREA_SIZE):
101+
plot_byte(screen, data, i)
102+
103+
pygame.display.flip()
104+
105+
# Wait for quit
106+
running = True
107+
while running:
108+
for event in pygame.event.get():
109+
if event.type == pygame.QUIT:
110+
running = False
111+
112+
pygame.quit()
113+
114+
115+
if __name__ == '__main__':
116+
# initialize Table
117+
TABLE = [to_bin(x) for x in range(256)]
118+
119+
with open(sys.argv[1], 'rb') as f:
120+
data = f.read()
121+
122+
paint(data)

0 commit comments

Comments
 (0)