Dark Bit Factory & Gravity
PROGRAMMING => Other languages => Blitz => Topic started by: Paul on October 06, 2007
-
Hi
Here's a lens effect that i made, could probably get it more optimised, but i don't know how :(
Used Mike_g's colourblend, hope thats ok.
Use the mousewheel or up and down to change the magnification
Const gx=1024,gy=768
Graphics gx,gy,32,1
SetBuffer BackBuffer()
Dim buffer(gx,gy)
Local image=LoadImage("C:\Users\paul\Desktop\Paul\mekis0fx200g1a.jpg")
If image=0 Then RuntimeError("Image failed to load")
If ImageWidth (image)>gx Then BX=gx-1 Else bx=ImageWidth (image)-1;check to see that we don't load an image thats bigger than our aray(x)
If ImageHeight(image)>gy Then By=gy-1 Else by=ImageHeight(image)-1;-----------------------------------!!------------------------------(y)
LockBuffer ImageBuffer(image);copy image inteo an array
For x=0 To bx
For y=0 To by
buffer(x,y)=ReadPixelFast(x,y,ImageBuffer(image))
Next
Next
UnlockBuffer ImageBuffer(image)
Global r#=50
While Not KeyHit(1)
DrawImage(image,0,0)
r#=r#+KeyDown(208)-KeyDown(200)+MouseZSpeed()
If KeyHit(203)+KeyHit(205) Then r#=60
LockBuffer
magnify(200,MouseX(),MouseY())
UnlockBuffer
Text 0,20,r#-50
;-------------------------------------------------------------------------
frame=frame+1;FPS timer
If MilliSecs()>time
time=MilliSecs()+1000
frames=frame
frame=0
EndIf
Text 0,0,"FPS:"+frames
;-------------------------------------------------------------------------
Flip 0
Cls
Wend
Function magnify(radius,cx,cy)
Local x,y,half_row_width,tx,ty,ang#,dist#
Local tx2#,ty2#
For y=-radius To radius
half_row_width=Sqr(radius^2-y^2)
For x=-half_row_width To half_row_width
tx=(cx+x) ;Get the current x drawing position
ty=(cy+y) ;Get the current y drawing position
ang#=ATan2(x,y) ;get the angle betwen the centre and the current pixel being drawn
;dist#=Sin(Sqr(x*x+y*y)/0.5)*(100)
dist#=(x*x+y*y)/500+Sqr(x*x+y*y)*r#/100 ;Get the distance ----------------------!!-------------------------
If tx>0 And ty>0 And tx<gx And ty<gy ;make sure we arent drawing outside the screen
tx2#=cx+Sin(ang)*dist ;precalcute the x
ty2#=cy+Cos(ang)*dist ; and y position
If tx2#>0 And tx2#<gx And ty2#>0 And ty2#<gy ; make sure we arent readin from outside the screen
x1=Floor(tx2#) ;Get the low x cordinate
x2=Ceil (tx2#) ;Get the high x cordinate
y1=Floor(ty2#) ;Get the low y cordinate
y2=Ceil (ty2#) ;Get the high y cordinate
col1=ColourBlend(buffer(x2,y1),buffer(x1,y1),(tx2#-x1)*256) ; blend the two colors with the difference betwen their two positions
col2=ColourBlend(buffer(x2,y2),buffer(x1,y2),(tx2#-x1)*256) ; in the x direction
col1=ColourBlend(col2,col1,(ty2#-y1)*256) ; and the y dirrection
WritePixelFast(tx,ty,col1) ; then draw it all to the screen
Else
WritePixelFast(tx,ty,0) ;if we try to draw to the screen but try to read from outside the screen then draw a black pixel
EndIf
EndIf
Next
Next
End Function
Function ColourBlend( rgb_1, rgb_2, alpha_1 );Mike_g's colour blend routine
alpha_2 = 256 - alpha_1
rb_1 = ((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00
g_1 = ((rgb_1 And $0000FF00) * alpha_1) And $00FF0000
rb_2 = ((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00
g_2 = ((rgb_2 And $0000FF00) * alpha_2) And $00FF0000
rb_1 = rb_1 + rb_2
g_1 = g_1 + g_2
Return (rb_1 Or g_1) Sar 8
End Function
-
You can of course precalc the x&y&alpha coefs once and for all.
-
Thats a good ide, why didn't i think of that?
-
Got that implemented, and it's like 4x faster thx allot :)
And made the colourblend function inline. these two changes made if 5x faster than the original!
Hold the first mousebutton down to use the precalculated function instead of the other one.
Any thing else i can do to make it faster?
Const gx=1024,gy=768
Graphics gx,gy,32
SetBuffer BackBuffer()
Dim buffer(gx,gy)
Local image=LoadImage("C:\Users\paul\Desktop\Paul\mekis0fx200g1a.jpg")
If image=0 Then RuntimeError("Image failed to load")
If ImageWidth (image)>gx Then BX=gx-1 Else bx=ImageWidth (image)-1;check to see that we don't load an image thats bigger than our aray(x)
If ImageHeight(image)>gy Then By=gy-1 Else by=ImageHeight(image)-1;-----------------------------------!!------------------------------(y)
LockBuffer ImageBuffer(image);copy image inteo an array
For x=0 To bx
For y=0 To by
buffer(x,y)=ReadPixelFast(x,y,ImageBuffer(image))
Next
Next
UnlockBuffer ImageBuffer(image)
Global r#=50,size=200
magnifyPC(size)
While Not KeyHit(1)
DrawImage(image,0,0)
r#=MouseZ()+50
If MouseZSpeed() Then magnifyPC(size)
LockBuffer
If MouseDown(1)
magnifyP(size,MouseX(),MouseY())
Else
magnify(size,MouseX(),MouseY())
EndIf
UnlockBuffer
;-------------------------------------------------------------------------
frame=frame+1;FPS timer
If MilliSecs()>time
time=MilliSecs()+1000
frames=frame
frame=0
EndIf
Text 0,0,"FPS:"+frames
;-------------------------------------------------------------------------
Flip 0
Cls
Wend
Dim magny#(0,0)
Dim magny2(0,0)
Function magnifyPC(radius)
Local x,y,half_row_width,tx,ty,ang#,dist#
Local tx2#,ty2#
Dim magny#(Ceil((radius+1)^2*Pi),1)
Dim magny2(Ceil((radius+1)^2*Pi),3)
DebugLog Ceil(radius^2*Pi)
TR#=r#/Float(100)
del#=Float(1)/500
For y=-radius To radius
half_row_width=Sqr(radius^2-y^2)
For x=-half_row_width To half_row_width
tx=(cx+x) ;Get the current x drawing position
ty=(cy+y) ;Get the current y drawing position
i=i+1
ang#=ATan2(x,y) ;get the angle betwen the centre and the current pixel being drawn
;dist#=Sin(Sqr(x*x+y*y)/0.5)*(100)
dist#=Float(x*x+y*y)*del+Sqr(x*x+y*y)*TR#;r#/100 ;Get the distance ----------------------!!-------------------------
;dist=Sin(Sqr((x*x+y*y)*0.45)+40)*Sqr((x*x+y*y))
tx2#=cx+Sin(ang)*dist ;precalcute the x
ty2#=cy+Cos(ang)*dist
x1=Floor(tx2#) ;Get the low x cordinate
;x2=Ceil (tx2#) ;Get the high x cordinate
y1=Floor(ty2#) ;Get the low y cordinate
;y2=Ceil (ty2#) ;Get the high y cordinate
magny(i,0)=tx2# ;Svae the x read value
magny(i,1)=ty2# ;and teh y read value
magny2(i,0)=x1 ;save x nd y values for blending
;magny2(i,1)=x2 ;...
magny2(i,1)=y1 ;...
;magny2(i,3)=y2 ;...
Next
Next
End Function
Function magnifyP(radius,cx,cy)
Local x,y,half_row_width,tx,ty,i
Local tx2#,ty2#
Local rgb_1,rgb_2,alpha_1,alpha_2,x1,x2,y1,y2,col1
For y=-radius To radius
half_row_width=Sqr(radius^2-y^2)
For x=-half_row_width To half_row_width
tx=(cx+x) ;Get the current x drawing position
ty=(cy+y) ;Get the current y drawing position
i=i+1
If tx>0 And ty>0 And tx<gx And ty<gy ;make sure we arent drawing outside the screen
tx2#=magny(i,0)+cx;+Sin(ang)*dist ;precalcute the x
ty2#=magny(i,1)+cy;+Cos(ang)*dist ; and y position
If tx2#>0 And tx2#<gx And ty2#>0 And ty2#<gy ; make sure we arent readin from outside the screen
x1=magny2(i,0)+cx;Floor(tx2#) ;Get the low x cordinate
x2=x1+1
y1=magny2(i,1)+cy;Floor(ty2#) ;Get the low y cordinate
y2=y1+1
;col1=ColourBlend(buffer(x2,y1),buffer(x1,y1),(tx2#-x1) *256) ; blend the two colors with the difference betwen their two positions
;col2=ColourBlend(buffer(x2,y2),buffer(x1,y2),(tx2#-x1) *256) ; in the x direction
;col1=ColourBlend(col2,col1,(ty2#-y1) *256) ; and the y dirrection
;-------------------------------------------------------------------------Blending
rgb_1=buffer(x2,y1)
rgb_2=buffer(x1,y1)
alpha_1=(tx2#-x1) *256
alpha_2=256-alpha_1
col1=(((((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00)+(((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00)) Or ((((rgb_1 And $0000FF00) * alpha_1) And $00FF0000)+(((rgb_2 And $0000FF00) * alpha_2) And $00FF0000))) Sar 8
rgb_1=buffer(x2,y2)
rgb_2=buffer(x1,y2)
rgb_1=(((((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00)+(((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00)) Or ((((rgb_1 And $0000FF00) * alpha_1) And $00FF0000)+(((rgb_2 And $0000FF00) * alpha_2) And $00FF0000))) Sar 8
rgb_2=col1
alpha_1=(ty2#-y1) *256
alpha_2=256-alpha_1
col1=(((((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00)+(((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00)) Or ((((rgb_1 And $0000FF00) * alpha_1) And $00FF0000)+(((rgb_2 And $0000FF00) * alpha_2) And $00FF0000))) Sar 8
;-------------------------------------------------------------------------
WritePixelFast(tx,ty,col1) ; then draw it all to the screen
Else
WritePixelFast(tx,ty,0) ;if we try to draw to the screen but try to read from outside the screen then draw a black pixel
EndIf
EndIf
Next
Next
End Function
Function magnify(radius,cx,cy)
Local x,y,half_row_width,tx,ty,ang#,dist#
Local tx2#,ty2#
For y=-radius To radius
half_row_width=Sqr(radius^2-y^2)
For x=-half_row_width To half_row_width
tx=(cx+x) ;Get the current x drawing position
ty=(cy+y) ;Get the current y drawing position
i=i+1
ang#=ATan2(x,y) ;get the angle betwen the centre and the current pixel being drawn
;dist#=Sin(Sqr(x*x+y*y)/0.5)*(100)
;dist#=(x*x+y*y)/500+Sqr(x*x+y*y)*r#/100 ;Get the distance ----------------------!!-------------------------
dist#=Float(x*x+y*y)/500+Sqr(x*x+y*y)*r#/100
If tx>0 And ty>0 And tx<gx And ty<gy ;make sure we arent drawing outside the screen
tx2#=cx+Sin(ang)*dist ;precalcute the x
ty2#=cy+Cos(ang)*dist ; and y position
If tx2#>0 And tx2#<gx And ty2#>0 And ty2#<gy ; make sure we arent readin from outside the screen
x1=Floor(tx2#) ;Get the low x cordinate
x2=Ceil (tx2#) ;Get the high x cordinate
y1=Floor(ty2#) ;Get the low y cordinate
y2=Ceil (ty2#) ;Get the high y cordinate
col1=ColourBlend(buffer(x2,y1),buffer(x1,y1),(tx2#-x1)*256) ; blend the two colors with the difference betwen their two positions
col2=ColourBlend(buffer(x2,y2),buffer(x1,y2),(tx2#-x1)*256) ; in the x direction
col1=ColourBlend(col2,col1,(ty2#-y1)*256) ; and the y dirrection
WritePixelFast(tx,ty,col1) ; then draw it all to the screen
Else
WritePixelFast(tx,ty,0) ;if we try to draw to the screen but try to read from outside the screen then draw a black pixel
EndIf
EndIf
Next
Next
End Function
Function ColourBlend( rgb_1, rgb_2, alpha_1 )
alpha_2 = 256 - alpha_1
;rb_1 = ((((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00)+(((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00))
;g_1 = ((((rgb_1 And $0000FF00) * alpha_1) And $00FF0000)+(((rgb_2 And $0000FF00) * alpha_2) And $00FF0000))
;rb_2 = (((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00)
;g_2 = (((rgb_2 And $0000FF00) * alpha_2) And $00FF0000)
;rb_1 = rb_1 + rb_2
;g_1 = g_1 + g_2
Return (((((rgb_1 And $00FF00FF) * alpha_1) And $FF00FF00)+(((rgb_2 And $00FF00FF) * alpha_2) And $FF00FF00)) Or ((((rgb_1 And $0000FF00) * alpha_1) And $00FF0000)+(((rgb_2 And $0000FF00) * alpha_2) And $00FF0000))) Sar 8
;Return (rb_1 Or g_1) Sar 8
End Function
-
Nice one Paul :)
-
Good karma for Paul and P01! :)
-
Lol I'd hardly call it 'My' colour blending function. After all stonemonkey told me how to do it all :P
Its a nice effect :) Dident notice too much of a difference with the look up tables tho, like +2 fps. But lookup tables are good no doubt.
Cheers.
-
whats your fps from the beggining mike_g?
Mine, in the version without tables if 24 and the one withjout 125, and thats a pretty big difference.
-
Nice work paul. For the 2 ways, i get around 10fps and 42 fps.
I've been doing it something like this although it probably won't make much difference:
;everything is (unsigned) integer except x_fraction and y_fraction
x_blend=(255.0*x_fraction)+1
y_blend=(255.0*y_fraction)+1
top_l_blend=(x_blend*(257-y_blend))shr 8
top_r_blend=((257-x_blend)*(257-y_blend))shr 8
bot_l_blend=(x_blend*y_blend)shr 8
bot_r_blend=((257-x_blend)*y_blend)shr 8
r_b=(((argb0 and $ff00ff)*top_l_blend)+((argb1 and $ff00ff)*top_r_blend)+((argb2 and $ff00ff)*bot_l_blend)+((argb3 and $ff00ff)*bot_r_blend))and $ff00ff00
g__=(((argb0 and $ff00)*top_l_blend)+((argb1 and $ff00)*top_r_blend)+((argb2 and $ff00)*bot_l_blend)+((argb3 and $ff00)*bot_r_blend))and $ff0000
argb_out=(r_b or g__)shr 8
It calculates the weights for each of the 4 pixels first.