News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Jean-Marie

Turrican (128K)

Started by Jean-Marie, 17:58, 12 April 25

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

Jean-Marie

This is version 7 featuring a more forgiving Timer decremented every second. Hooray!

Koren Lesthe


dlfrsilver

Quote from: Jean-Marie on 15:31, 21 June 25I just had a look at that Timer, and there's something amiss indeed 🤔
Looking at the Atari video, it should be decremented every second, but it's a bit faster on the CPC.
For some unknown reason, Daren White didn't rely on Interrupts to clock the Timer. This would have given the best precision, since there are 300 interrupts per second. You just need to set a value to 300, decrement it on every interrupt, and decrement the Timer when that value reaches 0.
I might have a look into that, thanks for reporting it.
org &04c8
ld a,(&dea0)        ;;counter
and &07
jp nz,l04de
ld a,&03            ;;number of digits to display
ld bc,&c50f         ;;Timer string offset in VRAM
ld de,&01           ;;decrement step
ld hl,&ded8         ;;Timer value (24 bit)
call &c622          ;;Decrement function

Hi Jean-Marie,

I have a little request : could it be possible for you to speed up the scrolling of Turrican ? In order to match a little better the Amiga/C64 versions ? 

Cheers, and hats off for this great remaster ! 


Jean-Marie

Quote from: dlfrsilver on Yesterday at 21:41could it be possible for you to speed up the scrolling of Turrican ?
Thank you @dlfrsilver. I did all that I could to have the game faster. For the scrolling, it used LDIR/LDDR instructions that I have unrolled, so it should be a tad faster, even if it's hardly noticeable. However, I'm not a scrolling expert, and maybe I missed obvious things.
The disassembled and (very poorly) commented code can be found in the Excel file enclosed. If someone can come up with improvements, feel free to participate.
The scrolling functions can be found in the Optimization tab at:
SCROLL UP: 124C
SCROLL DOWN:130E
SCROLL LEFT: 1372
SCROLL RIGHT: 12B7

Although, to be honest, I'd really like to close the Turrican chapter, as I've been playing it ad nauseam since February!

lightforce6128

Quote from: Jean-Marie on Today at 00:46
Quote from: dlfrsilver on Yesterday at 21:41could it be possible for you to speed up the scrolling of Turrican ?
For the scrolling, it used LDIR/LDDR instructions that I have unrolled, so it should be a tad faster, even if it's hardly noticeable. However, I'm not a scrolling expert, and maybe I missed obvious things.

@Jean-Marie : I am very impressed. Developing a program from scratch is one thing. But successfully redesigning an existing program (in machine code) with all its constraints and limitations, and even improving it, is a whole other level.

@dlfrsilver : If software scrolling is used for a game (like it is here), it will consume a big amount of computation time, probably more than anything else. Adapting this to hardware scrolling would need a redesign of big parts of the program. One example: In Turrican sprites are never erased. They are just overwritten by the next background. If the background is scrolled without being redrawn, each sprite will create a tail of unerased parts.

As far as I've seen, scrolling is done in a two-step process: First from the level map a screen-fitting tile map is copied. Then all tiles from this tile map are drawn to the screen. This second step looks like this:

ORG #0DA9

;; ... setting registers, initializing loops

;; This block copies one tile of 2x8 bytes to the screen buffer.
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
LDI : LDI : SUB C : LD D,A                 ;;  12
;;                                         ;; ---
;;                                         ;; 110


So one tile needs 110 NOPs, the surrounding loop structure needs additional 24 NOPs, and 32x16=512 tiles need to be drawn. This takes 68'608 NOPs or about 3.5 frames. With this approach, the frame rate will never be higher than 12.5 hz. And still, sprites, movement, music, game logic are missing.

Maybe somebody else sees something how this can be improved.

lightforce6128

#130
While experimenting with the Turrican tile drawing / scrolling, I had one idea to speed it up: Only draw half of the image, and later draw the remaining half. This somehow works, the drawing gets faster by one frame. But now every object is followed by some shadow object. Looks interesting, but does not really improve the game play. You can never be sure how many enemies are on screen.

ORG #0DA9

LD A,(#DE74) : CP A,#30            ;; Check which screen buffer should be updated.
                                   ;; This is not an address, but the value for CRTC register 12.
LD IX,#E72D : JP Z,$+6 : LD LX,#2F ;; Load address of list with screen row addresses to IX.
                                   ;; There are two entries per list row,
                                   ;; one for screen #8000 and one for #C000.

;; Update local frame counter.
LD A,0 :store_a : INC A : LD (store_a-1),A ;; 6 bytes

LD HL,(#C7F1) ;; Load address of tile map.
LD D,#60      ;; High byte of tile buffer address.

LD C,#10      ;; Number of rows.
row_loop:

    EXX
        LD E,(IX+#00)               ;; Load start address of screen row from list to DE'.
        LD D,(IX+#01)               ;;
        LD A,#04 : ADD LX : LD LX,A ;; Go to next address in list.
        LD B,#10                    ;; High byte of 2 scanline offsets in B'.
    EXX

    LD B,#20 ;; Number of chars.
    char_loop:

        XOR A : RLD           ;;  6 ;; Load upper 4 bits of tile number to A. Also shift tile number in (HL) by 4 bits.
        ADD D                 ;;  1 ;; Add tile buffer base address to get high byte of tile address in A.
        EX AF,AF' : LD A,(HL) ;;  3 ;; Load shifted tile number as low byte of tile address in A'
        INC HL                ;;  2 ;; Go to next tile in tile map.
        ;;                    ;; -- ;;
        ;;                    ;; 12 ;;

        EXX ;; 1

            LD L,A : EX AF,AF' : LD H,A ;; 3 ;; Transfer tile address from A/A' to HL.

            LD A,(store_a-1) : BIT 1,A : JR Z,even_frame ;;     4    ;;
            odd_frame:                                   ;;  ....... ;;
                LD C, #30 + 8                            ;;  2     . ;; High byte of 6 scanline offsets plus 8. This will be reduced by 8 LDIs.
                LD A,D                                   ;;  1     . ;; Store high byte of screen buffer address.
                JR registers_are_set                     ;;  3     . ;;
            even_frame:                                  ;;  .     . ;;
                LD C, #38 + 8                            ;;  .     2 ;; High byte of 7 scanline offsets plus 8. This will be reduced by 8 LDIs.
                INC L : INC L                            ;;  .     2 ;; Go to next tile line.
                LD A,D : ADD #08 : LD D,A                ;;  .     4 ;; Store high byte of next screen buffer address.
                JR registers_are_set                     ;;  .     3 ;;
            DEFS 1                                       ;; --    -- ;; Fill unused bytes.
            registers_are_set:                           ;; 10    15 ;; Average time: 12.5 NOPs

            ;; This block copies one tile of 2x8 bytes to the screen buffer.
            ;; It needs 60 NOPs. Loop overhead is additional 12+1+3+12.5+1+4 = 33.5 NOPs.
            ;; The loop is executed 32x16 = 512 times to show a single frame.
            ;; This takes  47'872 NOPs or ~2.4 frames.
            LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14 ;; Copy two bytes. Then go to next scanline.
            INC L : INC L                              ;;   2
            LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
            INC L : INC L                              ;;   2
            LDI : LDI : ADD B : LD D,A : DEC E : DEC E ;;  14
            INC L : INC L                              ;;   2
            LDI : LDI : SUB C : LD D,A                 ;;  12 ;; Copy the last two bytes. Go back to the first scanline.
            ;;                                         ;; ---
            ;;                                         ;;  60

        EXX ;; 1

    DJNZ char_loop ;; 4|3

    ;; The tile map is a bit bigger than the screen.
    ;; Skip 4 invisible tiles at the border.
    INC HL : INC HL : INC HL : INC HL

DEC C : JP NZ,row_loop

Jean-Marie

Wow, thanks for  your contribution, that's an interesting idea. I'll give it a try soon. You seem to have understood the code better than I did, bravo!
Also, I think there might be a mistake here:
LD A,(store_a-1) : BIT 1,A : JR Z,even_frameShouldn't it be Bit 0,A (or better: RRA), or have I misunderstood something?

dlfrsilver

Quote from: Jean-Marie on Today at 00:46
Quote from: dlfrsilver on Yesterday at 21:41could it be possible for you to speed up the scrolling of Turrican ?
Thank you @dlfrsilver. I did all that I could to have the game faster. For the scrolling, it used LDIR/LDDR instructions that I have unrolled, so it should be a tad faster, even if it's hardly noticeable. However, I'm not a scrolling expert, and maybe I missed obvious things.
The disassembled and (very poorly) commented code can be found in the Excel file enclosed. If someone can come up with improvements, feel free to participate.
The scrolling functions can be found in the Optimization tab at:
SCROLL UP: 124C
SCROLL DOWN:130E
SCROLL LEFT: 1372
SCROLL RIGHT: 12B7

Although, to be honest, I'd really like to close the Turrican chapter, as I've been playing it ad nauseam since February!

Thanks a lot ! :D 

I asked because some people said that it had the same scrolling speed as the original with no changes.

Egg Master

It's very interesting to see what can be done to improve scrolling. :)
Have you taken a look at the Turrican 2 display? It seems faster to me.

Jean-Marie

Quote from: Egg Master on Today at 10:58Have you taken a look at the Turrican 2 display? It seems faster to me.
It could be due to the screen size, which is smaller. A lot of games use software scrolling, so it could be interesting to have a look, although Daren White did quite a good job. I'm not sure it can be noticeably improved without changing a lot of things.

lmimmfn

I'm just curious, are the input routines at the start or end of a frame? If not at the end could they be moved to the end to reduce any perceived lag? As in take input at end of frame so next frame if generated based on those latest inputs?
6128 for the win!!!

lightforce6128

Quote from: Jean-Marie on Today at 09:59I think there might be a mistake here:
LD A,(store_a-1) : BIT 1,A : JR Z,even_frameShouldn't it be Bit 0,A (or better: RRA), or have I misunderstood something?

First I wanted to use bit 0. Then I recognized that the game uses double buffering. With checking bit 0, the first buffer will always show the first half, and the second buffer will always show the second half. But it is necessary to overwrite both halfs in each buffer. This is done by checking bit 1. Now the first buffer will show the first half, then the second buffer will also show the first half. After this, both buffers will show the second half.

Powered by SMFPacks Menu Editor Mod