News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Arnaud

#CPCTelera : Capture screen to sprite

Started by Arnaud, 20:35, 07 October 17

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Arnaud

Hello,

i have coded a new feature (easy to do this time) it copies screen part into sprite.

Here an example, the background of the UFO use the current screen to be redraw, no need to keep original image in memory.

[attachimg=1]

SpDizzy

Hi, Arnaud

First of all, thanks so much for your aportations both for community and #CPCTelera, they are really impresive and helpfull for those (like me) who are trying to make a wish come true: a little game for our beloved micro.

After testing the feature in an own project, I have a question related to getScreenToSprite(), but first things first.

My project is a mode 0 side view no scroll, no double buffer. Background is made of tiles (8 possible backgrounds right now). Over them there is a layer of objects as sprites with different decorations for levels like windows, doors,.. as well as game items.
Over them is the main sprite character (maybe attached image may help understand).

Main character is 6 x 56 bits, so flickering appers if drawed on pos.y 120 and under.

I wonder if there is any way to draw both captured background and sprite (in it's new position) with only one cpct_drawSprite? Something like:

- Capture backgroung on ScreenCapture
- Move / Copy Captured backgroung to BufferTemp size [SPRITE_W * SPRITE_H]
- Change character sprite position
- Draw character sprite masked over Captured background on BufferTemp
- Capture backgroung in new position
- WaitVSYNC
- Just Draw Buffer to screen

This way is a matter of draw as fast as possible With only one draw on VRAM after all process has been made on little Buffer, and maybe painting is faster and flickering free.

Is there any possibility for an approach like this?

Thanks so much for your time,

Arnaud

Quote from: SpDizzy on 11:56, 24 August 18
First of all, thanks so much for your aportations both for community and #CPCTelera, they are really impresive and helpfull for those (like me) who are trying to make a wish come true: a little game for our beloved micro.

Thanks a lot  :) , but all credit goes to @ronaldo to create cpctelera.

Quote from: SpDizzy on 11:56, 24 August 18I wonder if there is any way to draw both captured background and sprite (in it's new position) with only one cpct_drawSprite? Something like:

I think you need also this code (not yet merged to cpctelera v1.5), with those functions to can draw sprite into buffer :
https://github.com/lronaldo/cpctelera/tree/drawbackbuffer/cpctelera/src/sprites/drawToSpriteBuffer

Example :
https://github.com/lronaldo/cpctelera/tree/drawbackbuffer/examples/advanced/backBuffer

Preview on Profesor Retroman channel:

https://www.youtube.com/watch?v=8-nVXIHB_SU

Quote from: SpDizzy on 11:56, 24 August 18- Draw character sprite masked over Captured background on BufferTemp

The functions cpct_drawToSpriteBufferMasked or cpct_drawToSpriteBufferMaskedAlignedTable are exactly what you need.




SpDizzy

QuoteI think you need also this code (not yet merged to cpctelera v1.5), with those functions to can draw sprite into buffer :
https://github.com/lronaldo/cpctelera/tree/drawbackbuffer/cpctelera/src/sprites/drawToSpriteBuffer
Thanks so much Arnaud, so maybe a mix of both functions could be the solution. Will try it as soon as possible.

Also, have found your topic in the forum about drawToSpriteBuffer, sorry for asking before searching more  :doh:
http://www.cpcwiki.eu/forum/programming/help-for-speed-up-to-copy-sprite-array-to-another/
I guess is the same code.

Despite not being yet merged with latest CpcTelera release, is free to use it? I think @ronaldo is on the way to release it soon.



Arnaud

#4
Quote from: SpDizzy on 17:03, 24 August 18
Thanks so much Arnaud, so maybe a mix of both functions could be the solution. Will try it as soon as possible.
Also, have found your topic in the forum about drawToSpriteBuffer, sorry for asking before searching more  :doh:
http://www.cpcwiki.eu/forum/programming/help-for-speed-up-to-copy-sprite-array-to-another/
I guess is the same code.
No problem, you have confirmation it's the function to use.

Quote from: SpDizzy on 17:03, 24 August 18Despite not being yet merged with latest CpcTelera release, is free to use it? I think @ronaldo is on the way to release it soon.
Yes, of course, you can use this code and it have already been review by @ronaldo.

ronaldo

Quote from: SpDizzy on 17:03, 24 August 18
Despite not being yet merged with latest CpcTelera release, is free to use it? I think @ronaldo is on the way to release it soon.
Well, they are already merged in the development branch, which is next release's branch. In fact, they were merged months ago.

If you want, you may try it while it is under development. You only need to download development branch and install it.

If you don't feel like trying everything at the same time, you may just download CPCtelera low-level library sources (the cpctelera/src/ folder), replace yours and compile them under your current CPCtelera installation (type in 'make' under cpctelera/ folder). That will enable you to use all new functions if that is what you want. You will also find help for new functions in their own source files (help is written at the top of each function's file).

SpDizzy

Can't manage to mix both functions, cpct_getScreenToSprite and cpct_drawBackBuffer, and make it work, surely am I missing something.

Here's the code, for clarity made over UFO example, for DrawUFO() loop.
void DrawUFO()
{
    static BOOL moveRight;
    static u8 posX;
    u8* pvmem;
    u8* backPmem = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y);
   
    if (moveRight == FALSE)
    {
        if (posX == 0)
            moveRight = TRUE;
        else
            posX--;
    }
    else
    {
        if (posX == SCREEN_CX - G_UFO_0_W - 1)
            moveRight = FALSE;
        else
            posX++;
    }
   
    cpct_drawBackBuffer(gScreenCapture, G_UFO_0_W, G_UFO_0_H, gBackBuffer, G_UFO_0_W);  //-- DRAW gScreenCapture on gBackBuffer
    cpct_drawBackBufferMaskedAlignedTable(GetUfoSprite(), G_UFO_0_W, G_UFO_0_H, gBackBuffer, G_UFO_0_W, gMaskTable); // DRAW UFO sprite masked on gBackBuffer
   
    pvmem = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y);  //-- New Pointer for ScreenCapture
    cpct_getScreenToSprite(pvmem, gScreenCapture, G_UFO_0_W, G_UFO_0_H); //-- ScreenCapture
   
    cpct_waitVSYNC();
    cpct_drawSprite(gBackBuffer, pvmem, G_UFO_0_W, G_UFO_0_H); //-- Draw BackBuffer

}

Also gBackBuffer and gMaskTable are defined as:
u8 gBackBuffer[G_UFO_0_H*G_UFO_0_W]
cpctm_declareMaskTable(gMaskTable);
cpctm_createTransparentMaskTable(gMaskTable, 0x100, M0, 0);

Any help would be much appreciate. Thanks so much.


SpDizzy

Well, they are already merged in the development branch, which is next release's branch. In fact, they were merged months ago.

If you want, you may try it while it is under development. You only need to download development branch and install it.

Thanks so much @ronaldo .
I actually made a test based on old @Arnaud post on the wiki, not with cpctelera development branch functions. Sorry for that.
Going for CPCtelera low-level library sources

Arnaud

cpctm_createTransparentMaskTable(gMaskTable, 0x100, M0, 0);

I'm not sure the address where to set the transparent table is right (0x100)

Try to set at the address 0xBE00.

If not working can you put the whole example project on forum ?

SpDizzy

Thanks for support @Arnaud, obviously I need to improve my coding skills.
I wont be able to test it till tomorrow. Sorry for the delay

ronaldo

Quote from: SpDizzy on 19:20, 24 August 18
void DrawUFO()
{
    static BOOL moveRight;
    static u8 posX;
    u8* pvmem;
    u8* backPmem = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y);
   
    if (moveRight == FALSE)
    {
        if (posX == 0)
            moveRight = TRUE;
        else
            posX--;
    }
    else
    {
        if (posX == SCREEN_CX - G_UFO_0_W - 1)
            moveRight = FALSE;
        else
            posX++;
    }
   
    cpct_drawBackBuffer(gScreenCapture, G_UFO_0_W, G_UFO_0_H, gBackBuffer, G_UFO_0_W);  //-- DRAW gScreenCapture on gBackBuffer
    cpct_drawBackBufferMaskedAlignedTable(GetUfoSprite(), G_UFO_0_W, G_UFO_0_H, gBackBuffer, G_UFO_0_W, gMaskTable); // DRAW UFO sprite masked on gBackBuffer
   
    pvmem = cpct_getScreenPtr(CPCT_VMEM_START, posX, UFO_Y);  //-- New Pointer for ScreenCapture
    cpct_getScreenToSprite(pvmem, gScreenCapture, G_UFO_0_W, G_UFO_0_H); //-- ScreenCapture
   
    cpct_waitVSYNC();
    cpct_drawSprite(gBackBuffer, pvmem, G_UFO_0_W, G_UFO_0_H); //-- Draw BackBuffer

}

You have here a clear problem in your logic, concretely, in your drawing order. You get a capture from a given X place from the screen into the backbuffer, that you use for composing the image there, but you finally draw it together to the screen at X+1, leaving pixels at column X unrestored. Moreover, from the second frame beyond, you are not capturing the background when you do getScreenToSprite, but the background with the latest UFO drawn, as you never restore the background alone. These two logical problems together produce the mixing effect you have posted.

I think the problem is you have an incomplete idea in memory (you think that is possible to restore background and place next sprite in the same operation) and it works in your mind, but not in reality. That happens many times to all of us. Basically, you are trying to do a triple-buffer operation, with just 2 buffers. In this case, as you are moving only one sprite it would be possible, but you need your background buffer to stay clean at all times (not compositing the image there). You would need to create a new function that takes sprite and clean backbuffer and performs the composition directly to screen, overwriting there whatever it was. And, of course, for your backbuffer to stay clear, you would need a propper buckbuffer, including all the pixels in UFO's trajectory, so as not to have to capture the screen. You may alternatively use kind of a round-robin backbuffer, capturing only new pixels on every movement, but that would be far more complicated.

There is no problem at all in placing mask table either at 0x100 or at 0xBE00. As long as it is an aligned location and it does not overwrite any other code or data, it is fine.

SpDizzy

#11

Thanks so much for your concrete and logical explanation @ronaldo , it looks like the idea was not well arranged on my head, as I supposed. Nooby and inconsistent.

Everything makes sense now, despite for that little part...

QuoteMoreover, from the second frame beyond, you are not capturing the background when you do getScreenToSprite, but the background with the latest UFO drawn, as you never restore the background alone

I thought I was capturing just the background alone for next frame, because the UFO was not yet drawed on screen on previous frame, just on non visible part, gBackBuffer, so capturing screen gives just background. Am I wrong?
I need to ensure I caught the basics of the idea for a proper implementation. Otherwise doubling torreznos ingest would be the only way to go.

ronaldo

Quote from: SpDizzy on 09:13, 25 August 18
Thanks so much for your concrete and logical explanation @ronaldo , it looks like the idea was not well arranged on my head, as I supposed. Nooby and inconsistent.

Everything makes sense now, despite for that little part...

I thought I was capturing just the background alone for next frame, because the UFO was not yet drawed on screen on previous frame, just on non visible part, gBackBuffer, so capturing screen gives just background. Am I wrong?
I need to ensure I caught the basics of the idea for a proper implementation. Otherwise doubling torreznos ingest would be the only way to go.
Well, that's what you do on the first iteration of your loop. But from the second iteration beyond, you are capturing what lies on the screen, and that is not the background, but the background + the UFO. That happens because you only draw background + UFO to the screen. Therefore, there is not background only on the screen never again, so there is no way to capture only background from there.

Sometimes this is difficult to see. If you still have some difficulties to graps every detail, do a trace in paper with a small screen of 6x6 pixels and a 3x2 sprite and iterate through the process manually. You'll soon understand what happens.

SpDizzy

#13
QuoteWell, that's what you do on the first iteration of your loop. But from the second iteration beyond, you are capturing what lies on the screen, and that is not the background, but the background + the UFO. That happens because you only draw background + UFO to the screen. Therefore, there is not background only on the screen never again, so there is no way to capture only background from there.
:picard:  Please, don't take it into account  :doh: 

robcfg

Don't worry much about it.


Making mistakes is the way to learn how to do it properly and you have Ronaldo and the rest of the forum mates to help you.


Good luck!

Powered by SMFPacks Menu Editor Mod