Enterprise Forever
:UK => Programming => Topic started by: ssr86 on 2015.November.10. 22:43:01
-
Here's a code example for flipping a standard sprite "in place".
You would need to call this only when the sprite changes it's facing direction.
This method doesn't need an additional buffer.
The sprite data is stored normally.
It should be good in cases when the sprite seldom changes the direction it is facing.
Maybe when the direction of the sprite's standing pose changes only after a jump then the sprite data for the standing animation could be reversed during the jumping animation...
The code is written for sprites with even width but can be modified to work with odd widths too...
Here there's a byte pair in the middle and for the odd version there would be a single byte to reverse.
The values to add to hl and de to get to the next line of the sprite data would slightly change too.
The lookup table at the end is for 16-color mode pixels.
flip_sprite:
ld b,reverse_table/256 ;; bc is used for accessing the reversed byte values
ld de,sprite_data+sprite_width_in_bytes-1 ;; de = address of the end of the first sprite data line
ld hl,sprite_data ;; hl = address of the sprite data
exx
ld b,sprite_height
flip_line_loop:
exx
ld a,(de) ;; get left byte
ld c,a ;;
ld a,(bc) ;; reverse left byte
ex af,af'
ld c,(hl) ;; get right byte
ld a,(bc) ;; reverse it
ld (de),a ;; store it on the left side of the sprite data line
ex af,af'
ld (hl),a ;; store the left byte on the right side of the sprite data line
dec e ;; here I assume that the sprite data is aligned (not necessarily page aligned)
inc l ;;
;; repeat the part above k = (sprite_width_in_bytes / 2 - 1 ) times
[...]
;; for the last pair of bytes in the line loop we can drop the dec/inc part:
ld a,(de)
ld c,a
ld a,(bc)
ex af,af'
ld c,(hl)
ld a,(bc)
ld (de),a
ex af,af'
ld (hl),a
;; get to the next sprite data line
ld a,l
add a,sprite_width_in_bytes/2+1
ld l,a
adc a,h
sub l
ld h,a
ld a,e
add a,3*sprite_width_in_bytes/2-1
ld e,a
adc a,d
sub e
ld d,a
exx
djnz flip_line_loop
exx
ret
org ($/256+1)*256
reverse_table:
db $00,$02,$01,$03,$08,$0A,$09,$0B,$04,$06,$05,$07,$0C,$0E,$0D,$0F
db $20,$22,$21,$23,$28,$2A,$29,$2B,$24,$26,$25,$27,$2C,$2E,$2D,$2F
db $10,$12,$11,$13,$18,$1A,$19,$1B,$14,$16,$15,$17,$1C,$1E,$1D,$1F
db $30,$32,$31,$33,$38,$3A,$39,$3B,$34,$36,$35,$37,$3C,$3E,$3D,$3F
db $80,$82,$81,$83,$88,$8A,$89,$8B,$84,$86,$85,$87,$8C,$8E,$8D,$8F
db $A0,$A2,$A1,$A3,$A8,$AA,$A9,$AB,$A4,$A6,$A5,$A7,$AC,$AE,$AD,$AF
db $90,$92,$91,$93,$98,$9A,$99,$9B,$94,$96,$95,$97,$9C,$9E,$9D,$9F
db $B0,$B2,$B1,$B3,$B8,$BA,$B9,$BB,$B4,$B6,$B5,$B7,$BC,$BE,$BD,$BF
db $40,$42,$41,$43,$48,$4A,$49,$4B,$44,$46,$45,$47,$4C,$4E,$4D,$4F
db $60,$62,$61,$63,$68,$6A,$69,$6B,$64,$66,$65,$67,$6C,$6E,$6D,$6F
db $50,$52,$51,$53,$58,$5A,$59,$5B,$54,$56,$55,$57,$5C,$5E,$5D,$5F
db $70,$72,$71,$73,$78,$7A,$79,$7B,$74,$76,$75,$77,$7C,$7E,$7D,$7F
db $C0,$C2,$C1,$C3,$C8,$CA,$C9,$CB,$C4,$C6,$C5,$C7,$CC,$CE,$CD,$CF
db $E0,$E2,$E1,$E3,$E8,$EA,$E9,$EB,$E4,$E6,$E5,$E7,$EC,$EE,$ED,$EF
db $D0,$D2,$D1,$D3,$D8,$DA,$D9,$DB,$D4,$D6,$D5,$D7,$DC,$DE,$DD,$DF
db $F0,$F2,$F1,$F3,$F8,$FA,$F9,$FB,$F4,$F6,$F5,$F7,$FC,$FE,$FD,$FF
Other methods will follow as I have to adapt the examples for the Enterprise...
EDIT: added a working example...
-
"In-place" shifting:
Here we need two routines - left shift and right shift. That's because we change our sprite data permanently so for the "normal" frame we have to shift the sprite back.
; SHIFT SPRITE LEFT (changing sprite data)
; using DE as $aa55 (pixel mask) for optimization
shift_sprite_left:
ld hl,hero_normal+sprite_height*sprite_width_in_bytes-1
ld de,$aa55
ld iyl,sprite_height
lshift_height_loop:
;rightmost byte
ld a,(hl) ; get byte
and d ; get left pixel
rrca
ld c,a ; save it for later
ld a,(hl) ; get the same byte again
and e ; get right pixel
rlca ; shift it to left position
ld (hl),a ; save byte
dec hl ; go to previous byte
lshift_2byte macro
ld a,(hl) ; get byte
and d ; get left pixel
rrca ; shift to right pixel position
ld b,a ; save for later
ld a,(hl) ; get the same byte again
and e ; get right pixel
rlca ; shift to left pixel position
or c ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
dec hl ; go to previous byte
ld a,(hl) ; get byte
and d ; get left pixel
rrca ; shift to right pixel position
ld c,a ; save for later
ld a,(hl) ; get the same byte again
and e ; get right pixel
rlca ; shift to left pixel position
or b ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
dec hl ; go to previous byte
endm
rept sprite_width_in_bytes/2-1
lshift_2byte
endm
ld a,(hl) ; get the same byte again
and e ; get right pixel
rlca ; shift to left pixel position
or c ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
dec hl ; go to previous byte
dec iyl
jp nz,lshift_height_loop
ret
; SHIFT SPRITE RIGHT (changing sprite data)
; using de as $aa55 (pixel mask) for optimization
shift_sprite_right:
ld hl,hero_normal
ld de,$aa55
ld iyl,sprite_height
rshift_height_loop:
;leftmost byte
ld a,(hl) ; get byte
and e ; get right pixel
rlca
ld c,a ; save it for later
ld a,(hl) ; get the same byte again
and d ; get left pixel
rrca ; shift it to right position
ld (hl),a ; save byte
inc hl ; go to next byte
rshift_2byte macro
ld a,(hl) ; get byte
and e ; get right pixel
rlca ; shift to left pixel position
ld b,a ; save for later
ld a,(hl) ; get the same byte again
and d ; get left pixel
rrca ; shift to right pixel position
or c ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
inc hl ; go to next byte
ld a,(hl) ; get byte
and e ; get right pixel
rlca ; shift to left pixel position
ld c,a ; save for later
ld a,(hl) ; get the same byte again
and d ; get left pixel
rrca ; shift to right pixel position
or b ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
inc hl ; go to next byte
endm
rept sprite_width_in_bytes/2-1
rshift_2byte
endm
ld a,(hl) ; get the same byte again
and d ; get left pixel
rrca ; shift to right pixel position
or c ; or with shifted right pixel from previous byte
ld (hl),a ; save byte
inc hl ; go to next byte
dec iyl
jp nz,rshift_height_loop
ret
I have attached a working example...
I think it could be done better and be faster with using some LUT... but haven't tried yet...
-
Do you ssr86 write such an amount of comments for the assembly sources like these,
or is it only for the explanation for the web ?
-
Do you ssr86 write such an amount of comments for the assembly source like these,
or is it only for the explanation for the web ?
I guess, too much...
The comments are only for explanation purposes but as I read it now there're many unnecessary ones...
Well the examples are nearly a year old.. I've wrote them to compare different methods that I could come up with... I've published most of it on the cpcwiki many months ago but lost the motivation to finish it off (took too much time and I haven't met much interest on the subject on that forum, well I don't expect more from ef ;P, but wanted to post what I have here too).
-
Vertical flip with the "in-place" method:
flip_sprite_vertical:
; INPUT:
; DE = sprite data
ld de,hero_normal
; make hl point at the start of the last line of sprite data
ld hl,sprite_width_in_bytes * (sprite_height-1)
add hl,de
ld iyh,sprite_height/2
vflip_loop:
rept sprite_width_in_bytes - 1
ld a,(de)
ld c,a
ld a,(hl)
ld (hl),c
ld (de),a
inc de
inc hl
endm
ld a,(de)
ld c,a
ld a,(hl)
ld (hl),c
ld (de),a
inc de
;inc hl
ld bc,-2*sprite_width_in_bytes-1
add hl,bc
dec iyh
jp nz, vflip_loop
ret
-
I guess, too much...
Not "too much" for the reading, but the writing ...
In Hungary there was a book called "The explanation of the ROM of the Enterprise 128" or "Reverse engineering of the Enterprise 128's ROM":
http://ep128.hu/Ep_Konyv/Pic/Ep_ROM.jpg
and this book was (a big A4 based book with a width like a Harry Potter book's) a printing of the EP128's ROM adding comments line by line, like in your examples ...
They commented that, instruction by instruction ... :)
So ... reading is good, but the commenting is slow enough ... I just wondered you always code like this, or it's an exception ...
-
So ... reading is good, but the commenting is slow enough ... I just wondered you always code like this, or it's an exception ...
Well it seems that when doing the examples I got "bored" of adding that many comments pretty quick, because the other ones seem to have much less of that;P
However I would like my code to be commented in a good way, because doing so you can come back to such project more quickly, also you can publish your code and people can make use of it loosing much less time figuring out what the author is doing and why...
...But my code is rather messy although much still much better then some time before;P
-
Vertical flip using a temporary buffer for storing the flipped sprite... Although I think this would be useful only as means of "decompression" of the flipped sprite frames...
Two versions - the first uses ldi's for copying and the second uses stack.
The routines are just copying the sprite line by line but in inverted order...
flip_sprite_vertical:
; INPUT:
; HL = sprite data
; make HL point at the start of the last line of the sprite
ld bc,sprite_width_in_bytes*(sprite_height-1)
add hl,bc
ld de,flip_buffer
ld a,sprite_height
fsvloop:
rept sprite_width_in_bytes
ldi
endm
ld bc,-2*sprite_width_in_bytes
add hl,bc
dec a
jp nz, fsvloop
ret
flip_buffer ds sprite_height*sprite_width_in_bytes,0
flip_sprite_vertical:
; INPUT:
; DE = sprite data
di
; make HL point at the start of the last line of the sprite
ld hl,sprite_width_in_bytes * (sprite_height-1)
add hl,de
ld (save_sp),sp
ld de, flip_buffer + sprite_width_in_bytes
ld a,sprite_height
fsvloop:
ld i,a
; de = hero_frame + sprite_width_in_bytes * i
; hl = hero_frame0 + sprite_width_in_bytes * (sprite_height-1)
; to buffer...
ld sp,hl ; pop data from sprite frame buffer
pop af
ex af,af'
pop af
pop bc
exx
pop bc
pop de
pop hl
;pop ix
;pop iy
exx
ex de,hl
ld sp,hl ; push data to flip_buffer
ex de,hl
exx
;push iy
;push ix
push hl
push de
push bc
exx
push bc
push af
ex af,af'
push af
ld bc,sprite_width_in_bytes
ex de,hl
add hl,bc ;modify pointer to flip_buffer
ex de,hl
ld bc,-sprite_width_in_bytes
add hl,bc ;modify data pointer
ld a,i
dec a
jp nz,fsvloop
fvend:
save_sp equ $+1
ld sp,0000
ei
ret
flip_buffer ds sprite_height*sprite_width_in_bytes,0