sprite image : get, move (UV), repeat

Just starting out? Need help? Post your questions and find answers here.
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

sprite image : get, move (UV), repeat

Post by [blendman] »

Hi purebasic masters :)

1) get the sprite image
I use the sprites in lots of my 2d softwares (free and opensource for most of them ;))
In animatoon, my 2d painting application, I can use layers, with a very big size (3500x3000pixels for example).
So, my sprites are 3500x3000 pixels.

I draw the images of the selected tool (brush for example) directly on the current sprite-layer And on the current image-layer.

Do you know if we can get the image of the sprite, like we can with canvas ?

With a canvas :

Code: Select all

Image = getgadgetattribute(#canvas, #PB_Canvas_Image)
But how to get the image from the sprite ?
I have though about :

Code: Select all

Savesprite(#sprite, filename$)
Loadimage(#imagefromsprite, filename$)
But with big image (3500x3000 pixels) its too much long.

Another technic could be to use drawingbuffer. But with a big image, it seems very long too.

So I have though about copymemory(), but I dont know if its possible, and I don't know how to do that ^^.
If you have any suggestions or idea, it will be great !

2) move sprite uv

Its easy to move sprite uv, with clipsprite(). But, the sprite need to be at the same size as the image.
For an image of 3500x3000pixels, my app animatoon needs lots of memory (ram), because all my layer are composed with :
- a 3500x3000 image (32 bit, with alpha chanel)
- a 3500x3000 sprite for drawing and rendering, with its "own" image (its the image I would like to get)

So, I have though about this technic : to draw partially the image on the sprite of 1000x1000, and move the image on the sprite when needed (move the area to draw for example).
But, its not possible with clisprite(). We cant move an image of 3500x3000 on a sprite in 1000x1000.

So do you know if its possible, to move an image (like for scrolling) of 3500x3000 on a 1000x1000 sprite and how ?
I have try to redraw with startdrawing() the image on the sprite, but it's lagging if I do that at every frame (when moving the canvas area for example)
Thanks.

3) repeat the image on the sprite.

If i have an image with 256x256, iI can repeat it on a sprite of 1024x1024 with :

Code: Select all

StartDrawing (spriteoutput(#sprite))
For i=0 to 3
   For j=0 to 3
      DrawalphaImage(ImageId(#image), i*256, j*256)
   Next
Next
StopDrawing() 
It easy, but its not very fast With my big image in 3500x3000 :).
I use this technic to the "paper background".

Do you know if there is another technic faster ?

Thank you a lot for your answers :).
Ps : sorry for errors, I post from my tablet ^^
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4636
Joined: Sun Apr 12, 2009 6:27 am

Re: sprite image : get, move (UV), repeat

Post by RASHAD »

Hi
- Try to store your images data in Array() or List() [img,x,y] ,width and height are already known
- No need to change x & y for any other big image
- Use only one loop to draw the images without any further calculations

- That will be suitable for any big image
- You can ask wilbert for assembly routine :)
Egypt my love
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: sprite image : get, move (UV), repeat

Post by Mijikai »

Im not really sure if i understand correctly but why do you keep images in memory ?
Would it not be enough to only use sprites and then later create and image or images once done ?
[blendman] wrote: Sun Jun 06, 2021 6:48 am But how to get the image from the sprite ?
Something like this:

Code: Select all

Procedure.i CreatePNG(Sprite.i,*Buffer.Integer = #Null,File.s = #Null$);<- returns a pb image or an encoded image (*buffer) or saves the sprite as file
  Protected w.i
  Protected h.i
  Protected img.i
  Protected *bits
  w = SpriteWidth(Sprite)
  h = SpriteHeight(Sprite)
  img = CreateImage(#PB_Any,w,h,32,#PB_Image_Transparent)
  If img
    If StartDrawing(ImageOutput(img))
      *bits = DrawingBuffer()
      StopDrawing()
      If StartDrawing(SpriteOutput(Sprite))
        CopyMemory(DrawingBuffer(),*bits,(w << 2) * h)
        StopDrawing()
        If *Buffer
          *bits = EncodeImage(img,#PB_ImagePlugin_PNG)
          If *bits
            FreeImage(img)
            ProcedureReturn *bits
          EndIf
        ElseIf File
          If SaveImage(img,File,#PB_ImagePlugin_PNG)
            FreeImage(img)
            ProcedureReturn #True
          EndIf
        Else
          ProcedureReturn img
        EndIf 
      EndIf
    EndIf
    FreeImage(img)
  EndIf
  ProcedureReturn #Null
EndProcedure
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: sprite image : get, move (UV), repeat

Post by [blendman] »

Hi

Thank you for your answers :)

Rashad :
Thanks ;)
I Have tried to store the data image in array() with point()/plot(), but it's not enough fast to paint on a sprite and on an image at the same time (to keep the image of the sprite updated).

But I don't know if it's possible to :
- move the Position of the image on the sprite, with an image bigger than the sprite (for example : a sprite in 1000*1000 with an image in 3000*3000), without redraw the image each time I "move" its position on the sprite.
It's like the UV with Sprite in other applications.

- repeat an image (500*500) on a sprite (1000*1000), like with texture 3D. I can repeat with startdrawing(), but I don't know if there is another way to repeat easily the image on the sprite.

Mijikai :
Im not really sure if i understand correctly but why do you keep images in memory ?
Would it not be enough to only use sprites and then later create and image or images once done ?
thank you a lot for your code, it's very interesting ;).

I have to keep images in memory for at least 2 reasons :
- Sometimes, the screen is black and the sprites are "erased", we have to reload it ^^ (for example, if the monitor is in standby screen)
- Because I use some sprite blendmode (multiply, screen, add...). To get the correct result, I have to draw a white or black box on the sprite before to draw the image.
multiply -> I have to add a white box.
Add, screen -> I have to add a black box.
OF course, I change the image on the sprite only when I change the blendmode of the layer.

So, I need to keep the images of each layer updated and in memory.


Do you know if its possible to draw the image (from memory) with a special position on the sprite with your code ?
for example, for x=50, y=50, we can do :

Code: Select all

StartDrawing(SpriteOutput(#sprite))
DrawImage(ImageID(image), 50, 50)
StopDrawing()
I would like something like that, but I d'ont know how to do :

Code: Select all

Procedure.i SetImageTosprite(Sprite.i,Image.i,x.w,y.w)
  ; get a pb image and draw it on the sprite at position x/y
  Protected w.i
  Protected h.i
  Protected *bits
  w = SpriteWidth(Sprite)
  h = SpriteHeight(Sprite)
  
    If StartDrawing(ImageOutput(img))
      *bits = DrawingBuffer()
      StopDrawing()
      If StartDrawing(SpriteOutput(Sprite))
        ; CopyMemory(DrawingBuffer(),*bits,(w << 2) * h)
        ; <----- here how to paste the image at position x and y ?
        StopDrawing()
      EndIf
    EndIf
  
  ProcedureReturn #Null
EndProcedure

Thanks again.
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Re: sprite image : get, move (UV), repeat

Post by Mijikai »

I see why you need both in memory :)
[blendman] wrote: Mon Jun 07, 2021 9:42 am ...
Do you know if its possible to draw the image (from memory) with a special position on the sprite with your code ?
...
You can try this but it has no boudary checks so it only draws correctly if the src image fits (entirely) at the selected sprite position.

Code: Select all

Procedure.i SetImageToSprite(Sprite.i,Image.i,X.i,Y.i)
  Protected *src
  Protected src_p.i
  Protected src_w.i
  Protected src_h.i
  Protected *dst
  Protected dst_p.i
  Protected dst_w.i
  Protected dst_h.i
  Protected offset.i
  Protected span.i
  If StartDrawing(ImageOutput(Image))
    *src = DrawingBuffer()
    src_p = DrawingBufferPitch()
    src_w = OutputWidth()
    src_h = OutputHeight()
    StopDrawing()
    If StartDrawing(SpriteOutput(Sprite))
      *dst = DrawingBuffer()
      dst_p = DrawingBufferPitch()
      dst_w = OutputWidth()
      dst_h = OutputHeight()
      *src + (src_h * src_p)
      *dst + (dst_h * dst_p) - (Y * dst_p)
      dst_w - X
      dst_h - Y
      offset = X << 2
      span + (src_w << 2)
      src_h + Y - 1
      For src_w = Y To src_h
        CopyMemory(*src,*dst + offset,span)
        *src - src_p
        *dst - dst_p
      Next
      StopDrawing()
      ProcedureReturn #True
    EndIf
  EndIf
  ProcedureReturn #False
EndProcedure


Note:
Only for 32bit Images & Sprites!

On Windows OS the Y coordinate (for images in memory) is flipped, thats why the copy routine starts bottom up.
Not sure how other OSes deal with images they probably dont flip Y.
Changing this *dst + (dst_h * dst_p) - (Y * dst_p) to *dst + (Y * dst_p) and *dst - dst_p to *dst + dst_p
and removing *src + (src_h * src_p) and changing *src - src_p to *src + src_p should work then.

I dont know how fast this is in comparison so let me know if you test it - im curious 8)

Have fun :)
User avatar
[blendman]
Enthusiast
Enthusiast
Posts: 297
Joined: Thu Apr 07, 2011 1:14 pm
Location: 3 arks
Contact:

Re: sprite image : get, move (UV), repeat

Post by [blendman] »

@ Mijikai

Thank you very much !!
I will try your code soon, and tell you if it's fast ;)
Post Reply