;**************************************
;           DL_PerlinNoise
;         (c) DRAGONS' LORD
;**************************************
;       08.07.2024 - 10.07.2024
;**************************************

; defining internal structures
                struct FPNInt32
.Low            DW #0000
.High           DW #0000
                ends

                struct FLocation
.X              FPNInt32 0x0000, 0x0000
.Y              FPNInt32 0x0000, 0x0000
                ends

                struct FPNInt40
.Byte           DB #00
.Int            FPNInt32
                ends

                struct FNoise2D
.Frequency      DB #00
.Location       FLocation
                ends
                
;последовательность этих строчек НЕ МЕНЯТЬ!                
Camera:         FLocation ;0xffff, 0xff7f, 0xffff, 0xff7f
Noise2D:        FNoise2D 0x30 ;Frequency значение в педелах (32-255) - изменение масштаба
LocationX:      FPNInt40
LocationY:      FPNInt40
IntNoiseData:   FLocation 
           

; -----------------------------------------
;INC 32
; In :
;   HL - указатель на 32-битное число .Low
; Out :
;   HL = HL+1
; -----------------------------------------
Inc32           INC (HL)
                JR NZ, $+12
                INC L;INC HL
                INC (HL)
                JR NZ, $+8
                INC L;INC HL
                INC (HL)
                JR NZ, $+4
                INC L;INC HL
                INC (HL)
                
                RET
                
; -----------------------------------------
;DEC 32
; In :
;   HL - указатель на 32-битное число .Low
;   B  - сколько отнимаем (класть в Dec32+1)
; Out :
;   HL = HL-B
; -----------------------------------------                
Dec32           LD B,1 ;сколько отнимаем
                LD A, (HL)
                SUB B
                ld (HL), A
                JR NC, $+18
                INC L
                LD A, (HL)
                SUB B
                ld (HL), A
                JR NC, $+12
                INC L
                LD A, (HL)
                SUB B
                ld (HL), A
                JR NC, $+6
                INC L
                LD A, (HL)
                SUB B
                ld (HL), A
                
                RET
                
; -----------------------------------------
; сложение 32-битных чисел
; In :
;   HL'HL - 32-битное уменьшаемое число
;   DE'DE - 32-битное вычитаемое число
; Out :
;   HLDE  -  разность 32-битных чисел
; Corrupt :
;   F
; -----------------------------------------
Add32_32:       EXX
                ADD HL, DE
                PUSH HL         ; High
                EXX
                ADC HL, DE
                POP DE
                EX DE, HL

                RET      

; -----------------------------------------
; вычитание 32-битных чисел
; In :
;   HL'HL - 32-битное уменьшаемое число
;   DE'DE - 32-битное вычитаемое число
; Out :
;   HLDE  -  разность 32-битных чисел
; Corrupt :
;   F
; -----------------------------------------
Sub32_32:       EXX
                OR A
                SBC HL, DE
                PUSH HL         ; High
                EXX
                SBC HL, DE
                POP DE
                EX DE, HL

                RET
                
;include "Int32x8_40.asm" ;675t
; -----------------------------------------
; integer multiplies DEHL by A
; In :
;   DEHL  - multiplicand
;   A     - multiplier
; Out :
;   AHLDE - product DEHL * A
; Corrupt :
;   HL, DE, B, AF
; Note:
;   http://z80-heaven.wikidot.com/math#toc8
; -----------------------------------------
MulInt32x8_40:  PUSH HL
                LD HL, #0000        ; hi
                EXX
                LD HL, #0000        ; low
                POP DE

                LD B, #08
.L1             ADD HL, HL          ; low
                EXX
                ADC HL, HL          ; hi
                EXX
                
                ADC A, A
                JR NC, $+9
                ADD HL, DE          ; low
                EXX
                ADC HL, DE          ; hi
                EXX
                ADC A, #00
                DJNZ .L1

                PUSH HL
                EXX
                POP DE

                RET

;include "Int16x8_16.asm" ;265t
; -----------------------------------------
; integer multiplies DE by A
; In :
;   DE - multiplicand
;   A  - multiplier
; Out :
;   HL - product DE * A
; Corrupt :
;   HL, F
; Note:
;   http://z80-heaven.wikidot.com/math#toc1
; -----------------------------------------
MulInt16x8_16:  LD HL, #0000

               rept 8
                ADD HL, HL
                RLCA
                JR NC, $+3
                ADD HL, DE
               endr

                RET

;include "Lerp.asm" ;346t
; -----------------------------------------
; интерполяция между двумя 8-битными значениями (A, B) параметром (Alpha)
; результат в пределах [-128 .. 127]
; In :
;   BC - старший байт отражает знак младшего байта, младший байт имеет знак A [-128 .. 127]
;   HL - старший байт отражает знак младшего байта, младший байт имеет знак B [-128 .. 127]
;   A  - альфа значение в пределах от 0 до 1 [0 .. 255]
; Out :
;   HL - результат (HL - знаковое число)
; Corrupt :
;   HL, DE, AF
; Note:
;   A + Alpha * (B - A)
; -----------------------------------------
Lerp:           ;ret
                ; B - A
                OR A
                SBC HL, BC
                
                ; Alpha * (B - A)
                EX DE, HL
                CALL MulInt16x8_16

                ; HLA = HL >> 8
                LD L, H
                LD A, H
                ADD A, A
                SBC A, A
                LD H, A

                ; A + Alpha * (B - A)
                ADD HL, BC

                RET

;include "IntNoise.asm" ;243t
; -----------------------------------------
; an integer-noise function outputs a pseudorandom value 
; given an n-dimensional input value
; In :
;   LocationX - 32-bit X-axis offset (IntNoiseData + 0)
;   LocationY - 32-bit Y-axis offset (IntNoiseData + 4)
; Out :
;   HL - PRNG range [-128 .. 127]
; Corrupt :
;   HL, BC, AF
; -----------------------------------------
IntegerNoise:   LD B, HIGH PRNG_TAB
                LD HL, IntNoiseData
                LD C, (HL)

               rept 5;8 
                LD A, (BC)
                INC L;INC HL
                ADD A, (HL)
                LD C, A
               endr

                LD L, A
                ADD A, A
                SBC A, A
                LD H, A
                
                RET
                
;include "LerpNoise.asm" ;2199t
; -----------------------------------------
; linear interpolation of noise between adjacent noise values
; In :
;   LocationX - 32-bit X-axis offset
;   LocationX - lower 8-bit X-axis fractional (alpha)
;   LocationY - 32-bit Y-axis offset
;   LocationY - lower 8-bit Y-axis fractional (alpha)
; Out :
;   HL - linear noise interpolation range [-128 .. 127]
; Corrupt :
;   HL, DE, BC, AF
; -----------------------------------------
LerpNoise:      ; v1 = (x, y)
                LD HL, (LocationX + FPNInt40.Int.Low)
                LD (IntNoiseData + FLocation.X.Low), HL
                LD HL, (LocationX + FPNInt40.Int.High)
                LD (IntNoiseData + FLocation.X.High), HL

                LD HL, (LocationY + FPNInt40.Int.Low)
                LD (IntNoiseData + FLocation.Y.Low), HL
                LD HL, (LocationY + FPNInt40.Int.High)
                LD (IntNoiseData + FLocation.Y.High), HL

                CALL IntegerNoise
                SRA H
                RR L                               
                PUSH HL

                ; v2 = (x + 1, y)
                LD HL, IntNoiseData + FLocation.X.Low
                INC (HL)
                JR NZ, $+12
                INC L;INC HL
                INC (HL)
                JR NZ, $+8
                INC L;INC HL
                INC (HL)
                JR NZ, $+4
                INC L;INC HL
                INC (HL)

                CALL IntegerNoise
                SRA H
                RR L
                PUSH HL

                ; v4 = (x + 1, y + 1)
                LD HL, IntNoiseData + FLocation.Y.Low
                INC (HL)
                JR NZ, $+12
                INC L;INC HL
                INC (HL)
                JR NZ, $+8
                INC L;INC HL
                INC (HL)
                JR NZ, $+4
                INC L;INC HL
                INC (HL)

                CALL IntegerNoise
                SRA H
                RR L
                PUSH HL

                ; v3 = (x, y + 1) (взять старый x)
                LD HL, (LocationX + FPNInt40.Int.Low)
                LD (IntNoiseData + FLocation.X.Low), HL
                LD HL, (LocationX + FPNInt40.Int.High)
                LD (IntNoiseData + FLocation.X.High), HL

                CALL IntegerNoise
                SRA H
                RR L
                PUSH HL

                ; i2 = Lerp(v3, v4, FractionalX)
                LD A, (LocationX + FPNInt40.Byte)  ; FractionalX
                POP BC              ; A = v3
                POP HL              ; B = v4                
                CALL Lerp
                LD (.Int2), HL

                ; i1 = Lerp(v1, v2, FractionalX)
                LD A, (LocationX + FPNInt40.Byte)  ; FractionalX
                POP HL              ; B = v2
                POP BC              ; A = v1
                CALL Lerp

                ; HL = Lerp(i1, i2, FractionalY)
                LD A, (LocationY + FPNInt40.Byte)  ; FractionalY
                LD B, H
                LD C, L   ; A = i1
.Int2           EQU $+1
                LD HL, #0000        ; B = i2
                JP Lerp
                
;include "PerlinNoise.asm" ;3755t
; -----------------------------------------
; noise generation
; In :
;   FNoise2D.Frequency - range [0 .. 255]
;   FNoise2D.Location  - 32-bit values of the offset axes
; Out :
;   HL - noise range [-128 .. 127]
; Corrupt :
;   HL, DE, BC, AF
; -----------------------------------------
PerlinNoise2D:  
                ; AHLDE = Location.X * Frequency
                LD DE, (Noise2D + FNoise2D.Location.X.High)
                LD HL, (Noise2D + FNoise2D.Location.X.Low)
                LD A, (Noise2D + FNoise2D.Frequency)
                CALL MulInt32x8_40                         ; AHLDE
                
                ; save result to FMultiply40
                LD (LocationX + FPNInt40.Int.High - 1), HL
                LD (LocationX + FPNInt40.Int.Low  - 1), DE
                LD (LocationX + FPNInt40.Int.High + 1), A

                ; AHLDE = Location.Y * Frequency
                LD DE, (Noise2D + FNoise2D.Location.Y.High)
                LD HL, (Noise2D + FNoise2D.Location.Y.Low)
                LD A, (Noise2D + FNoise2D.Frequency)
                CALL MulInt32x8_40                         ; AHLDE

                ; save result to FMultiply40
                LD (LocationY + FPNInt40.Int.High - 1), HL
                LD (LocationY + FPNInt40.Int.Low  - 1), DE
                LD (LocationY + FPNInt40.Int.High + 1), A

                JP LerpNoise
                
;include "PRNG_Tab.asm"
                align 256
PRNG_TAB:      ; sequence
                DB  106,     -37,    -22,     38,    -68,     54,     37,     27
                DB  -17,     -89,    118,    -13,    -99,    -107,    -5,     84
                DB   35,      -3,     32,     17,    -81,      86,    52,    -24
                DB -120,     100,   -113,     69,    121,     -40,    74,   -100
                DB  -26,      25,    -62,    -44,    119,    -109,   -90,     56
                DB   78,     -63,    122,    -61,    -20,      91,    36,    115
                DB -119,     -25,    -60,    -49,     34,     -76,  -108,     31
                DB  111,     101,      4,    116,     16,      63,   -93,     98
                DB  -72,      43,    -38,    -86,   -121,    -111,    -2,     42
                DB  120,      47,     66,     99,   -112,    -114,   -21,    -83
                DB   29,     -34,    -88,     12,     97,       6,   108,    -70
                DB   -8,     107,     55,     87,    110,     -39,    -4,     -1
                DB   76,    -126,    -74,    -58,     65,    -104,   -51,     85
                DB  -30,      10,    -75,    -23,   -127,      28,   -84,     81
                DB    0,      14,     80,    -73,     48,     -18,    22,    -96
                DB  -19,      57,     26,     24,    125,     -42,   -80,    105
                DB  -98,    -103,    126,    -41,     53,      59,    39,     21
                DB  -57,      18,     95,      2,     77,     -43,   -59,     73
                DB  -52,     103,    -28,      3,    -54,     114,   117,    -87
                DB   71,      79,    -16,     33,    -92,    -101,    58,     30
                DB  -85,     -97,     -6,    -53,    -27,      50,   -79,     83
                DB  -32,    -102,     89,    113,   -117,     -14,    45,    -11
                DB  -36,     -45,     92,    -65,      8,     -94,  -105,     15
                DB  -66,     -95,     46,      9,    -56,     -55,    -7,   -122
                DB   70,     -46,     44,      5,    -12,     -10,   -47,     88
                DB   68,     -77,      1,    -78,     94,     102,  -124,     19
                DB -118,     -91,     75,     62,     40,      11,   109,    -35
                DB  -48,       7,    -71,    127,    -67,      96,   104,    112
                DB -128,     -29,     72,     20,    123,     -31,    82,     67
                DB -115,    -123,     60,     61,   -106,     -64,    23,    -50
                DB  124,      90,     -9,    -69,     93,    -110,    49,   -116
                DB  -82,    -125,     13,     64,    -15,     -33,    51,     41                
