This commit is contained in:
Irmen de Jong 2023-06-17 15:36:53 +02:00
parent 5da3abe6b4
commit ff7f3484e4
7 changed files with 109 additions and 83 deletions

View File

@ -97,7 +97,7 @@ _sinecosR8 .char trunc(127.0 * sin(range(180+45) * rad(360.0/180.0)))
}
sub atan_coarse_sgn(byte x1, byte y1, byte x2, byte y2) -> ubyte {
sub direction_sc(byte x1, byte y1, byte x2, byte y2) -> ubyte {
; From a pair of signed coordinates around the origin, calculate discrete direction between 0 and 23 into A.
cx16.r0L = 3 ; quadrant
cx16.r1sL = x2-x1 ; xdelta
@ -110,10 +110,10 @@ sub atan_coarse_sgn(byte x1, byte y1, byte x2, byte y2) -> ubyte {
cx16.r0L-=2
cx16.r2sL = -cx16.r2sL
}
return atan_coarse_qd(cx16.r0L, cx16.r1L, cx16.r2L)
return direction_qd(cx16.r0L, cx16.r1L, cx16.r2L)
}
sub atan_coarse(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
sub direction(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
; From a pair of positive coordinates, calculate discrete direction between 0 and 23 into A.
cx16.r0L = 3 ; quadrant
if x2>=x1 {
@ -128,10 +128,10 @@ sub atan_coarse(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
cx16.r2L = y1-y2
cx16.r0L -= 2
}
return atan_coarse_qd(cx16.r0L, cx16.r1L, cx16.r2L)
return direction_qd(cx16.r0L, cx16.r1L, cx16.r2L)
}
asmsub atan_coarse_qd(ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A {
asmsub direction_qd(ubyte quadrant @A, ubyte xdelta @X, ubyte ydelta @Y) -> ubyte @A {
;Arctan https://github.com/dustmop/arctan24
; From a pair of X/Y deltas (both >=0), and quadrant 0-3, calculate discrete direction between 0 and 23 into A.
; .reg:a @in quadrant Number 0 to 3.
@ -269,6 +269,7 @@ y2 = cx16.r3L
octant = cx16.r4L ;; temporary zeropage variable
lda x1
sec
sbc x2
bcs *+4
eor #$ff
@ -276,6 +277,7 @@ octant = cx16.r4L ;; temporary zeropage variable
rol octant
lda y1
sec
sbc y2
bcs *+4
eor #$ff
@ -283,6 +285,7 @@ octant = cx16.r4L ;; temporary zeropage variable
rol octant
lda log2_tab,x
sec
sbc log2_tab,y
bcc *+4
eor #$ff

View File

@ -184,43 +184,46 @@ math {
}
sub atan_coarse_sgn(byte x1, byte y1, byte x2, byte y2) -> ubyte {
; From a pair of signed coordinates around the origin, calculate discrete direction between 0 and 23 into A.
cx16.r0L = 3 ; quadrant
cx16.r1sL = x2-x1 ; xdelta
if_neg {
cx16.r0L--
cx16.r1sL = -cx16.r1sL
}
cx16.r2sL = y2-y1 ; ydelta
if_neg {
cx16.r0L-=2
cx16.r2sL = -cx16.r2sL
}
return atan_coarse_qd(cx16.r0L, cx16.r1L, cx16.r2L)
}
sub atan_coarse(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
sub direction(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {
; From a pair of positive coordinates, calculate discrete direction between 0 and 23 into A.
cx16.r0L = 3 ; quadrant
if x2>=x1 {
cx16.r1L = x2-x1
} else {
cx16.r1L = x1-x2
cx16.r0L--
}
if y2>=y1 {
cx16.r2L = y2-y1
} else {
cx16.r2L = y1-y2
cx16.r0L -= 2
}
return atan_coarse_qd(cx16.r0L, cx16.r1L, cx16.r2L)
; This adjusts the atan() result so that the direction N is centered on the angle=N instead of having it as a boundary
ubyte angle = atan(x1, y1, x2, y2) - 256/48
return 23-lsb(mkword(angle,0) / 2730)
}
sub atan_coarse_qd(ubyte quadrant, ubyte xdelta, ubyte ydelta) -> ubyte {
sub direction_sc(byte x1, byte y1, byte x2, byte y2) -> ubyte {
; From a pair of signed coordinates around the origin, calculate discrete direction between 0 and 23 into A.
; shift the points into the positive quadrant
ubyte px1
ubyte py1
ubyte px2
ubyte py2
if x1<0 or x2<0 {
px1 = x1 as ubyte + 128
px2 = x2 as ubyte + 128
} else {
px1 = x1 as ubyte
px2 = x2 as ubyte
}
if y1<0 or y2<0 {
py1 = y1 as ubyte + 128
py2 = y2 as ubyte + 128
} else {
py1 = y1 as ubyte
py2 = y2 as ubyte
}
return direction(px1, py1, px2, py2)
}
sub direction_qd(ubyte quadrant, ubyte xdelta, ubyte ydelta) -> ubyte {
; From a pair of X/Y deltas (both >=0), and quadrant 0-3, calculate discrete direction between 0 and 23.
return lsb(mkword(atan(0, 0, xdelta, ydelta), 0) / 2730)
when quadrant {
3 -> return direction(0, 0, xdelta, ydelta)
2 -> return direction(xdelta, 0, 0, ydelta)
1 -> return direction(0, ydelta, xdelta, 0)
else -> return direction(xdelta, ydelta, 0, 0)
}
}
sub atan(ubyte x1, ubyte y1, ubyte x2, ubyte y2) -> ubyte {

View File

@ -372,21 +372,21 @@ but perhaps the provided ones can be of service too.
Fast 8-bit byte cosine of angle 0..179 (each is a 2 degree step), result is in range -127..127
Angles 180..255 will yield a garbage result!
``atan(ubyte x1, ubyte y1, ubyte x2, ubyte y2)``
``atan (ubyte x1, ubyte y1, ubyte x2, ubyte y2)``
Fast arctan routine that uses more memory because of large lookup tables.
Calculate the angle, in a 256-degree circle, between two points in the positive quadrant.
``atan_coarse_sgn(byte x1, byte y1, byte x2, byte y2)``
Small and fast, but imprecise, arctan routine
From a pair of signed coordinates around the origin, calculate discrete direction between 0 and 23.
``atan_coarse(ubyte x1, ubyte y1, ubyte x2, ubyte y2)``
Small and fast, but imprecise, arctan routine
``direction (ubyte x1, ubyte y1, ubyte x2, ubyte y2)``
From a pair of positive coordinates, calculate discrete direction between 0 and 23.
This is a heavily optimized routine (small and fast).
``atan_coarse_qd(ubyte quadrant, ubyte xdelta, ubyte ydelta)``
Small and fast, but imprecise, arctan routine
``direction_sc (byte x1, byte y1, byte x2, byte y2)``
From a pair of signed coordinates around the origin, calculate discrete direction between 0 and 23.
This is a heavily optimized routine (small and fast).
``direction_qd (ubyte quadrant, ubyte xdelta, ubyte ydelta)``
If you already know the quadrant and x/y deltas, calculate discrete direction between 0 and 23.
This is a heavily optimized routine (small and fast).

View File

@ -1,7 +1,6 @@
TODO
====
- vm: fix syscall.ATAN calculation
- document some library modules better (diskio, etc)
...

View File

@ -2,43 +2,66 @@
%import textio
%zeropage basicsafe
main {
main {
const ubyte WIDTH=255
const ubyte HEIGHT=240
sub start() {
sys.gfx_enable(0) ; enable lo res screen
;; gfx2.screen_mode(4)
repeat {
const ubyte HEIGHT = 30 ; txt.DEFAULT_HEIGHT-1
const ubyte WIDTH = 80 ; txt.DEFAULT_WIDTH-1
const ubyte HALFWIDTH = 40 ; txt.DEFAULT_WIDTH/2
const ubyte HALFHEIGHT = 15 ; txt.DEFAULT_HEIGHT/2
ubyte xx
ubyte yy
txt.print_ub(math.atan(0, 0, 10, 20))
for yy in 0 to HEIGHT-1 {
for xx in 0 to WIDTH-1 {
ubyte value = math.direction(WIDTH/2, HEIGHT/2, xx, yy)
;; gfx2.plot(xx,yy,value)
sys.gfx_plot(xx, yy, value*10)
}
}
}
}
}
;main {
;
; sub start() {
;
; const ubyte HEIGHT = txt.DEFAULT_HEIGHT
; const ubyte WIDTH = txt.DEFAULT_WIDTH
; const ubyte HALFWIDTH = txt.DEFAULT_WIDTH/2
; const ubyte HALFHEIGHT = txt.DEFAULT_HEIGHT/2
;
; ubyte @zp value
; ubyte xx
; ubyte yy
; for yy in 0 to HEIGHT {
; for xx in 0 to WIDTH {
; value = math.atan(HALFWIDTH, HALFHEIGHT, xx, yy)
; txt.setchr(xx,yy,value)
; }
; }
;; for yy in 0 to HEIGHT-1 {
;; for xx in 0 to WIDTH-1 {
;; value = math.atan(HALFWIDTH, HALFHEIGHT, xx, yy)
;; txt.setchr(xx,yy,value)
;; }
;; }
;;
;; byte sx
;; byte sy
;; for sy in -HEIGHT/2 to HEIGHT/2 {
;; for sx in -WIDTH/2 to WIDTH/2 {
;; value = math.direction_sc(0, 0, sx, sy)
;; txt.setchr(sx+WIDTH/2 as ubyte,sy+HEIGHT/2 as ubyte,value)
;; }
;; }
;
; byte sx
; byte sy
; for sy in 0 to HEIGHT as byte {
; for sx in 0 to WIDTH as byte {
; value = math.atan_coarse_sgn(0, 0, sx-HALFWIDTH, sy-HALFHEIGHT)
; txt.setchr(sx as ubyte,sy as ubyte,value)
; }
; }
;
; for yy in 0 to HEIGHT {
; for xx in 0 to WIDTH {
; value = math.atan_coarse(HALFWIDTH, HALFHEIGHT, xx, yy)
; for yy in 0 to HEIGHT-1 {
; for xx in 0 to WIDTH-1 {
; value = math.direction(HALFWIDTH, HALFHEIGHT, xx, yy)
; txt.setchr(xx,yy,value)
; }
; }
;
; goto start
}
}
; }
;}

View File

@ -3,8 +3,7 @@ package prog8.vm
import prog8.code.core.AssemblyError
import prog8.intermediate.FunctionCallArgs
import prog8.intermediate.IRDataType
import kotlin.math.max
import kotlin.math.min
import kotlin.math.*
/*
SYSCALLS:
@ -479,12 +478,11 @@ object SysCalls {
val y1f = (y1 as UByte).toDouble()
val x2f = (x2 as UByte).toDouble()
val y2f = (y2 as UByte).toDouble()
val xd = x2f-x1f
val yd = y2f-y1f
TODO("calculate atan the same way as the 6502 routine does 0-255")
// val radians = atan2(yd, xd) + PI // 0 to 2*PI
// val result = floor(2*PI/radians*256.0)
// returnValue(callspec.returns!!, result, vm)
var radians = atan2(y2f-y1f, x2f-x1f)
if(radians<0)
radians+=2*PI
val result = floor(radians/2.0/PI*256.0)
returnValue(callspec.returns!!, result, vm)
}
else -> throw AssemblyError("missing syscall ${call.name}")
}

View File

@ -201,7 +201,7 @@ class VmProgramLoader {
program.st.allVariables().forEach { variable ->
var addr = allocations.allocations.getValue(variable.name)
// zero out uninitialized variables.
// zero out uninitialized ('bss') variables.
if(variable.uninitialized) {
if(variable.dt in ArrayDatatypes) {
repeat(variable.length!!) {