Prev: E0FC Up: Map Next: E29F
E102: Plot masked sprite (24px)
This is the sprite plotter for 24 pixel-wide masked sprites. It's used for both characters and objects.
Used by the routine at plot_sprites.
Input
IY Pointer to visible character.
Mask off the bottom three bits of the vischar's (isometric projected) x position and treat it as a signed field. This tells us how far we need to shift the sprite left or right. -4..-1 => left shift by 4..1px; 0..3 => right shift by 0..3px.
plot_masked_sprite_24px E102 LD A,(IY+$18) x = (vischar.iso_pos.x & 7)
E105 AND $07
E107 CP $04 Is x equal to 4 or above? (-4..-1)
E109 JP NC,pms24_left Jump if so
Right shifting case.
A is 0..3 here: the amount by which we want to shift the sprite right. The following op turns that into a jump table distance. e.g. It turns (0,1,2,3) into (3,2,1,0) then scales it by the length of each rotate sequence (8 bytes) to obtain the jump offset.
E10C CPL x = (~x & 3)
E10D AND $03
E10F ADD A,A Multiply by eight to get the jump distance
E110 ADD A,A
E111 ADD A,A
E112 LD ($E161),A Self modify the JR at pms24_right_mask_jump to jump into the mask rotate sequence
E115 LD ($E143),A Self modify the JR at pms24_right_bitmap_jump to jump into the bitmap rotate sequence
E118 EXX Fetch mask_pointer
E119 LD HL,($81AE)
E11C EXX Fetch bitmap_pointer
E11D LD HL,($81AC)
pms24_right_height_iters E120 LD B,$20 Set B for 32 iterations (self modified by E49D)
Start loop
pms24_right_loop E122 PUSH BC Preserve the loop counter
E123 LD B,(HL) Load the bitmap bytes bm0,bm1,bm2 into B,C,E
E124 INC HL
E125 LD C,(HL)
E126 INC HL
E127 LD E,(HL)
E128 INC HL
E129 PUSH HL Preserve the bitmap pointer
E12A EXX Bank
E12B LD B,(HL) Load the mask bytes mask0,mask1,mask2 into B',C',E'
E12C INC HL
E12D LD C,(HL)
E12E INC HL
E12F LD E,(HL)
E130 INC HL
E131 PUSH HL Preserve the mask pointer
E132 LD A,($81B7) Is the top bit of flip_sprite set?
E135 AND A
E136 CALL M,flip_24_masked_pixels Call flip_24_masked_pixels if so
E139 LD HL,($81B0) Fetch foreground_mask_pointer
E13C EXX
Note: This instruction is moved compared to the other routines.
E13D LD HL,($81A2) Load screen buffer pointer
Shift the bitmap right.
Our 24px wide bitmap has three bytes to shift (B,C,E) but we'll need an extra byte to capture any shifted-out bits (D).
E140 LD D,$00 bm3 = 0
pms24_right_bitmap_jump E142 JR pms24_right_bitmap_jumptable_0 Jump into shifter (self modified by E115)
Rotate the bitmap bytes (B,C,E,D) right by one pixel.
Shift out the leftmost byte's bottom pixel into the carry flag.
pms24_right_bitmap_jumptable_0 E144 SRL B carry = bm0 & 1; bm0 >>= 1
Shift out the next byte's bottom pixel into the carry flag while shifting in the previous carry at the top. (x3)
E146 RR C new_carry = bm1 & 1; bm1 = (bm1 >> 1) | (carry << 7); carry = new_carry
E148 RR E new_carry = bm2 & 1; bm2 = (bm2 >> 1) | (carry << 7); carry = new_carry
E14A RR D new_carry = bm3 & 1; bm3 = (bm3 >> 1) | (carry << 7); carry = new_carry
pms24_right_bitmap_jumptable_1 E14C SRL B Do the same again
E14E RR C
E150 RR E
E152 RR D
pms24_right_bitmap_jumptable_2 E154 SRL B Do the same again
E156 RR C
E158 RR E
E15A RR D
pms24_right_bitmap_jumptable_end E15C EXX Swap to masks bank
Shift the mask right.
This follows the same process as the bitmap shifting above, but the mask and a carry flag are set by default.
E15D LD D,$FF mask3 = $FF
E15F SCF carry = 1
pms24_right_mask_jump E160 JR pms24_right_mask_jumptable_0 Jump into shifter (self modified by E112)
Rotate the mask bytes (B,C,E,D) right by one pixel.
pms24_right_mask_jumptable_0 E162 RR B new_carry = mask0 & 1; mask0 = (mask0 >> 1) | (carry << 7); carry = new_carry
E164 RR C new_carry = mask1 & 1; mask1 = (mask1 >> 1) | (carry << 7); carry = new_carry
E166 RR E new_carry = mask2 & 1; mask2 = (mask2 >> 1) | (carry << 7); carry = new_carry
E168 RR D new_carry = mask3 & 1; mask3 = (mask3 >> 1) | (carry << 7); carry = new_carry
pms24_right_mask_jumptable_1 E16A RR B Do the same again
E16C RR C
E16E RR E
E170 RR D
pms24_right_mask_jumptable_2 E172 RR B Do the same again
E174 RR C
E176 RR E
E178 RR D
Plot using the foreground mask.
In TGE the bitmap pixels are set to 0 for black and 1 for white, and the mask pixels are set to 0 for opaque and 1 for transparent.
TGE uses "AND-OR" type masks. In this type of mask the screen contents are ANDed with the mask (preserving only those pixels set in the mask) then the bitmap is ORed into place, like so: result = (mask & screen) | bitmap
Bitmap Mask Result
0 0 Set to black
0 1 Set to background (transparent)
1 0 Set to white
1 1 Set to white
See also https://skoolkit.ca/docs/skoolkit-6.2/skool-macros.html#masks
However TGE also has a foreground layer to consider. This allows objects to be in front of a sprite too. The foreground mask removes from a sprite the pixels of objects in front of it. This gives us our final expression: result = ((~foreground_mask | mask) & screen) | (bitmap & foreground_mask)
In the left term: ((~foreground_mask | mask) & screen) :: The foreground mask is first inverted so that it will preserve the foreground layer's pixels. It's then ORed with the vischar's mask so that it preserves the transparent pixels around the vischar. The result is ANDed with the screen (buffer) pixels, creating a "hole" into which we will insert the bitmap pixels.
In the right term: (bitmap & foreground_mask) :: We take the vischar's bitmap pixels and mask them against the foreground mask. This means that we retain the parts of the vischar outside of the foreground mask.
Finally the OR merges the result with the screen-with-a-hole-cut-out.
Foreground Bitmap Mask Result
0 any any Set to foreground
1 0 0 Set to black
1 0 1 Set to background (transparent)
1 1 0 Set to white
1 1 1 Set to white
pms24_right_plot_0 E17A LD A,(HL) Load a foreground mask byte
E17B CPL Invert it
E17C OR B OR with mask byte mask0
E17D EXX Swap to bank containing bitmap bytes (in BC & DE) and screen buffer pointer (in HL)
E17E AND (HL) AND combined masks with screen byte
E17F EX AF,AF' Bank left hand term
E180 LD A,B Get bitmap byte bm0
E181 EXX Swap to bank containing mask bytes (in BC' & DE') and foreground mask pointer (in HL')
E182 AND (HL) AND with foreground mask byte
E183 LD B,A Save right hand term
E184 EX AF,AF' Unbank left hand term
E185 OR B Combine terms
E186 INC L Advance foreground mask pointer
E187 EXX Swap to bitmaps bank
pms24_right_plot_enable_0 E188 LD (HL),A Write pixel (self modified)
E189 INC HL Advance to next output pixel
E18A EXX Swap to masks bank
pms24_right_plot_1 E18B LD A,(HL) Do the same again for mask1 & bm1
E18C CPL
E18D OR C
E18E EXX
E18F AND (HL)
E190 EX AF,AF'
E191 LD A,C
E192 EXX
E193 AND (HL)
E194 LD C,A
E195 EX AF,AF'
E196 OR C
E197 INC L
E198 EXX
pms24_right_plot_enable_1 E199 LD (HL),A
E19A INC HL
E19B EXX
pms24_right_plot_2 E19C LD A,(HL) Do the same again for mask2 & bm2
E19D CPL
E19E OR E
E19F EXX
E1A0 AND (HL)
E1A1 EX AF,AF'
E1A2 LD A,E
E1A3 EXX
E1A4 AND (HL)
E1A5 LD E,A
E1A6 EX AF,AF'
E1A7 OR E
E1A8 INC L
E1A9 EXX
pms24_right_plot_enable_2 E1AA LD (HL),A
E1AB INC HL
E1AC EXX
pms24_right_plot_3 E1AD LD A,(HL) Do the same again for mask3 & bm3
E1AE CPL
E1AF OR D
E1B0 EXX
E1B1 AND (HL)
E1B2 EX AF,AF'
E1B3 LD A,D
E1B4 EXX
E1B5 AND (HL)
E1B6 LD D,A
E1B7 EX AF,AF'
E1B8 OR D
E1B9 INC L
E1BA LD ($81B0),HL Save foreground_mask_pointer
E1BD POP HL Restore the mask pointer
E1BE EXX
pms24_right_plot_enable_3 E1BF LD (HL),A
E1C0 LD BC,$0015 Advance screen buffer pointer by (24 - 3 = 21) bytes
E1C3 ADD HL,BC
E1C4 LD ($81A2),HL Save the screen buffer pointer
E1C7 POP HL Restore the bitmap pointer
E1C8 POP BC Restore the loop counter
E1C9 DEC B ...loop
E1CA JP NZ,pms24_right_loop
E1CD RET Return
Left shifting case.
A is 4..7 here, which we intepret as -4..-1: the amount by which we want to shift the sprite left.
pms24_left E1CE SUB $04 4..7 => jump table offset 0..3
E1D0 RLCA Multiply by eight to get the jump distance
E1D1 RLCA
E1D2 RLCA
E1D3 LD ($E22A),A Self modify the JR at pms24_left_mask_jump to jump into the mask rotate sequence
E1D6 LD ($E204),A Self modify the JR at pms24_left_bitmap_jump to jump into the bitmap rotate sequence
E1D9 EXX Fetch mask_pointer
E1DA LD HL,($81AE)
E1DD EXX Fetch bitmap_pointer
E1DE LD HL,($81AC)
pms24_left_height_iters E1E1 LD B,$20 Set B for 32 iterations (self modified by E4A0)
Start loop
pms24_left_loop E1E3 PUSH BC Preserve the loop counter
E1E4 LD B,(HL) Load the bitmap bytes bm1,bm2,bm3 into B,C,E
E1E5 INC HL
E1E6 LD C,(HL)
E1E7 INC HL
E1E8 LD E,(HL)
E1E9 INC HL
E1EA PUSH HL Preserve the bitmap pointer
E1EB EXX Bank
E1EC LD B,(HL) Load the mask bytes mask1,mask2,mask3 into B',C',E'
E1ED INC HL
E1EE LD C,(HL)
E1EF INC HL
E1F0 LD E,(HL)
E1F1 INC HL
E1F2 PUSH HL Preserve the mask pointer
E1F3 LD A,($81B7) Is the top bit of flip_sprite set?
E1F6 AND A
E1F7 CALL M,flip_24_masked_pixels Call flip_24_masked_pixels if so
E1FA LD HL,($81B0) Fetch foreground_mask_pointer
E1FD EXX
E1FE LD HL,($81A2) Load screen buffer pointer
Shift the bitmap left.
Our 24px wide bitmap has three bytes to shift (B,C,E) but we'll need an extra byte to capture any shifted-out bits (D).
E201 LD D,$00 bm0 = 0
pms24_left_bitmap_jump E203 JR pms24_left_bitmap_jumptable_0 Jump into shifter (self modified by E1D6)
Rotate the bitmap bytes (D,B,C,E) left by one pixel.
Shift out the rightmost byte's top pixel into the carry flag.
pms24_left_bitmap_jumptable_0 E205 SLA E carry = bm3 >> 7; bm3 <<= 1
Shift out the next byte's top pixel into the carry flag while shifting in the previous carry at the bottom. (x3)
E207 RL C new_carry = bm2 >> 7; bm2 = (bm2 << 1) | carry; carry = new_carry
E209 RL B new_carry = bm1 >> 7; bm1 = (bm1 << 1) | carry; carry = new_carry
E20B RL D new_carry = bm0 >> 7; bm0 = (bm0 << 1) | carry; carry = new_carry
pms24_left_bitmap_jumptable_1 E20D SLA E Do the same again
E20F RL C
E211 RL B
E213 RL D
pms24_left_bitmap_jumptable_2 E215 SLA E Do the same again
E217 RL C
E219 RL B
E21B RL D
pms24_left_bitmap_jumptable_3 E21D SLA E Do the same again
E21F RL C
E221 RL B
E223 RL D
pms24_left_bitmap_jumptable_end E225 EXX Swap to masks bank
Shift the mask left.
E226 LD D,$FF mask0 = $FF
E228 SCF carry = 1
pms24_left_mask_jump E229 JR pms24_left_mask_jumptable_0 Jump into shifter (self modified by E1D3)
Rotate the mask bytes (D,B,C,E) left by one pixel.
pms24_left_mask_jumptable_0 E22B RL E new_carry = mask3 >> 7; mask3 = (mask3 << 1) | carry; carry = new_carry
E22D RL C new_carry = mask2 >> 7; mask2 = (mask2 << 1) | carry; carry = new_carry
E22F RL B new_carry = mask1 >> 7; mask1 = (mask1 << 1) | carry; carry = new_carry
E231 RL D new_carry = mask0 >> 7; mask0 = (mask0 << 1) | carry; carry = new_carry
pms24_left_mask_jumptable_1 E233 RL E Do the same again
E235 RL C
E237 RL B
E239 RL D
pms24_left_mask_jumptable_2 E23B RL E Do the same again
E23D RL C
E23F RL B
E241 RL D
pms24_left_mask_jumptable_3 E243 RL E Do the same again
E245 RL C
E247 RL B
E249 RL D
Plot, using the foreground mask.
pms24_left_plot_0 E24B LD A,(HL) Load a foreground mask byte
E24C CPL Invert it
E24D OR D OR with mask byte mask0
E24E EXX Swap to bank containing bitmap bytes (in BC & DE) and screen buffer pointer (in HL)
E24F AND (HL) AND combined masks with screen byte
E250 EX AF,AF' Bank left hand term
E251 LD A,D Get bitmap byte bm0
E252 EXX Swap to bank containing mask bytes (in BC' & DE') and foreground mask pointer (in HL')
E253 AND (HL) AND with foreground mask byte
E254 LD D,A Save right hand term
E255 EX AF,AF' Unbank left hand term
E256 OR D Combine results
E257 INC L Advance foreground mask pointer
E258 EXX Swap to bitmaps bank
pms24_left_plot_enable_0 E259 LD (HL),A Write pixel (self modified)
E25A INC HL Advance to next output pixel
E25B EXX Swap to masks bank
pms24_left_plot_1 E25C LD A,(HL) Do the same again for mask1 & bm1
E25D CPL
E25E OR B
E25F EXX
E260 AND (HL)
E261 EX AF,AF'
E262 LD A,B
E263 EXX
E264 AND (HL)
E265 LD B,A
E266 EX AF,AF'
E267 OR B
E268 INC L
E269 EXX
pms24_left_plot_enable_1 E26A LD (HL),A
E26B INC HL
E26C EXX
pms24_left_plot_2 E26D LD A,(HL) Do the same again for mask2 & bm2
E26E CPL
E26F OR C
E270 EXX
E271 AND (HL)
E272 EX AF,AF'
E273 LD A,C
E274 EXX
E275 AND (HL)
E276 LD C,A
E277 EX AF,AF'
E278 OR C
E279 INC L
E27A EXX
pms24_left_plot_enable_2 E27B LD (HL),A
E27C INC HL
E27D EXX
pms24_left_plot_3 E27E LD A,(HL) Do the same again for mask3 & bm3
E27F CPL
E280 OR E
E281 EXX
E282 AND (HL)
E283 EX AF,AF'
E284 LD A,E
E285 EXX
E286 AND (HL)
E287 LD E,A
E288 EX AF,AF'
E289 OR E
E28A INC L
E28B LD ($81B0),HL Save foreground_mask_pointer
E28E POP HL Restore the mask pointer
E28F EXX
pms24_left_plot_enable_3 E290 LD (HL),A
E291 LD BC,$0015 Advance screen buffer pointer by (24 - 3 = 21) bytes
E294 ADD HL,BC
E295 LD ($81A2),HL Save the screen buffer pointer
E298 POP HL Restore the bitmap pointer
E299 POP BC Restore the loop counter
E29A DEC B ...loop
E29B JP NZ,pms24_left_loop
E29E RET Return
Prev: E0FC Up: Map Next: E29F