.tHE .sIRIUS .cYBERNETICS .cORPORATION
Okay, here I tell you some techniques of how to sum up fix-point-values and get the integer-value of it quite fast, which is the basic loop of every interpolation-task, e.g. for your polygon-routine, your gouraud-shading or rotozoomer, or for your mod-replay-routine or, or, or....
And I will only discuss the main-loop, not how to initialize the values, which basically depends on the tasks you need it for.
You can ether divide using the div-opcodes (slow) or by using a table which all possible results (should be the fastest - but can need big amounts of memory) - or the symbiosis (with less accuracy of course): A table with all possible 1/x and the mul-instruction...
![]()
A very rough and little introduction to fixed-point-representation:
1.234 is the same as 1234/1000; so fixed-point means in this context that 1234 actually means 1.234, because the value is just 1000 times bigger than the one you want to represent.
As computers work with the binary system, it's logical to use not the decimal-system there, but something like
A multiplication with fixedpoint looks like this:
You see, the point moved another thousand to the left, so you have to rescale your fixpoint-value after a multiplication by shifting to the right (dividing by thousand in this example).
Same goes for the division, but you need to shift before you divide, due to the fact that you would lose a lot more of accuracy by doing it the other way...
(wrong) 1522 / 1234 = 1*1000 = 1000
(right) 1522000 / 1234 = 1257
To minimize rounding-errors you should use a higher scaling-factor than the value you want to represent, as you can see: 1000 is good enough if you just want the integer, but for two digits behind the point it starts to be too inaccurate.
![]()
And now for the implementation
The basic kind of routine works with 16bit-accuracy (high-word represents integer-value, low-word the fraction) and looks like this (just for the ease of understanding):
loop:
add.l D1,D0 ;Add stepwidth
swap D0 ;swap hi- and low-word
move.w D0,(A0)+ ;output the integer-value
swap D0
dbra D7,loop ;repeat this many times
|
D0 = $0001 2000 = 1.125 D1 = $0001 6000 = 1.375 Looped: D0 = $0001 8000 = 1.5 D0 = $0002 E000 = 2.875 D0 = $0004 4000 = 4.25 D0 = $0005 A000 = 5.625 |
loop:
add.w D3,D2 ;add the fractions
addx.w D1,D0 ;and sum overflow
;with the integer-part
move.w D0,(A0)+ ;output
dbra D7,loop ;repeat this many times
|
D0 = $0001 : D2 = $2000 = 1.125 D1 = $0001 : D3 = $6000 = 1.325 Looped: D3 = $(0)8000 (+$6000) D0 = $(0)0001 (+$0001+(0)) D3 = $(0)E000 (+$6000) D0 = $(0)0002 (+$0001+(0)) D3 = $(1)4000 (+$6000) D0 = $(0)0004 (+$0001+(1)) D3 = $(0)A000 (+$6000) D0 = $(0)0005 (+$0001+(0)) |
sub.w D1,D0 ;prepare for init
add.l D1,D0 ;get initial X-Flag set
loop:
;add the fractions(hi)
addx.l D1,D0 ;and integer(low)-pair
move.w D0,(A0)+ ;output the value
;move doesn't change X-Flag!
dbra D7,loop ;repeat this many times
|
D0 = $2000 0001 = 1.125 D1 = $6000 0001 = 1.375 Init: D0 = $(?)2000 0000 (-D1.w) D0 = $(0)8000 0001 (+D1.l) Looped: D0 = $(0)E000 0000 D0 = $(1)4000 0002 D0 = $(0)A000 0004 D0 = $(1)0000 0005 |
tst.w D1 ;negative?
bpl.s notneg
sub.l #$010000,D1 ;then decrease frac.
notneg:
sub.w D1,D0 ;prepare for init
add.l D1,D0 ;get initial X-Flag set
loop:
addx.l D1,D0 ;add frac(hi) and int(low)
move.w D0,(A0)+ ;output the value
dbra D7,loop ;repeat this many times
|
tst.w D1 ;negative?
bpl.s notneg
sub.l #$010000,D1 ;then decrease frac.
notneg:
neg.w D7 ;Offset to the end of the REPT-Block
add.w D7,D7
add.w D7,D7 ;*4
lea jump_in(PC),A0
;before X-Flag init because "add"
;will ruin the X-Flag
sub.w D1,D0 ;prepare for init
add.l D1,D0 ;get initial X-Flag set
jmp -4(A0,D7.w) ;Go!
REPT 4096
addx.l D1,D0 ;add frac(hi) and int(low)
move.w D0,(A0)+ ;output the value
ENDR
jump_in:
|
tst.w D1 ;negative?
bpl.s notneg
sub.l #$010000,D1 ;then decrease frac.
notneg:
moveq #$1F,D6 ;Mask-Value
and.w D7,D6 ;Mask out 0-31
lsr.w #5,D7 ;/32
neg.w D6 ;Offset to end of REPT-block
;before X-Flag init because "neg"
;will ruin the X-Flag
sub.w D1,D0 ;prepare for init
add.l D1,D0 ;get initial X-Flag set
jmp jump_in(PC,D6.w*4) ;Go!
loop:
REPT 32
addx.l D1,D0 ;add frac(hi) and int(low)
move.w D0,(A0)+ ;output the value
ENDR
jump_in:
dbra D7,loop
|
;The bytes of the 32bit-Registers D0 and D1 are
;initialised to the following representation:
; xf|00|yi|yf
;where x and y are the two 8-bit-fixedpoint-values
;and f stands for the fractional part
;and i for the integer
;D3.b and D2.b are just the integer part of the x-value
;A1.l points to a 256x256-Pixels-Truecolor-Grafic
loop:
add.l D1,D0 ;add xf|00|yi|yf
addx.b D3,D2 ;add xi
move.w D0,D4 ;D4 = yi|yf
move.b D2,D4 ;D4 = yi|xi
;reads like: y*256+x
move.w (A1,D4.w*2),(A0)+ ;output the pixel
dbra D7,loop ;repeat this many times
|
bresenham
combsort
chunky2planar
codeTips
.tSCc.
|
|