News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

CPCTELERA - scrolling text vertically

Started by bart71, 12:03, 21 October 24

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

bart71

Hello
I know there have been similar threads, but none of them helped solving my issue.
Have spent 3 weekends on the problem now and not progressing too much.
Basically what I need to achieve is a vertical scrolling text in Mode 1 320x200 (like credits at the movie end  :) )
To make it a bit complicated I want to scroll it in the window 320x100 in the middle of the screen so I have some graphics above and below (but this is easy to redraw graphics so if I get whole screen scrolling this is more than enough )

1. First I tried with cpct_drawStringM1 - it worked but was too slow for smooth scrolling
2. Analyzed examples fro cpctelera and decided to try with easytilemaps. Have used custom fonts and created a nice tilemap with my text (40x100 tiles). It is working probably as intended but can't achieve my idea.

  • Using cpct_etm_drawTileBox2x4 - it draws initial box OK with cpct_etm_drawTileBox2x4 (0,0,40(screen width),26 (number of rows from tilemap),40 (tilemap width), CPCT_VMEM_START,MyTilemap2x4), it draws content from tilemap exactly as I want.
  • Tried to draw 'next frames' with (0,x,40(screen width),26 (number of rows from tilemap),40 (tilemap width), CPCT_VMEM_START,MyTilemap2x4) - it just re-draws the box in the original location in the tilemap, I need to start placing this box at fixed location, like  CPCT_VMEM_START so I get scrolling up effect -tried to add some offset to memory pointer but it did not work. Tried to play with cpct_setVideoMemoryOffset() - but I do not understand the logic here - while it only accepts 1byte address value. Anyone can help me with idea how to move this tilebox content up by 1 pixel with every iteration??
3. I started trying to use my tileset for drawing font characters as sprites - maybe it will be faster than cpct_drawStringM1

Any help or suggestions highly appreciated

lightforce6128

Just to collect some more information:

- It is mode 1.
- The area to scroll is 320 x 100.
- Scrolling should be in steps of 1 pixel, 2 pixels, 8 pixels, ... ?
- How many bytes different than the background are visible at the maximum (can be an estimated percentage)? If there are empty areas, this will save some time.
- How often should the screen be updated? With 50 Hz, 25 Hz, or even slower?

If the number of letters/sprites is not too high and they are not too big, then maybe a sprite- or tile-based approach can do the work. Especially if the text is not scrolling too fast, it will not be visible if you update this on every frame or only on every second or third frame.

I do not have experience with CPCTELERA. But however it is programmed, if you want to scroll half of the screen smoothly, updated on every frame, you will need a hardware scroll. If the step size should be smaller than 8 pixels, this will require to split the screen at two lines and to maintain this split with exact timing (also called "rupture").

If you consider to use mode 0, then this thread describes how double buffering and color cycling can be used to also scroll something smoothly. But the number of usable colors will be reduced by this approach dramatically, even in mode 0.

bart71

Quote from: lightforce6128 on 05:17, 22 October 24Just to collect some more information:

- It is mode 1. YES
- The area to scroll is 320 x 100. YES
- Scrolling should be in steps of 1 pixel, 2 pixels, 8 pixels, ... ? I was aiming at 1 pixel but I see it may be harder than expected
- How many bytes different than the background are visible at the maximum (can be an estimated percentage)? If there are empty areas, this will save some time. Not too much free space - nice graphics below and above the scrolling text
- How often should the screen be updated? With 50 Hz, 25 Hz, or even slower? Probably 25 or slower so text is readable 

If the number of letters/sprites is not too high and they are not too big, then maybe a sprite- or tile-based approach can do the work. Especially if the text is not scrolling too fast, it will not be visible if you update this on every frame or only on every second or third frame.

I do not have experience with CPCTELERA. But however it is programmed, if you want to scroll half of the screen smoothly, updated on every frame, you will need a hardware scroll. If the step size should be smaller than 8 pixels, this will require to split the screen at two lines and to maintain this split with exact timing (also called "rupture").

If you consider to use mode 0, then this thread describes how double buffering and color cycling can be used to also scroll something smoothly. But the number of usable colors will be reduced by this approach dramatically, even in mode 0. NO, project is Mode 1

Thanks for your quick answer. I investigated things a bit more since I posted my message. I know video memory setup (not linear, jumps by 8 lines)

lightforce6128

I worked a bit with software scrolling and finally could create a BASIC program with a small machine code program. The machine code is relocatable and should work on every address. While this was an interesting task, the scroll speed is not the best, as expected. There are still some possibilities to optimize the code, but I would not expect that it can double its speed.

100 MODE 1:BORDER 2
110 ' Write machine code.
120 MEMORY &A000-1:a=&A000
130 RESTORE 320:GOSUB 310:GOSUB 300
140 RESTORE 340:GOSUB 310:GOSUB 300
150 RESTORE 350:GOSUB 310
160 ' Draw some random lines.
170 FOR i=1 TO 50
180     MOVE RND*640,RND*400
190     DRAW RND*640,RND*400,1
200 NEXT
210 ' Draw two horizontal lines.
220 y=400-6*16:MOVE 0,y:DRAW 640,y,1
230 y=400-19*16-2:MOVE 0,y:DRAW 640,y,1
240 ' Delete last line.
250 y=400-19*16:MOVE 0,y:DRAW 640,y,0
260 ' Scroll image region.
270 FOR i=1 TO 13*8:CALL &A000:NEXT
280 END
290 ' Sub-routines and data.
300 FOR i=1 TO 20:RESTORE 330:GOSUB 310:NEXT:RETURN
310 READ c:FOR j=1 TO c:READ v:POKE a,v:a=a+1:NEXT:RETURN
320 DATA 15,&F3,&DD,&21,&00,&00,&DD,&39,&06,&67,&21,&E0,&C1,&31,&E0,&C9
330 DATA 5,&D1,&73,&23,&72,&23
340 DATA 4,&18,&02,&18,&98,
350 DATA 24,&21,&B0,&FF,&39,&54,&5D,&31,&00,&08,&39,&30,&04,&31,&50,&C0,&39
360 DATA &F9,&EB,&10,&86,&DD,&F9,&FB,&C9

The assembler program for the machine code looks like this:

NOLIST
ORG &A000
RUN &A000

SCREEN_ADDRESS    EQU &C000
CHAR_STEP         EQU 80
PIXEL_STEP        EQU &800
EIGHT_PIXEL_STEPS EQU 8 * PIXEL_STEP
PIXEL_PER_CHAR    EQU 8

;; Define region to scroll.
FIRST_ROW         EQU 6
ROW_NUMBER        EQU 13
START_ADDRESS     EQU FIRST_ROW * CHAR_STEP + SCREEN_ADDRESS

;; Because the stack pointer is used to support copying,
;; interrupts are disabled and the stack pointer is
;; stored in IX.
DI
LD IX,0 : ADD IX,SP

LD B, ROW_NUMBER * PIXEL_PER_CHAR - 1 ;; counter
LD HL, START_ADDRESS                  ;; target address
LD SP, START_ADDRESS + PIXEL_STEP     ;; source address

loop:

    ;; Copy first half. Use the stack for reading.
    ;; This can be improved if CHAR_STEP is a power of two.
    ;; Then 'INC HL' can be replaced with 'INC L', what is
    ;; twice as fast.
    REPEAT CHAR_STEP / 2 / 2
        POP DE
        LD (HL),E : INC HL
        LD (HL),D : INC HL
    REND

    ;; To keep the program relocatable, this intermediate
    ;; relative jump is needed to jump back from the end
    ;; of the loop to the top.
    JR skip
        back_to_loop: JR loop
    skip:

    ;; Copy second half.
    REPEAT CHAR_STEP / 2 / 2
        POP DE
        LD (HL),E : INC HL
        LD (HL),D : INC HL
    REND

    ;; Reset the stack pointer to the beginning of the line.
    ;; This will be the new destination address, later stored
    ;; in HL. In between, store it in DE.
    LD HL,-CHAR_STEP
    ADD HL,SP
    LD D,H : LD E,L

    ;; Now go to the next pixel line.
    LD SP, PIXEL_STEP
    ADD HL,SP
    JR NC,same_char_row
        ;; If this creates a carry, go back to the beginning of the
        ;; character line, then go forward to the next character line.
        LD SP, CHAR_STEP - EIGHT_PIXEL_STEPS
        ADD HL,SP
    same_char_row:

    ;; Finally store source and target addresses in SP and HL.
    LD SP,HL
    EX HL,DE

DJNZ back_to_loop

;; Restore the stack pointer, enable interrupts, and leave the program.
LD SP,IX
EI
RET

lightforce6128

I could not believe it, but a split screen / rupture can even be done in BASIC :o

The following program shows horizontal scrolling in the middle of the screen with two static areas above and below. Maybe this can be updated somehow to also scroll vertically, but I guess this needs to be done in assembly. The loop counters give a hint about the remaining time that could be used by the program (i.e. nothing).

100 MODE 1:BORDER 2
110 FOR i=1 TO 100
120 LOCATE 1+39*RND,1+24*RND
130 PRINT CHR$(65+26*RND);
140 NEXT
150 OUT &BC00,4:OUT &BD00,12
160 OUT &BC00,7:OUT &BD00,4
170 WHILE INKEY$=""
180 FRAME
190 OUT &BC00,7:OUT &BD00,30
200 OUT &BC00,13:OUT &BD00,i%
210 i%=i%+1 AND 31
220 FOR i=1 TO 1:NEXT
230 OUT &BC00,13:OUT &BD00,0
240 FOR i=1 TO 2:NEXT
250 OUT &BC00,7:OUT &BD00,12
260 WEND
270 OUT &BC00,4:OUT &BD00,38
280 OUT &BC00,7:OUT &BD00,30
290 MODE 1

lightforce6128

#5
I read a bit about CPCTELERA. If it is controlled from C or assembly, then much more can be done compared to BASIC.

I also had a short look at tile maps, sprite routines, and text printing. The documentation goes into detail and gives the needed time for each operation. In my above software scroll approach 5.5 NOPs are needed to copy one byte (with "POP DE:LD (HL),E:INC HL:LD (HL),D:INC HL") what can be reduced to 4.5 NOPs with a different screen width (replace "INC HL" with "INC L"). In CPCTELERA I saw factors of 5 (probably "LDI") and 6 (probably "LDIR" or "LD A,(DE):INC E:LD (HL),A:INC L"). So it seems there is nothing fast enough to scroll a bigger part of the screen fluently.

I did more experiments with BASIC. What can be done there with some effort should be easily portable to a C program where much more can be done. The following BASIC program shows a vertical scroll with steps of one pixel and two static graphics above and below. While the main loop of the BASIC program is full, in a C or assembly program there should be plenty of time free to do other things, e.g. writing new letters.

100 MODE 1:BORDER 2
110 ' Draw random lines.
120 FOR i=1 TO 50
130     MOVE 640*RND,6*8*2+19*8*2*RND
140     DRAW 640*RND,6*8*2+19*8*2*RND
150 NEXT
160 ' Draw horizontal lines.
170 y=6*8*2+2:MOVE 0,y:DRAW 640,y
180 MOVE 0,398:DRAW 640,398
190 ' Prepare split screen.
200 i%=8:j%=0:k%=0
210 ON BREAK GOSUB 390
220 OUT &BC00,4:OUT &BD00,18
230 OUT &BC00,5:OUT &BD00,4
240 OUT &BC00,7:OUT &BD00,8
250 ' Maintain split screen.
260 FRAME
270 OUT &BC00,12:OUT &BD00,&20
280 OUT &BC00,13:OUT &BD00,k%
290 OUT &BC00,5:OUT &BD00,i%
300 OUT &BC00,7:OUT &BD00,127
310 k%=(k%+((i%=1) AND 40)) AND 255
320 OUT &BC00,12:OUT &BD00,&30
330 OUT &BC00,13:OUT &BD00,0
340 OUT &BC00,5:OUT &BD00,j%
350 OUT &BC00,7:OUT &BD00,8
360 i%=((i%-2) AND 7)+1:j%=8-i%
370 GOTO 260
380 ' Restore settings.
390 OUT &BC00,4:OUT &BD00,38
400 OUT &BC00,5:OUT &BD00,0
410 OUT &BC00,6:OUT &BD00,25
420 OUT &BC00,7:OUT &BD00,30
430 MODE 1
440 END

bart71

Thanks million @lightforce6128 !!! 
A lot of useful stuff!!!

Meanwhile I have sorted out how to scroll using cpct_etm_drawTileBox2x4 - Instead of using a pointer to tilemap, I am moving the ponter 40 bytes to start from next line of tiles. Results are much below my final expectations but are sort of satisfactory as for now.

Later I will probably need to look into hardware scrolling - tried to play with that but was not able to find out how to set new starting address of video memory - found only how to choose memory page (16k chunk) and apply an offset (which is 8 bit only) (there is a thread in this forum about that but it did not help me too much)

So the main question has been answered now, for hardware scrolling I may open another one later. Thanks a lot, 
Maybe in some time I will share a new game demo!!!!

ervin

A little while ago I thought I'd give something similar a try, just for fun.

I wrote a little program to do a full-screen credits-style software scroll, in cpctelera.
Though it's mostly z80 code.

It's in mode 1, 40x25 chars, and only scrolls upwards.
It's pretty limited, and there are no comments (and I can't really remember what a lot of the code does!), but it might give you some ideas.

I had to rename main.c to main.c.txt to be able to upload it to the forum.

bart71

@ervin - I have just given a try to your executable - 1px scroll looks promising - will look into the code later. 
It uses firmware fonts - I am planning to use game fonts instead
Thanks a lot!!!  :)

lightforce6128

#9
Quote from: bart71 on 08:27, 25 October 24Later I will probably need to look into hardware scrolling - tried to play with that but was not able to find out how to set new starting address of video memory - found only how to choose memory page (16k chunk) and apply an offset (which is 8 bit only)

In the BASIC program no time was left to update the full 10-bit offset. That is the reason why the scrolling area jumps sometimes.

In the CPCWiki there is a section "Video Memory Address" showing how the video memory address is calculated by CRTC and Gate Array. The next section "Overscan bits" shows that the 10-bit offset is distributed on two 8-bit registers (12 and 13), where register 12 also selects the memory page and allow to activate a carry to use 32 kilobyte screens.

In the AMSTRAD CPC CRTC COMPENDIUM ( v1.8 ) from LOGON SYSTEM in section 20.2 ("VIDEO POINTER CALCULATION") there is a nice diagram about video memory calculation. (If one downloads this big PDF file, consider to store it locally permanently. It might happen that one will have a read more than once. :) )

But beware: Besides this, in the compendium there is also everything else (I really can't imagine that anything could be missing) about CRTC, Gate Array, and other things around video creation on the Amstrad CPC in very high detail. Only consume in small doses.

lightforce6128

Quote from: ervin on 13:14, 25 October 24A little while ago I thought I'd give something similar a try, just for fun.
I wrote a little program to do a full-screen credits-style software scroll, in cpctelera.
It's in mode 1, 40x25 chars, and only scrolls upwards.

Nice! Full screen and selectable scroll speed. With my small assembler routine I tried, but was not able to do this. Address calculation on CPC screens can be difficult. I only achieved an unexpected, but interesting effect of two planes somehow combed one into the other ...

Powered by SMFPacks Menu Editor Mod