Code archives/Graphics/Ultra Fast Draw Pixmap on Pixmap
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
| This is the fastest method I could come up with to draw a pixmap onto another pixmap. On a 2.4Ghz its about 7-8ms for 1000x1000px per pixmap (no debug). (ReadPixel and WritePixel are a little slower than using this direct memory method.) The caveats are you are using only RGBA, and you are plotting a source alpha pixmap onto a static alpha-ignored pixmap. It's best to convert RGBA before sending your pixmaps to this function. Additionally, this is unmultiplied alpha. If anyone needs multiplied alpha, I can offer some code assistance (may be even faster). Added an x,y offset and opacity when applying the source pixmap to destination. Big thanks to ImaginaryHuman for starting this out. Optimized alpha-blending code found on various places with Google. Edit: use at your own risk, but let me know if there are problems, I'd be happy to help. Also, I experienced a wrap-around defect or large vaules of x offset, but easily fixed-- but let me know if anyone gets this problem. | |||||
Function UltraDrawPixmapOnPixmap(spix:TPixmap, pixmap:TPixmap, x:Int, y:Int, opacity:Int = $ff) NoDebug
'' if your pixmaps are rgba8888 then it will work faster
'' ARGB is byte order
'' non-multiplied alpha
Local sourcepixel:Int Ptr, osp:Int Ptr
Local destpixel:Int Ptr, dsp:Int Ptr
Local sAlpha:Int
If (Not spix Or Not pixmap) Then Return
If spix.format<>PF_RGBA8888 spix = ConvertPixmap(spix, PF_RGBA8888 )
If pixmap.format<>PF_RGBA8888 pixmap = ConvertPixmap(pixmap, PF_RGBA8888 )
Local sWidth:Int=spix.Width
Local sHeight:Int=spix.Height
Local dWidth:Int=pixmap.Width
Local dHeight:Int=pixmap.Height
sourcepixel=Int Ptr(PixmapPixelPtr(spix,0,0))
destpixel=Int Ptr(PixmapPixelPtr(pixmap,0,0))
Local sRowInts:Int= spix.pitch Shr 2 '' 4 bytes to int
Local dRowInts:Int= pixmap.pitch Shr 2
''crop the image
If ( (x+sWidth)>=dWidth) Then sWidth=dWidth-x '-2 'if you get wraparound issues
If ( (y+sHeight)>=dHeight) Then sHeight=dHeight-y
If(y<0)
y = Abs(y)
sourcepixel :+(y*sRowInts)
sHeight :-y
y=0
EndIf
If(x<0)
sourcepixel :+(-x)
sWidth :+x
x=0
EndIf
destpixel = destpixel + x +(y*dRowInts)
dsp = destpixel
osp = sourcepixel
Local Mask:Int=$000000FF
For Local j:Int=0 To (sHeight)
For Local i:Int =0 To (sWidth) Step 2 'dRowInts
Local sPixel:Int
sPixel = sourcepixel[i]
sAlpha=(sPixel Shr 24) & $000000ff & opacity
Local dPixel:Int = destpixel[i]
''''straight alpha (unmultiplied)
'Local dAlpha:Int = dPixel Shr 24 & Mask ''untested: alpha onto alpha
'Local fa:Int = sAlpha + ((256-sAlpha)*dAlpha) Shr 8 ''untested: alpha onto alpha
Local srb:Int = sPixel & $00ff00ff
Local sg:Int = sPixel & $0000ff00
Local drb:Int = dPixel & $00ff00ff
Local dg:Int = dPixel & $0000ff00
Local orb:Int = (drb + (((srb - drb) * sAlpha + $00800080) Shr 8)) & $00ff00ff
Local og:Int = (dg + (((sg - dg ) * sAlpha + $00008000) Shr 8)) & $0000ff00
destPixel[i] = orb | og | $ff000000 ''no need for alpha blending if its on static bg
''lets do it again
If ( i >= dWidth And (sWidth & 1))
''odd length, dont draw
Else
sPixel = sourcepixel[i+1]
sAlpha=(sPixel Shr 24) & $000000ff & opacity
dPixel:Int = destpixel[i+1]
srb:Int = sPixel & $00ff00ff
sg:Int = sPixel & $0000ff00
drb:Int = dPixel & $00ff00ff
dg:Int = dPixel & $0000ff00
orb:Int = (drb + (((srb - drb) * sAlpha + $00800080) Shr 8)) & $00ff00ff
og:Int = (dg + (((sg - dg ) * sAlpha + $00008000) Shr 8)) & $0000ff00
destPixel[i+1] = orb | og | $ff000000
EndIf
Next
sourcepixel= osp + sRowInts*j ''need these to truncate off any extra bytes
destpixel = dsp + dRowInts*j
Next
End Function |
Comments
None.
Code Archives Forum