News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Arnaud

Cpcrslib clip scrolling question

Started by Arnaud, 13:31, 20 June 15

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Arnaud

Hello,
i am coding an adventure game, and i have problems with the scrolling entering a new room.

The scrolling must  replace step by step the old sprite of the room with the new one (like in Zombi game). 

But with Cpcrslib i haven't found how blit just a part of a sprite from memory, the function cpc_PutSp seems to work only with full sprite size.

I have thinking about using firmware with 0xBBCF GRA WIN WIDTH and 0xBBD2 GRA WIN HEIGHT functions to clip the sprites but it has no effect.

Thanks for idea,
Arnaud.

arnoldemu

#1
I think you will need a new library function for this effect.

EDIT: Looking at zombi it seems that each screen is drawn from lines.
So that the instructions for drawing are a list of lines with start and end.

When you go into a new room, it clears the area where the room is and draws the new one. So the effect you are seeing is the way it draws the lines, it takes a few frames.
If you described your room using the same method you can use gra draw line.
My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

ronaldo

Up to my understanding, you can use cpc_PutSp to draw partial lines of a sprite, provided that you draw complete lines.

cpc_PutSp is defined this way:
void cpc_PutSp(int *sprite, char height, char width, int *address)[/color]
For instance, if you have a 32-lines sprite, you can draw the first 16 just by changing the height parameter (and putting 16 instead of 32). If you wanted to draw the last 16 lines, the change is not so obvious, but not so difficult. If your sprite has, say, 4 bytes per line (8 pixels on mode 0), you can draw the 16-last lines with this code:
cpc_PutSp( (sprite + 16*4), 16, 4, address)
The last 16 lines start 16-lines away from the start of the sprite, and that is 16 lines * 4 bytes per line. And, of course, as they are only 16 lines, you put 16 in the height parameter.

Arnaud

Thanks for your replies.

ronalda :

I understand your example with the lines for vertical scrolling, but for the horizontal scrolling how it can be done ?



ronaldo

I assume what you wanted to do is some kind of "horizontal clipping" to show just some part of the sprite, like in the previous case. It is possible to do with cpc_PutSp, but it will be terribly slow. The problem is that cpc_PutSp always writes consecutive bytes from the sprite to the screen but, what you want to do is "write 2 bytes, jump over the other 2 and write the next 2 in the next line".

So, the solution, provided we have to use this function, will be something like this
cpc_PutSp( (sprite + 0), 1, 2, (screen + 0x0000) );
cpc_PutSp( (sprite + 4), 1, 2, (screen + 0x0800) );
cpc_PutSp( (sprite + 8), 1, 2, (screen + 0x1000) );
....

Of course, you could write a loop to do it properly, but I have written it unrolled for clarity. This goes drawing 2 bytes from each sprite line, going line by line, effectively drawing half of the sprite horizontaly.

Definitely, is a bad idea. It is much preferably to write a new function that lets you draw subsprites (parts of a sprite) or that manages clipping, if that's what you want.

Arnaud

Thanks ronaldo, i'll try your solution to see if it's fast enough.

ronaldo

Take it with care. I assume you know how screen memory is distributed, do you? I mean, this is pretty similar to drawing by yourself to the screen, screen lines are not always 0x800 bytes away one from each other, as you may see in this article (specially the table).

A loop for this matter would be something like this:
{
  unsigned char  i;
  unsigned char* sp  = sprite;
  unsigned char* scr = screen;

  for (i=0; i < SPRITE_HEIGHT; i++) {
    cpc_PutSp( sp, 1, DESIRED_WIDTH_IN_BYTES, scr );
    sp += 4;
    if (scr & 0x3800)
      scr += 0x0800;
    else
      scr += 0xC850;
  }
}


You should define your own values for SPRITE_HEIGHT and DESIRED_WIDTH_IN_BYTES.


KaosOverride

#7
There is a cpc_GetSP but it makes a copy from screen, so is not valid for "lineal" big sprites to make little ones.

There is the need to make a new function that takes care of the height and width of the original size and the desired size, the origin address of the big sprite and the destination address at screen, this way you can blit the desired rectangle from the original sprite.

But as they told you, Zombi draws lines from coordinates, no scroll, no sprites, but the effect is fast and nice.

EDIT: Do you mean the Amiga Zombi version? It makes scroll from screens...

KaosOverride · GitHub
MEGA Amstrad Public Amstrad folder

Arnaud

#8
Ronaldo :

Here my code, ROOM_HEIGHT and ROOM_WIDTH are the real size of my sprite.
I run it ... and i have a nasty cpc reboot. I think i'll have to read your article with care.

  unsigned char  i;
  unsigned char* sp  = GetRoomBuffer();
  int scr = cpc_GetScrAddress(ROOM_POS_X, ROOM_POS_Y);

  for (i=0; i < ROOM_HEIGHT; i++) {
    cpc_PutSp( sp, 1, ROOM_WIDTH, scr );
    sp += 4;
    if (scr & 0x3800)
      scr += 0x0800;
    else
      scr += 0xC850;
  }


KaosOverride :

Quote from: KaosOverride on 20:17, 20 June 15
There is a cpc_GetSP but it makes a copy from screen, so is not valid for "lineal" big sprites to make little ones.
I understand now why this solution doesn't work.

Quote from: KaosOverride on 20:17, 20 June 15
EDIT: Do you mean the Amiga Zombi version? It makes scroll from screens...
No Amstrad version.

Well i fell i'll put the scrolling step aside for the moment, there are a lot of other things to code in my game.
Thanks again for your replies  ;)

Arnaud

#9
It works with this great piece of code  :D

But ...
... it's not really fast
... it works only for left-to-right scrolling


void DrawScrollRoom(UCHAR* pSprite)
{
    UCHAR i,j;
    for (j = 0; i < ROOM_WIDTH; j++)
    {
        for (i = 0; i < ROOM_HEIGHT; i++)
        {
            cpc_PutSp( pSprite, 1, ROOM_WIDTH - j, cpc_GetScrAddress(ROOM_POS_X + j, ROOM_POS_Y + i) );
            pSprite += ROOM_WIDTH;
        }
    }
}


ronaldo

Nice man! 10 points to Griffindor! :D

When you get a reboot is because some calculation moves us to writting outside the range 0xC000-0xFFFF (the screen) and that usually is bad, very bad :).

Sorry for the last piece of code, I think I gave you code with a bug:
  unsigned char  i;
  unsigned char* sp  = GetRoomBuffer();
  int scr = cpc_GetScrAddress(ROOM_POS_X, ROOM_POS_Y);

  for (i=0; i < ROOM_HEIGHT; i++) {
    cpc_PutSp( sp, 1, WIDTH, scr );
    sp += 4;
    scr += 0x800;
    if (!(scr & 0x3800))
      scr += 0xC050;
  }

I haven't tested it, but this should work. It should be a little bit faster than calling cpc_GetScrAddress every iteration, but not much.

You actually can use the same logic for scrolling the other way. The only think you have to do is drawing the latest bytes of each WIDTH bytes instead of the first bytes :) .

Arnaud

#11
Hello i have tried your code and there's a little problem :
[attachimg=1]

Quote from: ronaldo on 22:14, 20 June 15
You actually can use the same logic for scrolling the other way. The only think you have to do is drawing the latest bytes of each WIDTH bytes instead of the first bytes :) .

But with your explanations my two sides scrolling works ! Thanks


void DrawSpriteLine(UCHAR* pSprite, UCHAR pWidth, int pMemScreen){
   cpc_PutSp( pSprite, 1, pWidth, pMemScreen );
}

void DrawScrollRoom(UCHAR pOffsetX, UCHAR* pSprite, UCHAR pLeftToRight){
   UCHAR y, size = ROOM_WIDTH - pOffsetX;
   for  ( y = 0; y < ROOM_HEIGHT; y++ )
   {
      if ( pLeftToRight) DrawSpriteLine(pSprite, size, cpc_GetScrAddress(ROOM_POS_X + pOffsetX, ROOM_POS_Y + y));
      else  DrawSpriteLine(pSprite + pOffsetX,  size, cpc_GetScrAddress(ROOM_POS_X, ROOM_POS_Y + y));
      pSprite += ROOM_WIDTH;
   }
}

void DrawRoomBackGround(){
   UCHARx, *sprite = GetRoomBuffer();
   for ( x = 0; x < ROOM_WIDTH; x += 4 )
      DrawScrollRoom(x, sprite, TRUE);
}


I don't understand why i must isolate cpc_PutSp in another function otherwise the screen result is corrupted.

arnoldemu

My games. My Games
My website with coding examples: Unofficial Amstrad WWW Resource

Arnaud

Quote from: arnoldemu on 09:22, 21 June 15
Nice looking.
Thanks  ;D , i'll create a specific thread for my game when it will be more advanced.

Powered by SMFPacks Menu Editor Mod