Page 1 of 1
5.10 Drawing a sprite on another sprite
Posted: Mon Feb 18, 2013 9:00 pm
by Nubcake
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
Re: 5.10 Drawing a sprite on another sprite
Posted: Mon Feb 18, 2013 9:49 pm
by IceSoft
Yes. Use the MP3D engine. But it is Windows only.
Re: 5.10 Drawing a sprite on another sprite
Posted: Mon Feb 18, 2013 11:02 pm
by Nubcake
IceSoft wrote:Yes. Use the MP3D engine. But it is Windows only.
Well if that's the case , how does one draw a transparent image of selected color directly to the screen ? Is that possible ?
Re: 5.10 Drawing a sprite on another sprite
Posted: Thu Feb 21, 2013 12:28 am
by Nubcake
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)
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
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.
Code: Select all
*Memory = AllocateMemory((ImageWidth(Image) * ImageHeight(Image) * 4))
Also by storing the pixel I don't understand the method behind the offset either.
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
Posted: Thu Feb 21, 2013 11:30 am
by Fig
Nubcake wrote:
Code: Select all
*Memory = AllocateMemory((ImageWidth(Image) * ImageHeight(Image) * 4))
Also by storing the pixel I don't understand the method behind the offset either.
Code: Select all
PokeL(*Memory + (y*ImageWidth(Image)+x)*4,Point(x,y))
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)
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
Re: 5.10 Drawing a sprite on another sprite
Posted: Fri Feb 22, 2013 8:17 pm
by Thorium
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
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:
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()
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.
Re: 5.10 Drawing a sprite on another sprite
Posted: Fri Feb 22, 2013 10:32 pm
by Nubcake
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:
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()
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.
So this code would be faster than the original ?
Re: 5.10 Drawing a sprite on another sprite
Posted: Sat Feb 23, 2013 11:03 am
by Fig
The calculation is correct for CPC6128
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
Re: 5.10 Drawing a sprite on another sprite
Posted: Tue Feb 26, 2013 11:05 am
by Lebostein
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.
Re: 5.10 Drawing a sprite on another sprite
Posted: Thu Feb 28, 2013 10:30 pm
by Nubcake
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.
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...