Dark Bit Factory & Gravity
PROGRAMMING => Other languages => Blitz => Topic started by: JumpMan on October 19, 2007
-
here is a bata of my pixmap antialias image rotation. it should work with any png image. and if you take away the framework it should work with any png, jpg or bmp. It does both weighted and unwheighted pixel transformation. it works with both alpha and non-alpha images. I don't think it has any bugs but let me know if you find any.
press:
1 for no antialias (normal speed)
2 for unweighted antialias(slow speed)
3 for weighted antialias ( slowest)
note: make shure it is running in release mode. debug mode can get quite slow.
as always if anybody find a way to speed this up I apreciate the help. and if any body can test it on a mac and let me know if it works(little endian big endian thing) I apreciate it also.
executable included:
SuperStrict
Rem
algoritm:
0 No antialias
1 Unweighted antialiasing
2 Weighted antialiasing
EndRem
' This sets the width of the block where only one pixel is selected
' It should be a multiple of 2
Const BW:Int = 2
Const W4S:Int = (8-BW/2)
Const W2W:Int = (BW)
Const W2H:Int = (8-BW/2)
Const CX1B:Float = (0.5-BW/2)
Const CY1B:Float = (8.5)
Const CX2B:Float = (0.5-BW/2)
Const CY2B:Float = (-7.5)
Const C1X:Float = 8.5
Const C1Y:Float = 8.5
Const C2X:Float =-7.5
Const C2Y:Float = 8.5
Const C3X:Float = 8.5
Const C3Y:Float =-7.5
Const C4X:Float =-7.5
Const C4Y:Float =-7.5
Const PRECISION:Int = 256'
Global clrColour:Int=0
Global algoritm:Int=0
Global BytesPerPixel:Int[] = [0,1,1,3,3,4,4]
Global convTableW4:Byte[W4S*W4S*4]
Global convTableW2:Byte[W2W*W2H*2]
Function putPixel(image:TPixmap, x%, y%, pixel%)
Local mem:Byte Ptr, bpp:Int
bpp = BytesPerPixel[image.format]
mem = image.pixels+y*image.pitch+x*bpp
Select bpp
Case 1 mem[0] = Byte(pixel)
Case 2 mem[0] = pixel
Case 3
mem[0] = (pixel & $FF)
mem[1] = (pixel Shr 8) & $FF
mem[2] = (pixel Shr 16) & $FF
Case 4 Int Ptr(mem)[0] = pixel '4 Byte/pixel
End Select
End Function
'** getPixel ***/
Function getPixel:Int(image:TPixmap, x%, y%)
Local pixel:Int
Local mem:Byte Ptr, bpp:Int
If((x<0) Or (y<0) Or (x>=image.width) Or (y>=image.height)) Return clrColour
bpp = BytesPerPixel[image.format]
mem = image.pixels +y*image.pitch+x*bpp
Select bpp
Case 1 Return mem[0]
Case 2 Return mem[0]|(mem[0] Shl 8)
Case 3 '24 bit pixel
Local r:Int, g:Int, b:Int
r = mem[0]
g = mem[1]
b = mem[2]
Return r | (g Shl 8) | (b Shl 16)
Case 4 Return Int Ptr(mem)[0]
End Select
End Function
Function mid2:Int(p1%, p2%)
Local r:Int, g:Int, b:Int,a:Int
a = (((p1 Shr 24) & $ff)+((p2 Shr 24) & $ff)) Shr 1
r = (((p1 Shr 16) & $ff)+((p2 Shr 16) & $ff)) Shr 1
g = (((p1 Shr 8 ) & $ff)+((p2 Shr 8 ) & $ff)) Shr 1
b = ((p1 & $ff)+(p2 & $ff)) Shr 1
Return (a Shl 24)|(r Shl 16) | (g Shl 8) | b
End Function
Function mid4:Int(p1%, p2%, p3%, p4%)
Local r:Int, g:Int, b:Int,a:Int
a = ( ((p1 Shr 24)&$ff)+((p2 Shr 24)&$ff)+((p3 Shr 24)&$ff)+((p4 Shr 24)&$ff))Shr 2
r = ( ((p1 Shr 16)&$ff)+((p2 Shr 16)&$ff)+((p3 Shr 16)&$ff)+((p4 Shr 16)&$ff))Shr 2
g = ( ((p1 Shr 8)&$ff)+((p2 Shr 8)&$ff)+((p3 Shr 8) &$ff)+((p4 Shr 8 )&$ff))Shr 2
b = ( (p1 &$ff)+(p2 &$ff)+(p3 &$ff)+(p4 &$ff) ) Shr 2
Return (a Shl 24)|(r Shl 16)|(g Shl 8)|b
End Function
Function calcPixel:Int(image:TPixmap, xpos%, ypos%)
Local x%, y%, px%, py%
Local pixelSelect:Int
x = xpos Shr 8
y = ypos Shr 8
px = xpos Shr 4
py = ypos Shr 4
px = px & $f
py = py & $f
pixelSelect = 0
If(px >= 12) pixelSelect :| 4
If(py >= 12) pixelSelect :| 8
If(px < 4) pixelSelect :| 2
If(py < 4) pixelSelect :| 1
Select pixelSelect
Case 0 ' Pick one pixel
Return getPixel(image,x,y)
Case 1 ' Weight two pixels, up
Return mid2(getPixel(image,x,y),getPixel(image,x,y-1))
Case 2 ' Weight two pixels, Left
Return mid2(getPixel(image,x,y), getPixel(image,x-1,y))
Case 3 ' Weight four pixels, Upper Left
Return mid4(getPixel(image,x,y), getPixel(image,x-1,y),getPixel(image,x,y-1),getPixel(image,x-1,y-1))
Case 4 ' Weight two pixels, Right
Return mid2(getPixel(image, x,y),getPixel(image,x+1,y))
Case 5 ' Weight four pixels, Upper Right
Return mid4(getPixel(image,x,y),getPixel(image,x+1,y),getPixel(image,x,y-1),getPixel(image,x+1,y-1))
Case 8 ' Weight two pixels, Lower
Return mid2(getPixel(image,x,y),getPixel(image,x,y+1))
Case 10 ' Weight four pixels, Lower Left
Return mid4(getPixel(image,x,y),getPixel(image,x-1,y),getPixel(image,x,y+1),getPixel(image,x-1,y+1))
Case 12 ' Weight four pixels, Lower Right
Return mid4(getPixel(image,x,y),getPixel(image,x+1,y),getPixel(image,x,y+1),getPixel(image,x+1,y+1))
End Select
End Function
Function midw2:Int(p1%, p2%, px%, py%)
Local r:Int, g:Int, b:Int,a:Int
Local w1:Int, w2:Int
If(px+py)>(W2W-1+W2H-1) Notify " Out of bounds!"
w1 = convTableW2[(px+py*W2W) Shl 1]
w2 = convTableW2[(px+py*W2W) Shl 1+1]
a = ( ((p1 Shr 24)&$ff)*w1 + ((p2 Shr 24)&$ff)*w2 ) Shr 5
r = ( ((p1 Shr 16)&$ff)*w1 + ((p2 Shr 16)&$ff)*w2 ) Shr 5
g = ( ((p1 Shr 8)&$ff )*w1 + ((p2 Shr 8 )&$ff)*w2 ) Shr 5
b = ( (p1&$ff)*w1 +( p2&$ff)*w2 ) Shr 5
Return (a Shl 24) | (r Shl 16) | (g Shl 8) | b
End Function
Function midw4:Int(p1%, p2%, p3%, p4%, wx%, wy%)
Local x:Int
Local r:Int, g:Int, b:Int,a:Int
Local w1:Int, w2:Int, w3:Int, w4:Int
Local convTable2:Int[] = [0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0]
wx = convTable2[wx]
wy = convTable2[wy]
w1 = convTableW4[(wx+wy*W4S)Shl 2+ 0]
w2 = convTableW4[(wx+wy*W4S)Shl 2+ 1]
w3 = convTableW4[(wx+wy*W4S)Shl 2+ 2]
w4 = convTableW4[(wx+wy*W4S)Shl 2+ 3]
a = (((p1 Shr 24)&$ff)*w1+((p2 Shr 24)&$ff)*w2+((p3 Shr 24)&$ff)*w3+((p4 Shr 24)&$ff)*w4)Shr 5
r = (((p1 Shr 16)&$ff)*w1+((p2 Shr 16)&$ff)*w2+((p3 Shr 16)&$ff)*w3+((p4 Shr 16)&$ff)*w4)Shr 5
g = (((p1 Shr 8)&$ff)*w1+((p2 Shr 8)&$ff)*w2+((p3 Shr 8 )&$ff)*w3+((p4 Shr 8)&$ff)*w4)Shr 5
b = ((p1&$ff)*w1+(p2&$ff)*w2+(p3&$ff)*w3+(p4&$ff)*w4 )Shr 5
Return (r Shl 16) | (g Shl 8) | b
End Function
Function rint:Float(n:Float)
If n<0 Return Floor(n)
If n> 0 Return Ceil(n)
Return n
End Function
Function calcWeightedPixel:Int(image:TPixmap, xpos%, ypos%)
Local x%, y%, px%, py%
Local pixelSelect:Int
Local p1%, p2%, p3%, p4%
x = xpos Shr 8
y = ypos Shr 8
px = xpos Shr 4
py = ypos Shr 4
px = px & $f
py = py & $f
pixelSelect = 0
If(px >= (8+BW/2)) pixelSelect :| 4
If(py >= (8+BW/2)) pixelSelect :| 8
If(px < (8-BW/2)) pixelSelect :| 2
If(py < (8-BW/2)) pixelSelect :| 1
Select pixelSelect
Case 0 ' Pick one pixel
Return getPixel(image, x, y)
Case 1 ' Weight two pixels, up
p1 = getPixel(image, x, y-1)
p2 = getPixel(image, x, y)
Return midw2(p1, p2, px-(8-BW/2), py)
Case 2 ' Weight two pixels, Left
p1 = getPixel(image, x-1, y)
p2 = getPixel(image, x, y)
Return midw2(p1, p2, py-(8-BW/2), px)
Case 3 ' Weight four pixels, up Left
p1 = getPixel(image, x-1, y-1)
p2 = getPixel(image, x, y-1)
p3 = getPixel(image, x-1, y)
p4 = getPixel(image, x, y)
Return midw4(p1, p2, p3, p4, px, py)
Case 4 ' Weight two pixels, Right
p1 = getPixel(image, x+1, y)
p2 = getPixel(image, x, y)
Return midw2(p1, p2, py-(8-BW/2), 15-px)
Case 5 ' Weight four pixels, up Right
p1 = getPixel(image, x+1, y-1)
p2 = getPixel(image, x, y-1)
p3 = getPixel(image, x+1, y)
p4 = getPixel(image, x, y)
Return midw4(p1, p2, p3, p4, px, py)
Case 8 ' Weight two pixels, down
p1 = getPixel(image, x, y+1)
p2 = getPixel(image, x, y)
Return midw2(p1, p2, px-(8-BW/2), 15-py)
Case 10 ' Weight four pixels, down Left
p1 = getPixel(image, x-1, y+1)
p2 = getPixel(image, x, y+1)
p3 = getPixel(image, x-1, y)
p4 = getPixel(image, x, y)
Return midw4(p1, p2, p3, p4, px, py)
Case 12 ' Weight four pixels, down Right
p1 = getPixel(image, x+1, y+1)
p2 = getPixel(image, x, y+1)
p3 = getPixel(image, x+1, y)
p4 = getPixel(image, x, y)
Return midw4(p1, p2, p3, p4, px, py)
End Select
End Function
Function drawRotateImage(image:TPixmap, canvas:TPixmap, v#)
Local x%, y%
Local mag% = 1
'--------- Beginning of rotate routine ------------
Local sinv:Int, cosv:Int ' Holds sinus And cosius values
Local startx:Int, starty:Int ' Holds start values
Local zoom:Int,pw:Int,ph:Int
Local imagePosX:Int, imagePosY:Int
Local tmpImagePosX:Int, tmpImagePosY:Int
Local pixelSelect:Int
Local px:Int, py:Int
Local pixel:Int
Local src:Byte Ptr, dest:Byte Ptr, srcbpp:Int, destbpp:Int
zoom = 100
sinv = rint((Sin(v)*PRECISION))
cosv = rint((Cos(v)*PRECISION))
startx = (Image.Width Shr 1)*PRECISION + PRECISION Shr 1
starty = (Image.Height Shr 1)*PRECISION + PRECISION Shr 1
startx :+ (Canvas.Width Shr 1)*(-cosv) + (Canvas.height Shr 1)*sinv
starty :- (Canvas.Width Shr 1)* sinv + (Canvas.Height Shr 1)*cosv
'************** First Field *****************/
'--- Start of Y-loop
imagePosX = startx
imagePosY = starty
pw = Canvas.Width*PRECISION
ph = Canvas.Height*PRECISION
For y=0 Until Canvas.Height Step 2
' Make temp copies of image counters For use in x loop
tmpImagePosX = imagePosX
tmpImagePosY = imagePosY
' Update image pos counter For Next row
imagePosX = imagePosX - sinv Shl 1
imagePosY = imagePosY + cosv Shl 1
'--- Start of X-loop
For x = 0 Until Canvas.Width
pixel = clrColour ' Default colour For cleared corners
If((tmpImagePosX>0) & (tmpImagePosX<(pw)) & (tmpImagePosY>0) & (tmpImagePosY<ph))
Select(algoritm)
Case 0 pixel = getPixel(image, tmpImagePosX Shr 8, tmpImagePosY Shr 8)
Case 1 pixel = calcPixel(image, tmpImagePosX, tmpImagePosY)
Case 2 pixel = calcWeightedPixel(image, tmpImagePosX, tmpImagePosY)
End Select
EndIf
tmpImagePosX = tmpImagePosX + cosv
tmpImagePosY = tmpImagePosY + sinv
putPixel(canvas, x, y, pixel)
Next
Next
'************** Second Field *****************/
imagePosX = startx - sinv
imagePosY = starty + cosv
'--- Start of Y-loop
For y = 0 Until Canvas.Height Step 2
' Make temp copies of image counters For use in x loop
tmpImagePosX = imagePosX
tmpImagePosY = imagePosY
' One Step For odd frames
imagePosX = imagePosX - sinv Shl 1
imagePosY = imagePosY + cosv Shl 1
'--- Start of X-loop
For x = 0 Until Canvas.Width
pixel = clrColour ' Default colour For cleared corners
If((tmpImagePosX>0) & (tmpImagePosX<(pw)) & (tmpImagePosY>0) & (tmpImagePosY<ph))
Select(algoritm)
Case 0 pixel = getPixel(image, tmpImagePosX Shr 8, tmpImagePosY Shr 8)
Case 1 pixel = calcPixel(image, tmpImagePosX, tmpImagePosY)
Case 2 pixel = calcWeightedPixel(image, tmpImagePosX, tmpImagePosY)
End Select
EndIf
' Update temp image pos counter For Next pixel in row
tmpImagePosX = tmpImagePosX + cosv
tmpImagePosY = tmpImagePosY + sinv
putPixel(canvas, x, y+1, pixel)
Next
Next
'------------ End of rotate routine ---------------
End Function
Function invl:Double(l:Double)
l = 15 - l
If(l<0) l = 0
Return l
End Function
Function scalar4:Double(w1:Double, w2:Double, w3:Double, w4:Double)
Return 32.0/(w1+w2+w3+w4)
End Function
Function scalar2:Double(w1:Double, w2:Double)
Return 32/(w1+w2)
End Function
Function calcTables()
Local x:Int, y:Int, i:Int
Local l1:Double, l2:Double, l3:Double, l4:Double
Local w1:Int, w2:Int, w3:Int, w4:Int
Local s:Double
Local d1:Double, d2:Double, d3:Double, d4:Double
' Calc 4-weight table
For y=0 Until (8-2/2)
For x=0 Until (8-2/2)
l1=invl(Sqr((C1X+x)*(C1X+x) + (C1Y+y)*(C1Y+y)))
l2=invl(Sqr((C2X+x)*(C2X+x) + (C2Y+y)*(C2Y+y)))
l3=invl(Sqr((C3X+x)*(C3X+x) + (C3Y+y)*(C3Y+y)))
l4=invl(Sqr((C4X+x)*(C4X+x) + (C4Y+y)*(C4Y+y)))
s = scalar4(l1, l2, l3, l4)
w1 = rint(l1*s)
w2 = rint(l2*s)
w3 = rint(l3*s)
w4 = rint(l4*s)
If(w1+w2+w3+w4 <> 32)
d1 = Abs(l1*s-w1)
d2 = Abs(l1*s-w1)
d3 = Abs(l1*s-w1)
d4 = Abs(l1*s-w1)
If((d1<d2) And (d1<d3) And (d1<d4))
w1 = w1 + (32-w1-w2-w3-w4)
Else
If((d2<d3) & (d2<d4))
w2 = w2 + (32-w1-w2-w3-w4)
Else
If(d3<d4) w3 = w3 + (32-w1-w2-w3-w4) Else w4 = w4 + (32-w1-w2-w3-w4)
EndIf
EndIf
EndIf
convTableW4[(x+y*(8-2/2))*4+0] = w1
convTableW4[(x+y*(8-2/2))*4+1] = w2
convTableW4[(x+y*(8-2/2))*4+2] = w3
convTableW4[(x+y*(8-2/2))*4+3] = w4
Next
Next
' Calc 2-weight table
For y = 0 Until (8-BW/2)
For x=0 Until BW
l1 = Sqr((CX1B+x)*(CX1B+x) + (CY1B+y)*(CY1B+y))
l2 = Sqr((CX2B+x)*(CX2B+x) + (CY2B+y)*(CY2B+y))
l1 = invl(l1)
l2 = invl(l2)
s = scalar2(l1, l2)
w1 = rint(l1*s)
w2 = rint(l2*s)
If(w1+w2 <> 32)
If((Abs(l1*s-w1)) < (Abs(l2*s-w2)))
w1 = w1 + (32-w1-w2)
Else
w2 = w2 + (32-w1-w2)
EndIf
EndIf
convTableW2[(x+y*(2))*2 + 0] = w1
convTableW2[(x+y*(2))*2 + 1] = w2
Next
Next
End Function
Function CreateCanvas:TPixmap(image:TPixmap)
Local D% = Sqr((image.width)^2+(image.height)^2)+1
D = (D Shr 1) Shl 1
Return CreatePixmap(D,D,image.format)
End Function
Global fps:Float, fpst:Float,fpsc:Float
Function CountFPS:Float()
If fpst < MilliSecs() Then
fpst=MilliSecs()+1000
fps = fpsc
fpsc = 0
Else
fpsc = fpsc + 1
End If
Return fps
End Function
Local canvas:TPixmap
Local image:TPixmap
Local v:Float= 0,dv:Float
Local motion:Int=1,update:Int=0
Local getEvent:Int,i:Int,x:Int, y:Int
calcTables()
Graphics 640,480,32
image = LoadPixmap("image.png")
If (image = Null) Notify "Could not load file"
canvas = CreateCanvas(image)
While Not KeyDown(key_escape)
Cls
dv = 0
update = motion
Select True
Case KeyDown(KEY_UP) dv = dv + 01.5; update = 1
Case KeyDown(KEY_DOWN) dv = dv - 01.5; update = 1
Case KeyDown(KEY_LCONTROL) v = 0; dv = 0; update = 1
Case KeyDown(KEY_LEFT) clrColour :- $080808; update = 1
Case KeyDown(KEY_RIGHT) clrColour :+ $080808; update = 1
Case KeyDown(KEY_1)
If(algoritm <>0)
algoritm = 0
update = 1
EndIf
Case KeyDown(KEY_2)
If(algoritm <>1)
algoritm = 1
update = 1
EndIf
Case KeyDown(KEY_3)
If(algoritm<>2)
algoritm = 2
update = 1
EndIf
End Select
If((dv <> 0) | (update))
v = v + dv
drawRotateImage(image, canvas, v)
motion = 0
EndIf
DrawPixmap canvas,150,100
DrawText ("FPS:"+(Int(CountFPS())),20,0)
DrawText "1: No antialias",20,15
DrawText "2: Unweighted antialiasing",20,30
DrawText "3: Weighted antialiasing", 20 ,45
DrawText "Left/Rigth: arrow canvas color",20,60
DrawText "Up/Down: set Rotation angle",20,75
DrawText "image Width = "+image.width,300,15
DrawText "image height = "+image.height,300,30
DrawText "canvas width = "+canvas.width,300,45
DrawText "canvas Height= "+canvas.height,300,60
Flip(0)
Wend
-
The difference is pretty dramatic isn't it? The unweighted is a good trade off for speed/quality. The weighted looks a bit better but it too slow for real time. I wonder if there's any good way of speeding it up?
Thanks for posting! K+
Jim
-
How do I run this program? (I don't know/have blitzbasic - it is blitzbasic right?)
-
@spitfire:
There is an exe in the attached .zip. Simply uninstall the whole zip. Change the folder
to "rotate antialias"[/i" and execute rtr4.exe.
@JumpMan:
Nice work!
-
@ jim, Thanks. I have been braking my head trying to get it to move faster but thats the best my limited skills can do. Maybe somebody have a better algorith. I will keep looking around for a better way. oh, how I wish bmax had built in asm integration.
@spitfire, no it's BlitzMax, it shouldn't be too hard to convert.
@Benny, Thank's
-
Have some Karma, thanks for the source and I echo what Jim said :)
-
->Jumpman
You can make it a lot faster by removing the Select/Case outside the loop. ie. have 3 different loops, and then putting the code fro getPixel/calcPixel/calcWeightedPixel inline inside each loop.
That will eliminate a load of If tests and function calls.
Rewrite getPixel to only support one format - look at all the code in there, you're doing all of that every single time you read a pixel, so millions of times you check what the display format is when it will never change :)
I suggest you just support 32 bits.
Jim
-
The reason I am using it like this is to process images from with in memory that are created on the fly. Shure, I can hardware rotate them on the fly. It is one of the qualities of Bmax. but if I want to modify an image on the fly without disturbing video memory, I have to work with pixmaps. if I want to work with prefabricated images I have to accept whatever format is available. so the single format is not an option. but you are right I can separate the different type of format in a single process group each. it will do pretty much what you said. you know, that crossed my mind before but I didn't considered it such a big deal until you mentioned it. so now it's like duh. I will post any modifications to the code as soon as I am done with it. thanks Jim.
@Shockwave, thanks.
-
If you get fed a non-32 bit graphic, convert it to 32bit first and then work from the copy.
Jim
-
why didn't I think of that? Thanks Jim.
I guess sacrificing a bit more memory fo the sake of speed is a fair tradeoff in this case.
I am half way down the convertion. and now thanks to you I am going to add the pixmap convertion function which shouldn't be too hard.
-
well I managed to speed it up some still the weighted function is sloooooow. let me know what you think
-
Much better ;D
The next massive, massive improvement is going to come from getting rid of the clipping from inside the loops.
One way to remove it would be always making a new image (like you've done with non 32bit sources), and making it 1 pixel larger in every dimension, and duplicating the edge pixels into the blank area.
Another way is to make the loops smaller, so instead of 0-width-1 they go from 1-width-2. That might mean you miss some pixels from the destination though.
Another way is if your texture is power-of-2 wide and high, you can use an AND to wrap the texture lookups.
ie.
(x+1)AND (width-1)
when width is a power of 2 will wrap x back to 0 when it overruns.
With non-power-of-2 MOD will work instead of AND, but will be a fair bit slower (it uses a divide internally).
Another huge improvement in speed might come from a slight loss of precision. In the blending, you split the 32 bit colour into r,g,b, do the blend, then go back to a 32bit colour.
You can avoid that by going...
colour0 = colour0 AND $00fefefe
colour1 = colour1 AND $00fefefe
blend50_50=(colour0+colour1) shr 1
Stonemonkey's been doing a lot of experimentation with blending and he might be able to help.
Food for thought!
Jim
-
Looks good, I used similar filtering for texturing and thought it could be used for sprite rotations and things like that too.
I know that blitzbasic had fairly large overheads for function calls but I don't know about bmax, I imagine it'll be much better although there'll still be some.
For blending, as Jim said for 50/50 blending you can mask out the low bit from each colour component of both sources and just add the results and shift 1 bit right. You lose a little of the colour information but it's not really noticable in most cases.
For weighted blending (and a lot of other calculations involving 24/32 bit colour) you don't need to shift the red and green values down to the low 8 bits, you can do the calcs where they are and you can calculate the red and blue together (and green and alpha together) and it only needs masking and 1 shift to move the results to the right bits.
I'm not really sure why you're using lookup tables, I did it something like this:
'FreeBasic code
'u_blend and v_blend in the range 0-255 which represent the fractional part between pixels
function blend4(byval argb0 as unsigned integer,byval argb1 as unsigned integer,_
byval argb2 as unsigned integer,byval argb3 as unsigned integer,_
byval u_blend as unsigned integer,byval v_blend as unsigned integer)as unsigned integer
'add 1 for accuracy, otherwise small loss of colour information
u_blend+=1
v_blend+=1
'calculate weights for each corner
dim as unsigned integer tl=((257-u_blend)*(257-v_blend))shr 8
dim as unsigned integer tr=(u_blend*(257-v_blend))shr 8
dim as unsigned integer bl=((257-u_blend)*v_blend)shr 8
dim as unsigned integer br=(u_blend*v_blend)shr 8
dim as unsigned integer _r_b,a_g_
'add up the red and blue components
_r_b=(((argb0 and &hff00ff)*tl)+((argb1 and &hff00ff)*tr)+((argb2 and &hff00ff)*bl)+((argb3 and &hff00ff)*br))
'shift all source colour bits right 8(not required if not calculating for alpha but the result would need shifted when returning the result)
argb0 shr=8
argb1 shr=8
argb2 shr=8
argb3 shr=8
'add up the green and alpha components
a_g_=(((argb0 and &hff00ff)*tl)+((argb1 and &hff00ff)*tr)+((argb2 and &hff00ff)*bl)+((argb3 and &hff00ff)*br))
'mask bits (and shift _r_b) and OR together to return the result
return ((_r_b shr 8)and &hff00ff)or(a_g_ and &hff00ff00)
end function
It uses 8 bits for the fractional values so you'd need to do something like:
px=xpos & $ff
py=ypos & $ff
A big problem though is that it does have to look up 4 source pixels and I've not come up with any solution for that yet.
-
Some more info on blending:
http://www.stereopsis.com/doubleblend.html
-
Thanks StoneMonkey I will look in to it.
the antialias routines are not mine. I modified them from some sorce code I had from years back. I believe the reason for the tables is that it is using integer math and it is using it to shift the floating point precision left or right(I know, old code). I have little knowledge of color manipulation, although I do understand what you and Jim are explaining. I like the 50/50 blending and the texture lookup wrap. I will try to implement both of them.
maybe silly question:
how bad would it be to zero out 2 bits for each color in a pixel for a four pixel look up.such as $00fcfcfc. is it functional? I don't know how much it would affect the quality. I might try it later on, out of curiosity.
-
maybe silly question:
how bad would it be to zero out 2 bits for each color in a pixel for a four pixel look up.such as $00fcfcfc. is it functional? I don't know how much it would affect the quality. I might try it later on, out of curiosity.
It works but depending on the image it can be noticable, particularly with images with areas of gradient colouring.
-
yes, I tried it. I think it is usable for most of my applications. and it speeds up about 15 percent. I will keep gradiets in mind. thanks.