Gameboy implementation of fast, reasonably accurate 8-bit interpolation. Licensed under zero-clause BSD/ISC/OpenBSD license.

Asm

2021-04-12 11:01

` ;; Copyright 2021 AlaskanEmily ;;  ;; Permission to use, copy, modify, and/or distribute this software for any ;; purpose with or without fee is hereby granted, provided that the above ;; copyright notice and this permission notice appear in all copies. ;;  ;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE ;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ;; POSSIBILITY OF SUCH DAMAGE.  ; ASM implementation of this C routine: ; unsigned interpolate(uint8_t t, uint8_t a, uint8_t b){ ;   uint8_t value, diff, dx; ;   if(a > b){ ;       value = a; ;       a = b; ;       b = value; ;       t = 255 - t; ;   } ;   diff = b - a; ;   value = a; ;   do{ ;       dx = diff & 1; ;       diff >>= 1; ;       if(t & 0x80) ;           value += diff + dx; ;   }while(t <<= 1); ;   return value; ; } ; The extra offset of dx here is a very rough form of rounding. ; If you do not include this, then the results will be about 1/16th too low.  ; Calculates the interpolation at a (0 to 255) of b to c ; Returns in a. interpolate:     push de     ld d, a ; Save the T-value in d          ; Swap the interpolation range and T value if necessary     ld a, c     sub b     jrnc @\$interpolate_inner     ; Swap b and c     ld e, b     ld b, c     ld c, e          ; Negate the T-value     ld a, 0xFF     sub d     ld d, a \$interpolate_inner:          ld a, c     sub b     ld e, a     ; e has the difference now.     ld a, b \$interpolate_bit:     ; srl will set the carry bit, and bit doesn't modify it.     ; This lets us use adc rather than add plus an inc and a jump below.     srl e     bit7 d     jrz @.no_add     adc e .no_add:     sla d     jrnz @\$interpolate_bit     pop de     ret`