Fix double height character rendering logic
This commit is contained in:
@@ -215,13 +215,27 @@ class TeletextCanvas(QWidget):
|
||||
if 0 <= p.row <= 25:
|
||||
grid[p.row] = p
|
||||
|
||||
# Pass 1: Backgrounds
|
||||
occlusion_mask = [False] * 40
|
||||
for r in range(25):
|
||||
packet = grid[r]
|
||||
self.draw_row(painter, r, packet)
|
||||
occlusion_mask = self.draw_row(painter, r, packet, draw_bg=True, draw_fg=False, occlusion_mask=occlusion_mask)
|
||||
|
||||
# Pass 2: Foregrounds
|
||||
occlusion_mask = [False] * 40
|
||||
for r in range(25):
|
||||
packet = grid[r]
|
||||
occlusion_mask = self.draw_row(painter, r, packet, draw_bg=False, draw_fg=True, occlusion_mask=occlusion_mask)
|
||||
|
||||
painter.end()
|
||||
|
||||
def draw_row(self, painter, row, packet):
|
||||
def draw_row(self, painter, row, packet, draw_bg=True, draw_fg=True, occlusion_mask=None):
|
||||
if occlusion_mask is None:
|
||||
occlusion_mask = [False] * 40
|
||||
|
||||
# Output mask for the next row
|
||||
next_occlusion_mask = [False] * 40
|
||||
|
||||
# Default State at start of row
|
||||
fg = COLORS[7] # White
|
||||
bg = COLORS[0] # Black
|
||||
@@ -229,6 +243,7 @@ class TeletextCanvas(QWidget):
|
||||
contiguous = True # Mosaic
|
||||
hold_graphics = False
|
||||
held_char = 0x20 # Space
|
||||
double_height = False
|
||||
|
||||
y = row * self.cell_h
|
||||
|
||||
@@ -248,6 +263,24 @@ class TeletextCanvas(QWidget):
|
||||
for c in range(40):
|
||||
x = c * self.cell_w
|
||||
|
||||
# If this cell is occluded by the row above, skip drawing and attribute processing?
|
||||
# Spec says "The characters in the row below are ignored."
|
||||
# Ideally we shouldn't even process attributes, but for simple renderer we just skip draw.
|
||||
# However, if we skip attribute processing, state (fg/bg) won't update.
|
||||
# Teletext attributes are serial.
|
||||
# BUT, if the row above covers it, the viewer sees the row above.
|
||||
# Does the hidden content affect the *rest* of the row?
|
||||
# Likely yes, attributes usually propagate.
|
||||
# But the spec says "ignored". Let's assume we skip *everything* for this cell visually,
|
||||
# but maybe we should technically maintain state?
|
||||
# For "Double Height" visual correctness, skipping drawing is the key.
|
||||
# We will Process attributes (to keep state consistent) but Skip Drawing if occluded.
|
||||
|
||||
# Wait, if we process attributes, we might set double_height=True for the NEXT row?
|
||||
# If this cell is occluded, it shouldn't trigger DH for the next row.
|
||||
|
||||
is_occluded = occlusion_mask[c]
|
||||
|
||||
# Decide byte value
|
||||
if row == 0 and c < 8:
|
||||
# Use generated header prefix
|
||||
@@ -274,9 +307,9 @@ class TeletextCanvas(QWidget):
|
||||
elif byte_val == 0x1D: # New BG
|
||||
bg = fg
|
||||
elif byte_val == 0x0C: # Normal Height
|
||||
pass
|
||||
double_height = False
|
||||
elif byte_val == 0x0D: # Double Height
|
||||
pass # Not implemented yet
|
||||
double_height = True
|
||||
elif byte_val == 0x19: # Contiguous Graphics
|
||||
contiguous = True
|
||||
elif byte_val == 0x1A: # Separated Graphics
|
||||
@@ -286,14 +319,33 @@ class TeletextCanvas(QWidget):
|
||||
elif byte_val == 0x1F: # Release Graphics
|
||||
hold_graphics = False
|
||||
|
||||
# Record Double Height for next row
|
||||
if double_height and not is_occluded:
|
||||
next_occlusion_mask[c] = True
|
||||
|
||||
# If occluded, do not draw anything for this cell
|
||||
if is_occluded:
|
||||
continue
|
||||
|
||||
# Draw Background
|
||||
painter.fillRect(x, y, self.cell_w, self.cell_h, bg)
|
||||
if draw_bg:
|
||||
# If double height, draw taller background
|
||||
h_bg = self.cell_h * 2 if double_height else self.cell_h
|
||||
painter.fillRect(x, y, self.cell_w, h_bg, bg)
|
||||
|
||||
# Draw Foreground
|
||||
if draw_fg:
|
||||
# Calculate height
|
||||
# For Mosaics, we use the height param.
|
||||
# For Alphanumerics, we scale the painter.
|
||||
|
||||
if is_control:
|
||||
# "Set-at" spacing attribute? Teletext control codes occupy a space
|
||||
# unless "Hold Graphics" replaces it with previous graphic char.
|
||||
if hold_graphics and graphics_mode:
|
||||
if double_height:
|
||||
self.draw_mosaic(painter, x, y, held_char, fg, contiguous, height=self.cell_h * 2)
|
||||
else:
|
||||
self.draw_mosaic(painter, x, y, held_char, fg, contiguous)
|
||||
else:
|
||||
# Draw space (nothing, since we filled BG)
|
||||
@@ -301,28 +353,45 @@ class TeletextCanvas(QWidget):
|
||||
else:
|
||||
if graphics_mode:
|
||||
# Mosaic Graphics
|
||||
h_mos = self.cell_h * 2 if double_height else self.cell_h
|
||||
if (0x20 <= byte_val <= 0x3F) or (0x60 <= byte_val <= 0x7F):
|
||||
self.draw_mosaic(painter, x, y, byte_val, fg, contiguous)
|
||||
self.draw_mosaic(painter, x, y, byte_val, fg, contiguous, height=h_mos)
|
||||
held_char = byte_val
|
||||
else:
|
||||
# Capital letter in graphics mode? Usually shows char?
|
||||
char = get_char(byte_val, self.subset_idx)
|
||||
painter.setPen(fg)
|
||||
if double_height:
|
||||
painter.save()
|
||||
painter.translate(x, y)
|
||||
painter.scale(1, 2)
|
||||
painter.drawText(QRect(0, 0, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||
painter.restore()
|
||||
else:
|
||||
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||
held_char = 0x20
|
||||
else:
|
||||
# Alphanumeric
|
||||
char = get_char(byte_val, self.subset_idx)
|
||||
painter.setPen(fg)
|
||||
if double_height:
|
||||
painter.save()
|
||||
painter.translate(x, y)
|
||||
painter.scale(1, 2)
|
||||
painter.drawText(QRect(0, 0, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||
painter.restore()
|
||||
else:
|
||||
painter.drawText(QRect(x, y, self.cell_w, self.cell_h), Qt.AlignmentFlag.AlignCenter, char)
|
||||
# Draw Cursor
|
||||
# Invert the cell at cursor position
|
||||
if self.cursor_visible and c == self.cursor_x and row == self.cursor_y:
|
||||
if draw_fg and self.cursor_visible and c == self.cursor_x and row == self.cursor_y:
|
||||
painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_Difference)
|
||||
# Difference with white creates inversion
|
||||
# Note: Cursor follows double height? Probably just the active cell.
|
||||
painter.fillRect(x, y, self.cell_w, self.cell_h, QColor(255, 255, 255))
|
||||
painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceOver)
|
||||
|
||||
return next_occlusion_mask
|
||||
def mousePressEvent(self, event):
|
||||
self.setFocus()
|
||||
# Calculate cell from mouse position
|
||||
@@ -360,7 +429,10 @@ class TeletextCanvas(QWidget):
|
||||
row = int(my / (self.cell_h * scale))
|
||||
self.set_cursor(col, row)
|
||||
|
||||
def draw_mosaic(self, painter, x, y, char_code, color, contiguous):
|
||||
def draw_mosaic(self, painter, x, y, char_code, color, contiguous, height=None):
|
||||
if height is None:
|
||||
height = self.cell_h
|
||||
|
||||
val = char_code & 0x7F
|
||||
bits = 0
|
||||
if val >= 0x20:
|
||||
@@ -368,7 +440,7 @@ class TeletextCanvas(QWidget):
|
||||
|
||||
# Grid definitions for 2x3 grid
|
||||
x_splits = [0, int(self.cell_w / 2), self.cell_w]
|
||||
y_splits = [0, int(self.cell_h / 3), int(2 * self.cell_h / 3), self.cell_h]
|
||||
y_splits = [0, int(height / 3), int(2 * height / 3), height]
|
||||
|
||||
# Block indices (col, row) for the 6 bits
|
||||
block_indices = [
|
||||
|
||||
Reference in New Issue
Block a user