A Sprite2Mem and Mem2sprite question

Previous topic - Next topic

backspace

Hi again,

This time it's my turn to ask a MEM2* question, but more to ask if anyone can see what I am wrong in my code.
This is my first attempt at using the MEM stuff, to see if I can actually use a dirty rectangle method in painting with a "brush". It's easy with drawsprite to a buffered screen, but the MEM thing is hopefully the start of a more complex  bit based process for painting.

I would really appreciate some educate eyes to see where I am messing up in my code. It's probably something very noobish, so please be gentle with that stick :)

Code (glbasic) Select
// --------------------------------- //
// Project: mem2mem-paint-test
// --------------------------------- //

//we define our variables here
GLOBAL x,y,i,r,i, mx,my,mlb,mrb,c,cc,rr
GLOBAL brush%[], bground%[], dirty%[]


//we start with a white image to paint on - we stick to 640x480 with this test
CREATESCREEN 30, 99, 640, 480    //screen 30, sprite 99, our work area

//we now use our own screen to make our work area white
USESCREEN 30
DRAWRECT 0,0,640,480, RGB(255,255,255)

//we set up a new screen for a paintbrush image
CREATESCREEN 31, 100, 20, 20   //screen 31, sprite 100, brush size 20x20

//we switch to our paintbrush screen to create the brush
USESCREEN 31

//we use math to draw in circles
FOR r = 1 TO 10                                 //for radius 1 to 10. Half width of our brush = radius
FOR i = 0 TO 360                            //all around the compas
x = SIN(i)*r                            //1st part of a circle formula
y = COS(i)*r                            //2nd part of a circle formula
SETPIXEL x+10,y+10,RGB(100,100,100)     //0,0 is top left corner, so we offset drawing to middle of image
NEXT
NEXT

//our main game loop
WHILE TRUE

//we get the mouse state
MOUSESTATE mx,my,mlb,mrb

//if the left button is down, we MEM our brush onto the canvas
IF mlb =1 THEN drawBrush()


//we ensure that all final drawings go to the real screen
USESCREEN -1

//we draw our work area sprite onto the real screen
DRAWSPRITE 99, 0, 0

//use the brush as a mouse pointer
DRAWSPRITE 100,mx,my

SHOWSCREEN
WEND


FUNCTION drawBrush:   //we could use parameter, but for this test we use globals
LOCAL x = mx-9     //mouse x less half the brush width + center pixel
LOCAL y = my-9     //mouse y less half the brush height + center pixel
LOCAL w = x+19     //width of the brush less 1
LOCAL h = y+19     //height of the brush less 1
LOCAL r%,g%,b%,a%
LOCAL BGabgr%      //Background alpha, red, green, blue . .that's why it has a funny name
LOCAL DIRTYabgr%, BRUSHabgr%
LOCAL rr,yy

//grab the background work area
SPRITE2MEM(bground%[], 99)

//grab the brush
SPRITE2MEM(brush%[], 100)

//build the dirty rectangle
rr = -1 //inner rows
cc = -1                                                                          //inner columns
FOR r = y TO h        //for each row
    rr = rr + 1 //for each inner row
    cc = -1                                                                         //reset inner column for new row
FOR c = x TO w    //for each column
    cc = cc + 1 //for each inner column
BGabgr% = bground%[c + r*20]             //get a piece of our drawing buffer
DIRTYabgr% = BGabgr% //get the buffer into the dirty rectangle
BRUSHabgr% = brush%[cc + rr*20]          //get the brush
BGabgr% = bOR(DIRTYabgr%,BRUSHabgr%)    //add the brush to the diry rectangle
bground%[c + r*20] = BGabgr%                    //rebuild background from the rectangle
NEXT
NEXT

//Replace background with changes
MEM2SPRITE(bground%[], 99, 640, 480)

ENDFUNCTION


I came, I saw, I coded.

Kitty Hello

Hi
Draw both, brush and background to see if they are ok. The blending with bOR is also not perfect. It might just brighten up. Does it not work? Cant test atm.

backspace

#2
Hi Kitty,

Thanks for the reply. Yes that was a poor post I my part. I just dumped the code without an explanation. Sorry about that; frustration sometimes does get the upperhand and mess up the mind.

The problem was that I could not see any results from OR-ing the the two buffers together. The resulting buffer was "empty" for some unknown reason, and would not update anything onto the "screen".

I have however addressed the problem by passing the DGInt arrays to INLINE functions and using c to manipulate the byte data. All my pixel-magic algorithms are from c libraries anyway, so I can just INLINE the ones that I use. So I SPRITE2MEM in, do the INLINE stuff and MEM2SPRITE back again. This has solved all previous problems that I had.




I came, I saw, I coded.

backspace

#3
Oh my. Just when I thought I had everything sorted out, I ran into another snag.
This has all got to do with my MEM2SPRITE paint-thing, so I am continuing the new question here.

This time it looks as if the MEM2SPRITE is actually the cause of all my problems.
I am able to get a sprites onto  PixelArray[]s with SPRITE2MEM. This works perfectly.
I am able to manipulate the array data against another with all sorts of 'magic" using INLINE with no problems
I can convert the PixelArray[]s back to sprites with MEM2SPRITE, with a big smile.

BUT.. here comes the issue:
If I drawsprite the image after a MEM2SPRITE, I see all my work on the image.
If I print, drawline, drawsprite, or any of the other commands to the "screen" that holds the image (after a MEM2SPRITE)... Nothing happens
If I remove the MEM2SPRITE command, then the other commands all draw to that "screen" without any problems.

So it seems as of the MEM2SPRITE somehow "locks up" the screen and image, and wont accept anything else done on it.
Here's a little test program to illustrate my point.

On first run you can see the image, but not the PRINT "hello" and another drawn image drawn onto the "memsprite"'s image screen
If you comment out the MEM2SPRITE, then you can see that all the other stuff actually works ok.

Why this is important, is that I want to be able to sometime add some text to the image, or maybe even draw some lines on them, which can't really be done with MEM buffers.

Code (glbasic) Select

// --------------------------------- //
// Project: sprite2mem-test-12
// --------------------------------- //

SETCURRENTDIR("Media")

LOCAL PX1%[]
LOCAL argb%

CREATESCREEN 1,1,320,240
CREATESCREEN 2,2,320,240
CREATESCREEN 3,3,50,50

USESCREEN 3
DRAWRECT 0,0,49,49,RGB(50,100,150)
USESCREEN -1

LOADSPRITE "dogncat1.png",1

SPRITE2MEM(PX1[],1)
MEM2SPRITE(PX1[], 2, 320, 240)   // <----------comment out this line and the rest works fine

USESCREEN 2
DRAWSPRITE 3,200,100
PRINT "HI",5,5
USESCREEN -1

DRAWSPRITE 2,0,0

SHOWSCREEN
MOUSEWAIT


Edit: I attached the image I used for the test. I kept it small for test purposes.


[attachment deleted by admin]
I came, I saw, I coded.

backspace

Luckily I don't give up easily. I've found a work-around, but this still does not solve the MEM2SPRITE "lockout" problem.

What I've done is create a new screen and sprite, and then draw my image and other stuff on that, then use the new sprite to display the results.

I'm a little concerned about the overhead of creating a new screen in a a game loop. since the paintbrush will need to continuously update the image via a new screen, 60 or more times a second. If it's a pointer to a newly created class instance, then that's ok, since that's what c+ is made to do anyway, but this does raise the possibility of memory leaks. (No offense to the programmers, it's one of the things about c++)

Here's the workaround. It does exactly what I need, but leaves me with performance and memory leak concerns.

Code (glbasic) Select
// --------------------------------- //
// Project: sprite2mem-tes-13
// --------------------------------- //

SETCURRENTDIR("Media")

LOCAL PX1%[]
LOCAL argb%
LOCAL r,y

CREATESCREEN 1,1,320,240
CREATESCREEN 2,2,320,240
CREATESCREEN 3,3,50,50

USESCREEN 3
DRAWRECT 0,0,49,49,RGB(255,0,0)
USESCREEN -1

LOADSPRITE "dogncat1.png",1

SPRITE2MEM(PX1[],1)
MEM2SPRITE(PX1[], 2, 320, 240)   

// Create a new screen and sprite to use as an intemediary step to publish

CREATESCREEN 4,4,320,240
USESCREEN 4
DRAWSPRITE 2,0,0

DRAWSPRITE 3,200,100
PRINT "HI",5,5

USESCREEN -1
DRAWSPRITE 4,0,0

SHOWSCREEN
MOUSEWAIT


I came, I saw, I coded.

mentalthink

hi BackSpace thanks for your code, very interesting... in fact I like use this technic for 3d... but.. if you want draw...
because don't draw the image and whit an dinamic array paint over, you can do layers, like photoshop, and when you finished the work, makes a grabsprite and you have the same like you do whit your code, but whitout troubles of speed... In PC Mem2Sprite for me runs very quickly but in mobile devices not...

But thanks it's very interesting playing whit the values os RGBA, can do very nice effects...  :good:

graffix989

ive had simular problems with mem2sprite, used setpixel from array (for any changes)  then grabsprite as a workaround... my best guess is mem2sprite somehow fills the backbuffer with pixels that cannot be changed until cleared?? i also noticed mem2sprite has to be EXACTLY same size if replacing a current sprite... dunno, ive found a few quirks with GLBasic that all need their own workaround :) good luck

fuzzy70

Here is my version of your code which only uses 2 createscreens. I have just changed the mem2sprite ID to one which is not one been used by a screen & drew the sprite.

Only thing I can think of is some kind of conflict with created screens & mem2sprite using same sprite number  :O.

Lee

Code (glbasic) Select
// SETCURRENTDIR("Media") // go to media files
// --------------------------------- //
// Project: sprite2mem-test-12
// --------------------------------- //

SETCURRENTDIR("Media")

LOCAL PX1%[]
LOCAL argb%

//CREATESCREEN 1,1,320,240   // Not needed
CREATESCREEN 2,2,320,240
CREATESCREEN 3,3,50,50

USESCREEN 3
DRAWRECT 0,0,49,49,RGB(50,100,150)
USESCREEN -1

LOADSPRITE "dogncat1.png",1

SPRITE2MEM(PX1[],1)
MEM2SPRITE(PX1[],4, 320, 240)   // Changed sprite ID to one that is not used by a create screen

USESCREEN 2
DRAWSPRITE 4,0,0 // Draw the memspite 1st
DRAWSPRITE 3,200,100
PRINT "HI",5,5
USESCREEN -1

DRAWSPRITE 2,0,0

SHOWSCREEN
MOUSEWAIT
"Why don't you just make ten louder and make ten be the top number and make that a little louder?"
- "These go to eleven."

This Is Spinal Tap (1984)

Kitty Hello

#8
That one was a hard nut to crack!
Wehn you do mem2sprite, the new sprite can be bigger than it was before. So mem2sprite is the same as loadsprite, internally.
When you lod a sprite, the old one gets dumped and you get a new one created.
However!!! You screen "2" is still assigned to the texture id you just deleted! Ha! So, in order to make it work, you'd re-createscreen for that sprite. ... which would clear the scprite with transparent pixels.

I try to fix it, so I re-assign the new sprite id to the screen.

[edit]
aaaaaand fixxxxored! (For LOADSPRITE and MEM2SPRITE).