Author Topic: antialias pixmap rotation [BMAX]  (Read 9120 times)

0 Members and 1 Guest are viewing this topic.

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
antialias pixmap rotation [BMAX]
« 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:
Code: [Select]
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

 
« Last Edit: October 19, 2007 by JumpMan »

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #1 on: October 19, 2007 »
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
Challenge Trophies Won:

Offline spitfire

  • Amiga 1200
  • ****
  • Posts: 275
  • Karma: 9
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #2 on: October 19, 2007 »
How do I run this program? (I don't know/have blitzbasic - it is blitzbasic right?)

Offline benny!

  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4384
  • Karma: 228
  • in this place forever!
    • View Profile
    • bennyschuetz.com - mycroBlog
Re: antialias pixmap rotation [BMAX]
« Reply #3 on: October 19, 2007 »
@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!
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #4 on: October 19, 2007 »
@ 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

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17414
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: antialias pixmap rotation [BMAX]
« Reply #5 on: October 19, 2007 »
Have some Karma, thanks for the source and I echo what Jim said :)
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #6 on: October 20, 2007 »
->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
Challenge Trophies Won:

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #7 on: October 20, 2007 »
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.

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #8 on: October 20, 2007 »
If you get fed a non-32 bit graphic, convert it to 32bit first and then work from the copy.

Jim
Challenge Trophies Won:

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #9 on: October 21, 2007 »
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.

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #10 on: October 22, 2007 »
well I managed to speed it up some still the weighted function is sloooooow. let me know  what you think

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #11 on: October 22, 2007 »
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
Challenge Trophies Won:

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #12 on: October 22, 2007 »
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:

Code: [Select]
'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.
« Last Edit: October 22, 2007 by Stonemonkey »

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #13 on: October 23, 2007 »
« Last Edit: October 23, 2007 by Stonemonkey »

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #14 on: October 23, 2007 »
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.

Offline Stonemonkey

  • Pentium
  • *****
  • Posts: 1315
  • Karma: 96
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #15 on: October 24, 2007 »
Quote
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.

Offline JumpMan

  • C= 64
  • **
  • Posts: 45
  • Karma: 11
    • View Profile
Re: antialias pixmap rotation [BMAX]
« Reply #16 on: October 24, 2007 »
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.