5.10 Drawing a sprite on another sprite
5.10 Drawing a sprite on another sprite
How would you draw a sprite onto another sprite without using UseBuffer ? ; It never worked for me and I read somewhere Fred said it's slow and should be avoided .
Ideas ?
Nubcake
Ideas ?
Nubcake
Re: 5.10 Drawing a sprite on another sprite
Yes. Use the MP3D engine. But it is Windows only.
Belive! C++ version of Puzzle of Mystralia
Bug Planet
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
Bug Planet
<Wrapper>4PB, PB<game>, =QONK=, PetriDish, Movie2Image, PictureManager,...
Re: 5.10 Drawing a sprite on another sprite
Well if that's the case , how does one draw a transparent image of selected color directly to the screen ? Is that possible ?IceSoft wrote:Yes. Use the MP3D engine. But it is Windows only.
Re: 5.10 Drawing a sprite on another sprite
Bump I figured it out instead of using sprites I use Images the way to draw a transparent image without any API calls would to write each pixel in the image to memory then when reading check if it's the transparent colour don't plot it else etc.
There was only a few things I did not understand in this procedure which I adapted from someone's code (It's incomplete as I was testing)
The significance of Allocating memory ; Why does it need to be multiplied by 4 ? I'm sure it has something to do with the fact that Poke/PeekL is being used since it writes/reads 4 bytes.
Also by storing the pixel I don't understand the method behind the offset either.
Can someone explain this to me ?
Thanks
Nubcake
There was only a few things I did not understand in this procedure which I adapted from someone's code (It's incomplete as I was testing)
Code: Select all
Procedure DisplayTransparentImage(Output,Image,x,y,Color)
*Memory = AllocateMemory((ImageWidth(Image) * ImageHeight(Image) * 4))
StartDrawing(ImageOutput(Image))
For x = 0 To ImageWidth(Image) - 1
For y = 0 To ImageHeight(Image) - 1
PokeL(*Memory + (y*ImageWidth(Image)+x)*4,Point(x,y))
Next
Next
StopDrawing()
StartDrawing(ScreenOutput())
For x = 0 To ImageWidth(Image) - 1
For y = 0 To ImageHeight(Image) - 1
If PeekL(*Memory + (y*ImageWidth(Image)+x)*4) <> Color
Plot(x,y,PeekL(*Memory + (y*ImageWidth(Image)+x)*4))
EndIf
Next
Next
StopDrawing()
FreeMemory(*Memory)
EndProcedure
Code: Select all
*Memory = AllocateMemory((ImageWidth(Image) * ImageHeight(Image) * 4))
Code: Select all
PokeL(*Memory + (y*ImageWidth(Image)+x)*4,Point(x,y))
Can someone explain this to me ?
Thanks
Nubcake
Re: 5.10 Drawing a sprite on another sprite
As you can't adress memory with x and y because it's linear, you need to convert your x,y coordonate in a single adress. This code assumes your image is 32bits format=> 4 bytes per pixel.(it explains everything)Nubcake wrote:Also by storing the pixel I don't understand the method behind the offset either.Code: Select all
*Memory = AllocateMemory((ImageWidth(Image) * ImageHeight(Image) * 4))
Code: Select all
PokeL(*Memory + (y*ImageWidth(Image)+x)*4,Point(x,y))
ie, you image starts at 800 adress, your image is 1024 pixels width.
your first line will begin at 800 and end at 800+1023x4
so you can calculate the begining adress of each line:
800+1023*y*4
Then, you just have to add your x coordonate to complete the calculation:
800+(1023*y*4)+(x*4)
you can reduce:
800+(1023*y+x)*4
There are 2 methods to program bugless.
But only the third works fine.
Win10, Pb x64 5.71 LTS
But only the third works fine.
Win10, Pb x64 5.71 LTS
Re: 5.10 Drawing a sprite on another sprite
That calculation is wrong because it disregards the pitch.Fig wrote: Then, you just have to add your x coordonate to complete the calculation:
800+(1023*y*4)+(x*4)
you can reduce:
800+(1023*y+x)*4
The pitch is the actual size in byte of a image line in memory and can be bigger than width*pixelsize.
The caluclation of a pixel is more like that: baseaddress + pitch * y + pixelsize * x.
While you start at X and Y = 0.
In a loop that processes all pixel you can greatly speed it up by using pointers and increment them like that:
Code: Select all
StartDrawing(ScreenOutput())
For y = 0 To ImageHeight(Image) - 1
*Pixel = *Memory + Pitch * y
For x = 0 To ImageWidth(Image) - 1
If *Pixel\l <> Color
Plot(x, y, *Pixel\l)
EndIf
*Pixel = *Pixel + PixelSize
Next
Next
StopDrawing()
Re: 5.10 Drawing a sprite on another sprite
So this code would be faster than the original ?Thorium wrote: That calculation is wrong because it disregards the pitch.
The pitch is the actual size in byte of a image line in memory and can be bigger than width*pixelsize.
The caluclation of a pixel is more like that: baseaddress + pitch * y + pixelsize * x.
While you start at X and Y = 0.
In a loop that processes all pixel you can greatly speed it up by using pointers and increment them like that:
As you can see we have only one addition per pixel and one multiplication per line. Which is way faster than having to multiplicate for every pixel twice.Code: Select all
StartDrawing(ScreenOutput()) For y = 0 To ImageHeight(Image) - 1 *Pixel = *Memory + Pitch * y For x = 0 To ImageWidth(Image) - 1 If *Pixel\l <> Color Plot(x, y, *Pixel\l) EndIf *Pixel = *Pixel + PixelSize Next Next StopDrawing()
Re: 5.10 Drawing a sprite on another sprite
The calculation is correct for CPC6128
Fred made that code...


Fred made that code...
Code: Select all
;
; ------------------------------------------------------------
;
; PureBasic - Drawing via Direct Screen Access (DSA)
;
; (c) 2006 - Fantaisie Software
;
; ------------------------------------------------------------
;
; Note: disable the debugger to run at full speed !
;
#ScreenWidth = 800 ; Feel free to change this to see the pixel filling speed !
#ScreenHeight = 600
If InitSprite() = 0 Or InitKeyboard()=0
MessageRequester("Error","DirectX 7+ is needed.",0)
EndIf
Structure Pixel
Pixel.l
EndStructure
Procedure.f GSin(angle.f)
ProcedureReturn Sin(angle*(2*3.14/360))
EndProcedure
; Pre-calculated values are faster than realtime calculated ones...
; ... so we save them in an array before starting gfx operations
Dim CosTable(#ScreenWidth*2)
Dim ColorTable(255)
For i = 0 To #ScreenWidth*2
CosTable(i) = GSin(360*i/320)* 32 + 32
Next
If OpenScreen(#ScreenWidth, #ScreenHeight, 32, "PB Plasma")
Repeat
Wave+6
If Wave > 320 : Wave = 0 : EndIf
If StartDrawing(ScreenOutput())
Buffer = DrawingBuffer() ; Get the start address of the screen buffer
Pitch = DrawingBufferPitch() ; Get the length (in byte) took by one horizontal line
PixelFormat = DrawingBufferPixelFormat() ; Get the pixel format.
If PixelFormat = #PB_PixelFormat_32Bits_RGB
For i = 0 To 255
ColorTable(i) = i << 16 ; Blue is at the 3th pixel
Next
Else ; Else it's 32bits_BGR
For i = 0 To 255
ColorTable(i) = i ; Blue is at the 1th pixel
Next
EndIf
For y = 0 To #ScreenHeight-1
pos1 = CosTable(y+wave)
*Line.Pixel = Buffer+Pitch*y
For x = 0 To #ScreenWidth-1
pos2 = (CosTable(x+Wave) + CosTable(x+y) + pos1)
*Line\Pixel = ColorTable(pos2) ; Write the pixel directly to the memory !
*Line+4
Next
Next
StopDrawing()
EndIf
ExamineKeyboard()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
Else
MessageRequester("Error","Can't open the screen !",0)
EndIf
End
There are 2 methods to program bugless.
But only the third works fine.
Win10, Pb x64 5.71 LTS
But only the third works fine.
Win10, Pb x64 5.71 LTS
Re: 5.10 Drawing a sprite on another sprite
Use the Screen! This is the easiest, safest and fastest method.
1. ClearScreen() with your transparent sprite color
2. DisplayTransparentSprite() your 1. Sprite
3. DisplayTransparentSprite() your 2. Sprite on the first
4. GrabSprite() the new Sprite from Screen
5. ClearScreen() with your standard background color
These actions are performed on the hidden screen buffer and will not be visible.
1. ClearScreen() with your transparent sprite color
2. DisplayTransparentSprite() your 1. Sprite
3. DisplayTransparentSprite() your 2. Sprite on the first
4. GrabSprite() the new Sprite from Screen
5. ClearScreen() with your standard background color
These actions are performed on the hidden screen buffer and will not be visible.
Re: 5.10 Drawing a sprite on another sprite
I never thought of that it sure beats using Plot/Point for each pixel which slows down the program with large images , just a question ; are these functions faster than using the 2D drawing ones ? i.e DrawImage GrabImage etc...Lebostein wrote:Use the Screen! This is the easiest, safest and fastest method.
1. ClearScreen() with your transparent sprite color
2. DisplayTransparentSprite() your 1. Sprite
3. DisplayTransparentSprite() your 2. Sprite on the first
4. GrabSprite() the new Sprite from Screen
5. ClearScreen() with your standard background color
These actions are performed on the hidden screen buffer and will not be visible.