refactor: improve UI rendering, show access heatmap
This commit is contained in:
parent
63c03e55fa
commit
0d3c3c28a0
9 changed files with 216 additions and 90 deletions
|
@ -1,7 +1,7 @@
|
||||||
Orao Emulator
|
Orao Emulator
|
||||||
============
|
============
|
||||||
|
|
||||||
![Screenshot](assets/screenshot.png?raw=true)
|
![Screenshot](assets/screenshot-20211017-225446.png?raw=true)
|
||||||
|
|
||||||
[Orao](https://en.wikipedia.org/wiki/Orao_%28computer%29) is a Croatian 8-bit
|
[Orao](https://en.wikipedia.org/wiki/Orao_%28computer%29) is a Croatian 8-bit
|
||||||
computer used primarily in elementary schools, as part of a computer literacy
|
computer used primarily in elementary schools, as part of a computer literacy
|
||||||
|
|
BIN
assets/screenshot-20211017-225446.png
Normal file
BIN
assets/screenshot-20211017-225446.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
79
orao.py
79
orao.py
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/python2
|
#!/usr/bin/python2
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf8 -*-
|
||||||
|
|
||||||
import pygame, numpy, sys, datetime, wave, time
|
import pygame, numpy, sys, datetime
|
||||||
from orao.cpu import CPU
|
from orao.cpu import CPU
|
||||||
from orao.keyboard import listener as orao_kbd_listener
|
from orao.keyboard import listener as orao_kbd_listener
|
||||||
from orao.video import mem_listener as video_mem_listener, terminal
|
from orao.video import mem_listener as video_mem_listener, terminal
|
||||||
|
@ -10,7 +10,7 @@ from orao.chargen import chargen_init, chargen_draw_str
|
||||||
|
|
||||||
# views
|
# views
|
||||||
from orao.views.cpu_state import CPUState
|
from orao.views.cpu_state import CPUState
|
||||||
from orao.views.heatmap import MemHeatmap
|
from orao.views.micro_mem_view import MicroMemView
|
||||||
|
|
||||||
MEM_LOAD_PRG = None
|
MEM_LOAD_PRG = None
|
||||||
|
|
||||||
|
@ -36,51 +36,82 @@ chargen_init(cpu.memory[0xE000:])
|
||||||
|
|
||||||
# views
|
# views
|
||||||
view_cpu_state = CPUState()
|
view_cpu_state = CPUState()
|
||||||
view_heatmap = MemHeatmap()
|
|
||||||
|
# ram zero page & stack
|
||||||
|
view_zp = MicroMemView(start_addr=0x0000, size=0x0200, caption='ZP & stack', disp_width=64)
|
||||||
|
view_zp.listen(cpu)
|
||||||
|
|
||||||
|
# user ram view
|
||||||
|
view_ram = MicroMemView(start_addr=0x0200, size=0x5E00, caption='RAM', disp_width=128)
|
||||||
|
view_ram.listen(cpu)
|
||||||
|
|
||||||
|
# rom access view
|
||||||
|
view_rom = MicroMemView(start_addr=0xC000, size=0x4000, caption='ROM', disp_width=256)
|
||||||
|
view_rom.listen(cpu)
|
||||||
|
|
||||||
|
view_screen = MicroMemView(start_addr=0x6000, size=0x2000, disp_width=32)
|
||||||
|
view_screen.listen(cpu)
|
||||||
|
|
||||||
# status lines
|
# status lines
|
||||||
status_line = pygame.Surface((64 * 8, 3*8), depth=24)
|
status_line = pygame.Surface((64 * 8, 4*8), depth=24)
|
||||||
status_line.fill((0, 0, 0))
|
status_line.fill((0, 0, 0))
|
||||||
chargen_draw_str(status_line, 0, 0, 'Orao Emulator v0.1')
|
chargen_draw_str(status_line, 0, 0, 'Orao Emulator v0.1')
|
||||||
|
|
||||||
# setup screen
|
# setup screen
|
||||||
screen = pygame.display.set_mode((
|
screen = pygame.display.set_mode((
|
||||||
terminal.get_width() * 2 + 1 + int(max(view_heatmap.width, view_cpu_state.width*1.8)),
|
terminal.get_width() * 2 + 2 + int(max(view_rom.width, view_cpu_state.width * 2)),
|
||||||
terminal.get_height() * 2 + 3*8 + 2
|
terminal.get_height() * 2 + 3*8 + 2 + 30
|
||||||
))
|
))
|
||||||
pygame.display.set_caption('Orao Emulator v0.1')
|
pygame.display.set_caption('Orao Emulator v0.1')
|
||||||
|
|
||||||
|
lc = (0xff, 0xcc, 0x00)
|
||||||
|
chargen_draw_str(status_line, 0, 16, 'F12:', color=lc)
|
||||||
|
chargen_draw_str(status_line, 24+8, 16, ' SCREENSHOT')
|
||||||
|
|
||||||
if MEM_LOAD_PRG is not None:
|
if MEM_LOAD_PRG is not None:
|
||||||
chargen_draw_str(status_line, 0, 16, 'F8:', color=(0, 0, 0), bg=(0, 255, 0))
|
chargen_draw_str(status_line, 0, 24, 'F8:', color=lc)
|
||||||
chargen_draw_str(status_line, 24, 16, ' %s' % MEM_LOAD_PRG)
|
chargen_draw_str(status_line, 24, 24, ' %s' % MEM_LOAD_PRG)
|
||||||
|
|
||||||
def render_frame():
|
def render_frame(frame_time_ms):
|
||||||
view_cpu_state.render(cpu)
|
view_cpu_state.render(cpu, frame_time_ms)
|
||||||
view_heatmap.render(cpu)
|
view_zp.render(cpu, frame_time_ms)
|
||||||
|
view_ram.render(cpu, frame_time_ms)
|
||||||
|
view_rom.render(cpu, frame_time_ms)
|
||||||
|
view_screen.render(cpu, frame_time_ms)
|
||||||
|
|
||||||
# blit
|
# blit
|
||||||
screen.fill((0, 0, 0))
|
screen.fill((0, 0, 0))
|
||||||
screen.blit(pygame.transform.smoothscale(terminal, (512, 512)), [0, 0])
|
screen.blit(pygame.transform.scale(terminal, (512, 512)), [0, 0])
|
||||||
chargen_draw_str(status_line, 0, 8, 'Speed: {0:.2f} MHz'.format(ratio))
|
chargen_draw_str(status_line, 0, 8, 'Speed: {0:.2f} MHz'.format(ratio))
|
||||||
screen.blit(status_line, [0, 512+1])
|
screen.blit(status_line, [0, 512+1])
|
||||||
lsx = 512 + 1
|
x = 512 + 1
|
||||||
lsy = 0
|
y = 0
|
||||||
_, lsy = view_cpu_state.blit(screen, [lsx, lsy], scale=1.8)
|
cx, y = view_cpu_state.blit(screen, [x, y], scale=2)
|
||||||
|
|
||||||
lsy += 1
|
y += 5
|
||||||
view_heatmap.blit(screen, [lsx, lsy])
|
x2, y2 = view_zp.blit(screen, [x, y], scale=4)
|
||||||
|
y2 += 5
|
||||||
|
_, y2 = view_ram.blit(screen, [x, y2], scale=2)
|
||||||
|
y2 += 5
|
||||||
|
_, _ = view_rom.blit(screen, [x, y2], scale=1)
|
||||||
|
|
||||||
|
screen.blit(pygame.transform.scale(view_screen.read_map.surf, (512,512)), [0,0])
|
||||||
|
screen.blit(pygame.transform.scale(view_screen.write_map.surf, (512,512)), [0,0])
|
||||||
|
|
||||||
# finish rendering
|
# finish rendering
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
before, previous_loop_cycles = datetime.datetime.now(), cpu.cycles
|
before, previous_loop_cycles = datetime.datetime.now(), cpu.cycles
|
||||||
time_elapsed = lambda: (datetime.datetime.now()-before).microseconds + 1
|
|
||||||
|
|
||||||
for i in range(5000):
|
for i in range(5000):
|
||||||
cpu.step()
|
cpu.step()
|
||||||
|
|
||||||
|
time_elapsed = (datetime.datetime.now()-before).microseconds + 1
|
||||||
|
clock.tick()
|
||||||
|
|
||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
running = False
|
running = False
|
||||||
|
@ -117,21 +148,25 @@ while running:
|
||||||
# HACK: reset stack pointer
|
# HACK: reset stack pointer
|
||||||
cpu.sp = 241
|
cpu.sp = 241
|
||||||
|
|
||||||
|
if pkeys[pygame.K_F12]:
|
||||||
|
now = datetime.datetime.now() # current date and time
|
||||||
|
pygame.image.save(screen, "assets/screenshot-%s.png" % now.strftime("%Y%m%d-%H%M%S"))
|
||||||
|
|
||||||
if event.type == pygame.USEREVENT + 1:
|
if event.type == pygame.USEREVENT + 1:
|
||||||
render_frame()
|
render_frame(clock.get_time())
|
||||||
|
|
||||||
cpu.tape_out = None if cpu.cycles - cpu.last_sound_cycles > 20000 else cpu.tape_out
|
cpu.tape_out = None if cpu.cycles - cpu.last_sound_cycles > 20000 else cpu.tape_out
|
||||||
|
|
||||||
if len(cpu.sndbuf) > 4096 or cpu.sndbuf and cpu.cycles - cpu.last_sound_cycles > 20000:
|
if len(cpu.sndbuf) > 4096 or cpu.sndbuf and cpu.cycles - cpu.last_sound_cycles > 20000:
|
||||||
while cpu.channel.get_queue():
|
while cpu.channel.get_queue():
|
||||||
if time_elapsed() > 10000: break
|
if time_elapsed > 10000: break
|
||||||
|
|
||||||
cpu.channel.queue(pygame.sndarray.make_sound(numpy.uint8(cpu.sndbuf)))
|
cpu.channel.queue(pygame.sndarray.make_sound(numpy.uint8(cpu.sndbuf)))
|
||||||
cpu.sndbuf = []
|
cpu.sndbuf = []
|
||||||
|
|
||||||
overshoot = cpu.cycles - previous_loop_cycles - time_elapsed()
|
overshoot = cpu.cycles - previous_loop_cycles - time_elapsed
|
||||||
pygame.time.wait((overshoot > 0) * overshoot // 1000) # Pričekaj da budemo cycle exact
|
pygame.time.wait((overshoot > 0) * overshoot // 1000) # Pričekaj da budemo cycle exact
|
||||||
|
|
||||||
ratio = 1.0 * (cpu.cycles - previous_loop_cycles) / time_elapsed()
|
ratio = 1.0 * (cpu.cycles - previous_loop_cycles) / time_elapsed
|
||||||
|
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
|
|
53
orao/views/access_map.py
Normal file
53
orao/views/access_map.py
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
from .view import View
|
||||||
|
|
||||||
|
# mark accessed locations
|
||||||
|
|
||||||
|
class AccessMap(View):
|
||||||
|
decay_locations = []
|
||||||
|
|
||||||
|
def __init__(self, size=0x5F00, start_addr=0, disp_width=256, color=(255, 0, 0)):
|
||||||
|
self.start_addr = start_addr
|
||||||
|
self.size = size
|
||||||
|
self.disp_width = disp_width
|
||||||
|
|
||||||
|
dims = (disp_width, size / disp_width)
|
||||||
|
self.init_surface(pygame.Surface(dims, pygame.SRCALPHA, depth=32))
|
||||||
|
r,g,b = color
|
||||||
|
self.surf.fill((r, g, b, 0))
|
||||||
|
self.writes = []
|
||||||
|
|
||||||
|
def render(self, cpu, frame_time_ms):
|
||||||
|
# decay alfa
|
||||||
|
decay = int(frame_time_ms*256/500)
|
||||||
|
new_decay_locations = []
|
||||||
|
alpha = pygame.surfarray.pixels_alpha(self.surf)
|
||||||
|
|
||||||
|
for w in self.decay_locations:
|
||||||
|
v = alpha[w]
|
||||||
|
if v > 0:
|
||||||
|
nv = max(v-decay,0)
|
||||||
|
alpha[w] = nv
|
||||||
|
if nv > 0:
|
||||||
|
new_decay_locations.append(w)
|
||||||
|
|
||||||
|
# mark new writes
|
||||||
|
for w in self.writes:
|
||||||
|
alpha[w] = 192
|
||||||
|
new_decay_locations.append(w)
|
||||||
|
|
||||||
|
alpha = None
|
||||||
|
self.writes = []
|
||||||
|
self.decay_locations = new_decay_locations
|
||||||
|
|
||||||
|
def mem_listener(self, addr, val, cpu):
|
||||||
|
if addr < self.start_addr:
|
||||||
|
return
|
||||||
|
|
||||||
|
addr -= self.start_addr
|
||||||
|
if addr >= self.size:
|
||||||
|
return
|
||||||
|
|
||||||
|
y, x = divmod(addr, self.disp_width)
|
||||||
|
self.writes.append((x, y))
|
|
@ -1,35 +1,26 @@
|
||||||
import pygame
|
import pygame
|
||||||
|
from .view import View
|
||||||
from ..chargen import chargen_draw_str
|
from ..chargen import chargen_draw_str
|
||||||
|
|
||||||
class CPUState:
|
|
||||||
surf = None
|
class CPUState(View):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.surf = pygame.Surface((8 * 8, 6 * 8), depth=24)
|
self.init_surface(pygame.Surface((2 * 8 * 8, 3 * 8), depth=24))
|
||||||
self.width = self.surf.get_width()
|
#self.set_smooth_scale()
|
||||||
self.height = self.surf.get_height()
|
|
||||||
self.surf.fill((0, 0, 0))
|
|
||||||
|
|
||||||
def scale(self, f):
|
def draw_text(self, x, y, text, color=(0, 255, 0)):
|
||||||
return pygame.transform.smoothscale(self.surf, (int(self.width * f), int(self.height * f)))
|
chargen_draw_str(self.surf, x, y, text, color=color)
|
||||||
|
|
||||||
def render(self, cpu):
|
def render(self, cpu, frame_time_ms):
|
||||||
lc = (0xff, 0xcc, 0x00)
|
lc = (0xff, 0xcc, 0x00)
|
||||||
chargen_draw_str(self.surf, 0, 0*8, 'A X Y', color=lc)
|
self.draw_text(0, 0 * 8, 'A X Y', color=lc)
|
||||||
chargen_draw_str(self.surf, 0, 1*8, '%02X %02X %02X' % (cpu.a, cpu.x, cpu.y))
|
self.draw_text(0, 1 * 8, '%02X %02X %02X' % (cpu.a, cpu.x, cpu.y))
|
||||||
|
|
||||||
chargen_draw_str(self.surf, 0, 2*8, 'PC:', color=lc)
|
self.draw_text(0, 2 * 8, 'PC:', color=lc)
|
||||||
chargen_draw_str(self.surf, 0, 3*8, 'SP:', color=lc)
|
self.draw_text(8 * 8, 2 * 8, 'SP:', color=lc)
|
||||||
chargen_draw_str(self.surf, 4*8, 2*8, '%04X' % cpu.pc)
|
self.draw_text(3 * 8, 2 * 8, '%04X' % cpu.pc)
|
||||||
chargen_draw_str(self.surf, 4*8, 3*8, '%04X' % cpu.sp)
|
self.draw_text(11 * 8, 2 * 8, '%04X' % cpu.sp)
|
||||||
|
|
||||||
chargen_draw_str(self.surf, 0, 4*8, "NVssDIZC", color=lc)
|
self.draw_text(8 * 8, 0 * 8, "NVssDIZC", color=lc)
|
||||||
chargen_draw_str(self.surf, 0, 5*8, "{0:b}".format(cpu.flags))
|
self.draw_text(8 * 8, 1 * 8, "{0:b}".format(cpu.flags))
|
||||||
|
|
||||||
def blit(self, screen, pos, scale=1):
|
|
||||||
if scale == 1:
|
|
||||||
screen.blit(self.surf, pos)
|
|
||||||
return (pos[0], pos[1] + self.height)
|
|
||||||
else:
|
|
||||||
screen.blit(self.scale(scale), pos)
|
|
||||||
return (pos[0], pos[1] + int(self.height*scale))
|
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import pygame
|
import pygame
|
||||||
import numpy
|
import numpy
|
||||||
from ..chargen import chargen_draw_str
|
from .view import View
|
||||||
|
|
||||||
SURF_SCALE = 2
|
|
||||||
|
|
||||||
palette = []
|
palette = []
|
||||||
# below chars
|
# below chars
|
||||||
|
@ -12,51 +10,24 @@ palette += [(i * 2, 255, 0) for i in range(128 - 32)]
|
||||||
# other
|
# other
|
||||||
palette += [(i * 2, 0, 255) for i in range(128)]
|
palette += [(i * 2, 0, 255) for i in range(128)]
|
||||||
|
|
||||||
|
# displays memory locations as colors of palette based on value
|
||||||
|
|
||||||
class MemHeatmap:
|
class MemHeatmap(View):
|
||||||
dims = (32, 192)
|
|
||||||
surf = None
|
surf = None
|
||||||
tick_color = (0xff, 0xcc, 0x00)
|
|
||||||
label_color = (0xff, 0xcc, 0x00)
|
|
||||||
tick_size = 2
|
|
||||||
start_addr = 0
|
start_addr = 0
|
||||||
|
size = 0
|
||||||
|
|
||||||
def __init__(self, size=16, start_addr=0):
|
def __init__(self, size=0x1000, start_addr=0, disp_width=256):
|
||||||
# mem view surface
|
|
||||||
self.start_addr = start_addr
|
self.start_addr = start_addr
|
||||||
self.dims = (32, size * 8)
|
self.size = size
|
||||||
self.surf = pygame.Surface(self.dims, depth=8)
|
|
||||||
|
dims = (disp_width, size / disp_width)
|
||||||
|
self.init_surface(pygame.Surface(dims, depth=8))
|
||||||
self.surf.set_palette(palette)
|
self.surf.set_palette(palette)
|
||||||
|
|
||||||
# label surface
|
def render(self, cpu, frame_time_ms):
|
||||||
self.surf_labels = pygame.Surface((2 * 8 + self.tick_size, size * 8 * 2), depth=24)
|
w, h = self.dims()
|
||||||
|
mem = cpu.memory[self.start_addr:self.start_addr + (w * h)]
|
||||||
self.width = self.surf.get_width() * SURF_SCALE
|
arr = numpy.reshape(mem, (h, w))
|
||||||
self.width += self.surf_labels.get_width()
|
|
||||||
|
|
||||||
self.height = self.surf.get_height()
|
|
||||||
self.surf.fill((0, 0, 0))
|
|
||||||
self.surf_labels.fill((0, 0, 0))
|
|
||||||
|
|
||||||
# build labels
|
|
||||||
for i in range(0, size):
|
|
||||||
y = i * 8 * SURF_SCALE
|
|
||||||
chargen_draw_str(self.surf_labels, 0, y, '%02X' % i, color=self.label_color)
|
|
||||||
# draw ticks
|
|
||||||
for t in range(0, self.tick_size):
|
|
||||||
self.surf_labels.set_at((16 + t, y), self.tick_color)
|
|
||||||
|
|
||||||
def scale(self, f):
|
|
||||||
return pygame.transform.scale(self.surf, (int(self.surf.get_width() * f), int(self.surf.get_height() * f)))
|
|
||||||
|
|
||||||
def render(self, cpu):
|
|
||||||
w, h = self.dims
|
|
||||||
arr = numpy.reshape(cpu.memory[self.start_addr:(w * h)], (h, w))
|
|
||||||
pygame.surfarray.blit_array(self.surf, numpy.transpose(arr))
|
pygame.surfarray.blit_array(self.surf, numpy.transpose(arr))
|
||||||
|
|
||||||
def blit(self, screen, pos, scale=1):
|
|
||||||
x, y = pos
|
|
||||||
screen.blit(self.surf_labels, pos)
|
|
||||||
x += self.surf_labels.get_width()
|
|
||||||
screen.blit(self.scale(SURF_SCALE), [x, y])
|
|
||||||
return [x + self.width, y + self.height]
|
|
||||||
|
|
36
orao/views/micro_mem_view.py
Normal file
36
orao/views/micro_mem_view.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
from .heatmap import MemHeatmap
|
||||||
|
from .access_map import AccessMap
|
||||||
|
from .text_label import TextLabel
|
||||||
|
|
||||||
|
class MicroMemView:
|
||||||
|
mem_map = None
|
||||||
|
read_map = None
|
||||||
|
write_map = None
|
||||||
|
|
||||||
|
def __init__(self, size=0x1000, start_addr=0, caption='Unnamed', disp_width=256):
|
||||||
|
self.mem_map = MemHeatmap(start_addr=start_addr, size=size, disp_width=disp_width)
|
||||||
|
self.mem_map.surf.set_alpha(128)
|
||||||
|
self.caption = TextLabel("%04X-%04X: %s (%d bpl)" % (start_addr, start_addr+size-1, caption, disp_width))
|
||||||
|
|
||||||
|
self.read_map = AccessMap(start_addr=start_addr, size=size, disp_width=disp_width, color=(0,128+64,255))
|
||||||
|
self.write_map = AccessMap(start_addr=start_addr, size=size, disp_width=disp_width)
|
||||||
|
self.width = self.mem_map.width
|
||||||
|
self.height = self.mem_map.height
|
||||||
|
|
||||||
|
def render(self, cpu, frame_time_ms):
|
||||||
|
self.mem_map.render(cpu, frame_time_ms)
|
||||||
|
self.read_map.render(cpu, frame_time_ms)
|
||||||
|
self.write_map.render(cpu, frame_time_ms)
|
||||||
|
|
||||||
|
def blit(self, screen, pos, scale=1):
|
||||||
|
x,y = pos
|
||||||
|
_,y = self.caption.blit(screen, pos)
|
||||||
|
self.mem_map.blit(screen, (x,y), scale=scale)
|
||||||
|
self.read_map.blit(screen, (x,y), scale=scale)
|
||||||
|
x, y = self.write_map.blit(screen, (x,y), scale=scale)
|
||||||
|
return [x, y]
|
||||||
|
|
||||||
|
def listen(self, cpu):
|
||||||
|
cpu.store_mem_listeners.append(self.write_map.mem_listener)
|
||||||
|
cpu.read_mem_listeners.append(self.read_map.mem_listener)
|
9
orao/views/text_label.py
Normal file
9
orao/views/text_label.py
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import pygame
|
||||||
|
from .view import View
|
||||||
|
from ..chargen import chargen_draw_str
|
||||||
|
|
||||||
|
|
||||||
|
class TextLabel(View):
|
||||||
|
def __init__(self, text):
|
||||||
|
self.init_surface(pygame.Surface((len(text)*8, 8), depth=24))
|
||||||
|
chargen_draw_str(self.surf, 0,0, text, color=(0xff, 0xcc, 0x00))
|
31
orao/views/view.py
Normal file
31
orao/views/view.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
class View:
|
||||||
|
surf = None
|
||||||
|
scale_method = pygame.transform.scale
|
||||||
|
|
||||||
|
def init_surface(self, surf):
|
||||||
|
self.surf = surf
|
||||||
|
self.width = self.surf.get_width()
|
||||||
|
self.height = self.surf.get_height()
|
||||||
|
|
||||||
|
def set_smooth_scale(self):
|
||||||
|
self.scale_method = pygame.transform.smoothscale
|
||||||
|
|
||||||
|
def scaled_surf(self, f):
|
||||||
|
return self.scale_method(self.surf, (int(self.width * f), int(self.surf.get_height() * f)))
|
||||||
|
|
||||||
|
def dims(self):
|
||||||
|
return self.width, self.height
|
||||||
|
|
||||||
|
def blit(self, screen, pos, scale=1):
|
||||||
|
if self.surf is None:
|
||||||
|
return pos
|
||||||
|
|
||||||
|
# if scale == 1:
|
||||||
|
# screen.blit(self.surf, pos)
|
||||||
|
# else:
|
||||||
|
screen.blit(self.scaled_surf(scale), pos)
|
||||||
|
|
||||||
|
x, y = pos
|
||||||
|
return [int(x + self.width * scale), int(y + self.height * scale)]
|
Loading…
Reference in a new issue