def draw_step(self, x0, y0, sx, sy, plot, goback): """ Make a DRAW step, drawing a line and reurning if requested. """ scale = self.draw_scale rotate = self.draw_angle aspect = self.screen.mode.pixel_aspect yfac = aspect[1] / (1.*aspect[0]) x1 = (scale*sx) / 4 y1 = (scale*sy) / 4 if rotate == 0 or rotate == 360: pass elif rotate == 90: x1, y1 = int(y1*yfac), -int(x1//yfac) elif rotate == 180: x1, y1 = -x1, -y1 elif rotate == 270: x1, y1 = -int(y1*yfac), int(x1//yfac) else: fx, fy = fp.Single.from_int(x1), fp.Single.from_int(y1) phi = fp.mul(fp.Single.from_int(rotate), deg_to_rad) sinr, cosr = fp.sin(phi), fp.cos(phi) fxfac = fp.div(fp.Single.from_int(aspect[0]), fp.Single.from_int(aspect[1])) fx, fy = fp.add(fp.mul(cosr,fx), fp.div(fp.mul(sinr,fy), fxfac)), fp.mul(fp.sub(fp.mul(cosr,fy), fxfac), fp.mul(sinr,fx)) x1, y1 = fx.round_to_int(), fy.round_to_int() y1 += y0 x1 += x0 if plot: self.draw_line(x0, y0, x1, y1, self.last_attr) self.last_point = x1, y1 if goback: self.last_point = x0, y0
def draw_step(self, x0, y0, sx, sy, plot, goback): """ Make a DRAW step, drawing a line and reurning if requested. """ scale = self.draw_scale rotate = self.draw_angle aspect = self.screen.mode.pixel_aspect yfac = aspect[1] / (1. * aspect[0]) x1 = (scale * sx) / 4 y1 = (scale * sy) / 4 if rotate == 0 or rotate == 360: pass elif rotate == 90: x1, y1 = int(y1 * yfac), -int(x1 // yfac) elif rotate == 180: x1, y1 = -x1, -y1 elif rotate == 270: x1, y1 = -int(y1 * yfac), int(x1 // yfac) else: fx, fy = fp.Single.from_int(x1), fp.Single.from_int(y1) phi = fp.mul(fp.Single.from_int(rotate), deg_to_rad) sinr, cosr = fp.sin(phi), fp.cos(phi) fxfac = fp.div(fp.Single.from_int(aspect[0]), fp.Single.from_int(aspect[1])) fx, fy = fp.add(fp.mul(cosr, fx), fp.div(fp.mul(sinr, fy), fxfac)), fp.mul( fp.sub(fp.mul(cosr, fy), fxfac), fp.mul(sinr, fx)) x1, y1 = fx.round_to_int(), fy.round_to_int() y1 += y0 x1 += x0 if plot: self.draw_line(x0, y0, x1, y1, self.last_attr) self.last_point = x1, y1 if goback: self.last_point = x0, y0
def value_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep( right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack( fp.div( fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack( vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left, right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not ( vartypes.gt(left, right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep( vartypes.gt(left, right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left, right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right)) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right)) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) elif op == tk.EQV: return vartypes.twoscomp_to_int(~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right))) elif op == tk.IMP: return vartypes.twoscomp_to_int((~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right)) else: raise error.RunError(error.STX)
def get_window_logical(self, x, y): """ Convert physical to logical coordinates. """ x, y = fp.Single.from_int(x), fp.Single.from_int(y) if self.window: scalex, scaley, offsetx, offsety = self.window return (fp.div(fp.sub(x, offsetx), scalex), fp.div(fp.sub(y, offsety), scaley)) else: return x, y
def vdiv(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right)))) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))))
def circle(self, lcoord, r, start, stop, c, aspect): """ Draw a circle, ellipse, arc or sector (CIRCLE). """ x0, y0 = self.view_coords(*self.get_window_physical(*lcoord)) c = self.get_attr_index(c) if aspect == None: aspect = fp.div( fp.Single.from_int(self.screen.mode.pixel_aspect[0]), fp.Single.from_int(self.screen.mode.pixel_aspect[1]), ) if aspect.equals(aspect.one): rx, _ = self.get_window_scale(r, fp.Single.zero) ry = rx elif aspect.gt(aspect.one): _, ry = self.get_window_scale(fp.Single.zero, r) rx = fp.div(r, aspect).round_to_int() else: rx, _ = self.get_window_scale(r, fp.Single.zero) ry = fp.mul(r, aspect).round_to_int() start_octant, start_coord, start_line = -1, -1, False if start: start = fp.unpack(vartypes.pass_single_keep(start)) start_octant, start_coord, start_line = get_octant(start, rx, ry) stop_octant, stop_coord, stop_line = -1, -1, False if stop: stop = fp.unpack(vartypes.pass_single_keep(stop)) stop_octant, stop_coord, stop_line = get_octant(stop, rx, ry) if aspect.equals(aspect.one): self.draw_circle(x0, y0, rx, c, start_octant, start_coord, start_line, stop_octant, stop_coord, stop_line) else: startx, starty, stopx, stopy = -1, -1, -1, -1 if start != None: startx = abs(fp.mul(fp.Single.from_int(rx), fp.cos(start)).round_to_int()) starty = abs(fp.mul(fp.Single.from_int(ry), fp.sin(start)).round_to_int()) if stop != None: stopx = abs(fp.mul(fp.Single.from_int(rx), fp.cos(stop)).round_to_int()) stopy = abs(fp.mul(fp.Single.from_int(ry), fp.sin(stop)).round_to_int()) self.draw_ellipse( x0, y0, rx, ry, c, start_octant / 2, startx, starty, start_line, stop_octant / 2, stopx, stopy, stop_line, ) self.last_attr = c self.last_point = x0, y0
def circle(self, lcoord, r, start, stop, c, aspect): """ Draw a circle, ellipse, arc or sector (CIRCLE). """ x0, y0 = self.view_coords(*self.get_window_physical(*lcoord)) c = self.get_attr_index(c) if aspect is None: aspect = fp.div( fp.Single.from_int(self.screen.mode.pixel_aspect[0]), fp.Single.from_int(self.screen.mode.pixel_aspect[1])) if aspect.equals(aspect.one): rx, _ = self.get_window_scale(r, fp.Single.zero) ry = rx elif aspect.gt(aspect.one): _, ry = self.get_window_scale(fp.Single.zero, r) rx = fp.div(r, aspect).round_to_int() else: rx, _ = self.get_window_scale(r, fp.Single.zero) ry = fp.mul(r, aspect).round_to_int() start_octant, start_coord, start_line = -1, -1, False if start: start = fp.unpack(vartypes.pass_single_keep(start)) start_octant, start_coord, start_line = get_octant(start, rx, ry) stop_octant, stop_coord, stop_line = -1, -1, False if stop: stop = fp.unpack(vartypes.pass_single_keep(stop)) stop_octant, stop_coord, stop_line = get_octant(stop, rx, ry) if aspect.equals(aspect.one): self.draw_circle(x0, y0, rx, c, start_octant, start_coord, start_line, stop_octant, stop_coord, stop_line) else: startx, starty, stopx, stopy = -1, -1, -1, -1 if start is not None: startx = abs( fp.mul(fp.Single.from_int(rx), fp.cos(start)).round_to_int()) starty = abs( fp.mul(fp.Single.from_int(ry), fp.sin(start)).round_to_int()) if stop is not None: stopx = abs( fp.mul(fp.Single.from_int(rx), fp.cos(stop)).round_to_int()) stopy = abs( fp.mul(fp.Single.from_int(ry), fp.sin(stop)).round_to_int()) self.draw_ellipse(x0, y0, rx, ry, c, start_octant / 2, startx, starty, start_line, stop_octant / 2, stopx, stopy, stop_line) self.last_attr = c self.last_point = x0, y0
def value_operator(op, left, right): """ Get value of binary operator expression. """ if op == tk.O_CARET: return vcaret(left, right) elif op == tk.O_TIMES: return vtimes(left, right) elif op == tk.O_DIV: return vdiv(left, right) elif op == tk.O_INTDIV: return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).apply_carry().ifloor()) elif op == tk.MOD: numerator = vartypes.pass_int_unpack(right) if numerator == 0: # simulate division by zero return fp.pack(fp.div(fp.unpack(vartypes.pass_single_keep(left)).ifloor(), fp.unpack(vartypes.pass_single_keep(right)).ifloor()).ifloor()) return vartypes.pack_int(vartypes.pass_int_unpack(left) % numerator) elif op == tk.O_PLUS: return vplus(left, right) elif op == tk.O_MINUS: return vartypes.number_add(left, vartypes.number_neg(right)) elif op == tk.O_GT: return vartypes.bool_to_int_keep(vartypes.gt(left,right)) elif op == tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.equals(left, right)) elif op == tk.O_LT: return vartypes.bool_to_int_keep(not(vartypes.gt(left,right) or vartypes.equals(left, right))) elif op == tk.O_GT + tk.O_EQ: return vartypes.bool_to_int_keep(vartypes.gt(left,right) or vartypes.equals(left, right)) elif op == tk.O_LT + tk.O_EQ: return vartypes.bool_to_int_keep(not vartypes.gt(left,right)) elif op == tk.O_LT + tk.O_GT: return vartypes.bool_to_int_keep(not vartypes.equals(left, right)) elif op == tk.AND: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) & vartypes.pass_twoscomp(right) ) elif op == tk.OR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) | vartypes.pass_twoscomp(right) ) elif op == tk.XOR: return vartypes.twoscomp_to_int( vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right) ) elif op == tk.EQV: return vartypes.twoscomp_to_int( ~(vartypes.pass_twoscomp(left) ^ vartypes.pass_twoscomp(right)) ) elif op == tk.IMP: return vartypes.twoscomp_to_int( (~vartypes.pass_twoscomp(left)) | vartypes.pass_twoscomp(right) ) else: raise error.RunError(error.STX)
def set_window(self, fx0, fy0, fx1, fy1, cartesian=True): """ Set the logical coordinate window (WINDOW). """ if fy0.gt(fy1): fy0, fy1 = fy1, fy0 if fx0.gt(fx1): fx0, fx1 = fx1, fx0 if cartesian: fy0, fy1 = fy1, fy0 left, top, right, bottom = self.get_view() x0, y0 = fp.Single.zero, fp.Single.zero x1, y1 = fp.Single.from_int(right-left), fp.Single.from_int(bottom-top) scalex = fp.div(fp.sub(x1, x0), fp.sub(fx1,fx0)) scaley = fp.div(fp.sub(y1, y0), fp.sub(fy1,fy0)) offsetx = fp.sub(x0, fp.mul(fx0,scalex)) offsety = fp.sub(y0, fp.mul(fy0,scaley)) self.window = scalex, scaley, offsetx, offsety self.window_bounds = fx0, fy0, fx1, fy1, cartesian
def set_window(self, fx0, fy0, fx1, fy1, cartesian=True): """ Set the logical coordinate window (WINDOW). """ if fy0.gt(fy1): fy0, fy1 = fy1, fy0 if fx0.gt(fx1): fx0, fx1 = fx1, fx0 if cartesian: fy0, fy1 = fy1, fy0 left, top, right, bottom = self.get_view() x0, y0 = fp.Single.zero, fp.Single.zero x1, y1 = fp.Single.from_int(right - left), fp.Single.from_int(bottom - top) scalex = fp.div(fp.sub(x1, x0), fp.sub(fx1, fx0)) scaley = fp.div(fp.sub(y1, y0), fp.sub(fy1, fy0)) offsetx = fp.sub(x0, fp.mul(fx0, scalex)) offsety = fp.sub(y0, fp.mul(fy0, scaley)) self.window = scalex, scaley, offsetx, offsety self.window_bounds = fx0, fy0, fx1, fy1, cartesian
def get_random_int(n): """ Get a value from the random number generator (int argument). """ if n < 0: n = -n while n < 2**23: n *= 2 state.basic_state.rnd_seed = n if n != 0: state.basic_state.rnd_seed = (state.basic_state.rnd_seed*rnd_a + rnd_c) % rnd_period # rnd_seed/rnd_period return fp.pack(fp.div(fp.Single.from_int(state.basic_state.rnd_seed), fp.Single.from_int(rnd_period)))
def get_random_int(n): """ Get a value from the random number generator (int argument). """ if n < 0: n = -n while n < 2**23: n *= 2 state.basic_state.rnd_seed = n if n != 0: state.basic_state.rnd_seed = (state.basic_state.rnd_seed * rnd_a + rnd_c) % rnd_period # rnd_seed/rnd_period return fp.pack( fp.div(fp.Single.from_int(state.basic_state.rnd_seed), fp.Single.from_int(rnd_period)))
def format_float_fixed(expr, decimals, force_dot): """ Put a float in fixed-point representation. """ unrounded = mul(expr, pow_int(expr.ten, decimals)) # expr * 10**decimals num = unrounded.copy().iround() # find exponent exp10 = 1 pow10 = pow_int(expr.ten, exp10) # pow10 = 10L**exp10 while num.gt(pow10) or num.equals(pow10): # while pow10 <= num: pow10.imul10() # pow10 *= 10 exp10 += 1 work_digits = exp10 + 1 diff = 0 if exp10 > expr.digits: diff = exp10 - expr.digits num = div(unrounded, pow_int(expr.ten, diff)).iround() # unrounded / 10**diff work_digits -= diff num = num.trunc_to_int() # argument work_digits-1 means we're getting work_digits==exp10+1-diff digits # fill up with zeros digitstr = get_digits(num, work_digits-1, remove_trailing=False) + ('0' * diff) return decimal_notation(digitstr, work_digits-1-1-decimals+diff, '', force_dot)
def format_float_fixed(expr, decimals, force_dot): """ Put a float in fixed-point representation. """ unrounded = mul(expr, pow_int(expr.ten, decimals)) # expr * 10**decimals num = unrounded.copy().iround() # find exponent exp10 = 1 pow10 = pow_int(expr.ten, exp10) # pow10 = 10L**exp10 while num.gt(pow10) or num.equals(pow10): # while pow10 <= num: pow10.imul10() # pow10 *= 10 exp10 += 1 work_digits = exp10 + 1 diff = 0 if exp10 > expr.digits: diff = exp10 - expr.digits num = div(unrounded, pow_int(expr.ten, diff)).iround() # unrounded / 10**diff work_digits -= diff num = num.trunc_to_int() # argument work_digits-1 means we're getting work_digits==exp10+1-diff digits # fill up with zeros digitstr = get_digits(num, work_digits - 1, remove_trailing=False) + ('0' * diff) return decimal_notation(digitstr, work_digits - 1 - 1 - decimals + diff, '', force_dot)
def value_timer(ins): """ TIMER: get clock ticks since midnight. """ # precision of GWBASIC TIMER is about 1/20 of a second return fp.pack( fp.div(fp.Single.from_int(timedate.timer_milliseconds() / 50), fp.Single.from_int(20)))
try: import numpy except ImportError: numpy = None import error import fp import state import vartypes import util import draw_and_play # FIXME: circular import import backend # degree-to-radian conversion factor deg_to_rad = fp.div(fp.Single.twopi, fp.Single.from_int(360)) class Drawing(object): """ Manage graphics drawing. """ def __init__(self, screen): self.screen = screen self.unset_window() self.unset_view() self.reset() def reset(self): """ Reset graphics state. """ if self.screen.mode.is_text_mode: return self.last_point = self.get_view_mid()
def number_divide(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double(left)), fp.unpack(vartypes.pass_double(right))) ) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single(left)), fp.unpack(vartypes.pass_single(right))) )
try: import numpy except ImportError: numpy = None import error import fp import state import vartypes import util import draw_and_play import backend # degree-to-radian conversion factor deg_to_rad = fp.div(fp.Single.twopi, fp.Single.from_int(360)) class Drawing(object): """ Manage graphics drawing. """ def __init__(self, screen): self.screen = screen self.unset_window() self.unset_view() self.reset() def reset(self): """ Reset graphics state. """ if self.screen.mode.is_text_mode: return
def value_timer(ins): """ TIMER: get clock ticks since midnight. """ # precision of GWBASIC TIMER is about 1/20 of a second return fp.pack(fp.div( fp.Single.from_int(timedate.timer_milliseconds()/50), fp.Single.from_int(20)))
def vdiv(left, right): """ Left/right. """ if left[0] == '#' or right[0] == '#': return fp.pack( fp.div(fp.unpack(vartypes.pass_double_keep(left)), fp.unpack(vartypes.pass_double_keep(right))) ) else: return fp.pack( fp.div(fp.unpack(vartypes.pass_single_keep(left)), fp.unpack(vartypes.pass_single_keep(right))) )