Page 1 of 2
Reflection Effect
Posted: Mon Jan 30, 2017 3:59 am
by coder14
Is it possible to draw the faded reflection of an image below it to get a reflection effect? I'm looking to do something like this but not pre-drawn - I have the top image but need to flip and fade it and then drawn it below the actual image.
Example:
Can PB do this through code?
Re: Reflection Effect
Posted: Mon Jan 30, 2017 7:01 am
by Shield
coder14 wrote:Can PB do this through code?
Absolutely.
Roughly speaking, all you need to do is draw the original image, make a copy of it, flip it on the horizontal axis
and then draw it below the original image where each line has an increasing alpha value to make it fade out.
The drawing commands allow you to do all this quite easily.

Re: Reflection Effect
Posted: Mon Jan 30, 2017 9:18 am
by netmaestro
Code: Select all
; Fading reflection effect
; Authors: Lloyd Gallant (netmaestro), Wilbert, #NULL
; January 30, 2017
file$ = GetTemporaryDirectory()+"test_camera.png"
InitNetwork()
If FileSize(file$) = -1
If Not ReceiveHTTPFile("http://www.lloydsplace.com/camera.png", file$)
MessageRequester("oops!","Problem getting image... quitting")
EndIf
EndIf
UsePNGImageDecoder()
LoadImage(0, file$)
Global w=ImageWidth(0)
Global h=ImageHeight(0)
; Create image with reflection
CreateImage(1, w, h << 1, 32, #PB_Image_Transparent)
StartDrawing(ImageOutput(1))
DrawAlphaImage(ImageID(0),0,0)
For y = 0 To h - 1
ClipOutput(0, h + y, w, 1)
ease.d = y / h
ease = 1 - Pow( (1-ease), 5) ; change exponent for fadeout pace
alpha.d = 255 - ease * 255
DrawAlphaImage(ImageID(0), 0, y * 2, Int(alpha))
Next
StopDrawing()
OpenWindow(0,0,0,w,h << 1,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(0,0,0,0,0,ImageID(1))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
Re: Reflection Effect
Posted: Mon Jan 30, 2017 9:42 am
by Keya
here's my version of flip rows
Code: Select all
Procedure FlipBufferRows(hImg)
Protected *pbuf, *psrc, *ptmp, *pdst, width, height, i
If StartDrawing(ImageOutput(hImg))
*pbuf = DrawingBuffer()
width = DrawingBufferPitch() ;check padding
height = ImageHeight(hImg)
*psrc = *pbuf
*ptmp = AllocateMemory(width*height) ;Temp buffer to write rows in reverse order
If *ptmp
*pdst = *ptmp + (width*height)-width
For i = 0 To height-1
CopyMemory(*psrc, *pdst, width)
*pdst-width
*psrc+width
Next i
CopyMemory(*ptmp, *pbuf, width*height) ;Overwrite existing buffer with flipped buffer
FreeMemory(*ptmp) ;Free temp buffer
EndIf
StopDrawing()
EndIf
EndProcedure
Re: Reflection Effect
Posted: Mon Jan 30, 2017 9:50 am
by netmaestro
@keya, got any ideas for how to better accelerate the reduction of alpha than what I've got? My formula alpha.d = 255-(y/h)*255 works for a linear reduction from 254 to 0 over the whole height of the image, but I'd like to do something more rapid, that disappears totally by the time the image is 75 percent drawn. I tried a hamfisted select block to speed it up but there must be some math that will work. If only I'd spent less time dipping pigtails in the inkwell and paid more attention in school I might know some of this stuff.
Re: Reflection Effect
Posted: Mon Jan 30, 2017 10:24 am
by Keya
Re: Reflection Effect
Posted: Mon Jan 30, 2017 10:50 am
by #NULL
cool effect
since the (y/h) is already normalized to 0..1 you can apply any interpolation/easing function or formula. i made up this one for exponential fadeout:
Code: Select all
ease.d = y / h
ease = 1 - Pow( (1-ease), 4) ; change exponent for fadeout pace
alpha.d = 255 - ease * 255
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:00 am
by wilbert
Example using GrabDrawingImage
Code: Select all
file$ = GetTemporaryDirectory()+"test_camera.png"
InitNetwork()
If FileSize(file$) = -1
If Not ReceiveHTTPFile("http://www.lloydsplace.com/camera.png", file$)
MessageRequester("oops!","Problem getting image... quitting")
EndIf
EndIf
UsePNGImageDecoder()
LoadImage(0, file$)
Global w=ImageWidth(0)
Global h=ImageHeight(0)
; Create image with reflection
CreateImage(1, w, h << 1, 32, #PB_Image_Transparent)
StartDrawing(ImageOutput(1))
DrawingMode(#PB_2DDrawing_AllChannels)
DrawAlphaImage(ImageID(0),0,0)
For y = 1 To h
GrabDrawingImage(2, 0, h - y, w, 1)
DrawAlphaImage(ImageID(2), 0, h + y - 1, 255 - 255 * y / h)
Next
FreeImage(2)
StopDrawing()
OpenWindow(0,0,0,w,h << 1,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(0,0,0,0,0,ImageID(1))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
Using ClipOutput
Code: Select all
file$ = GetTemporaryDirectory()+"test_camera.png"
InitNetwork()
If FileSize(file$) = -1
If Not ReceiveHTTPFile("http://www.lloydsplace.com/camera.png", file$)
MessageRequester("oops!","Problem getting image... quitting")
EndIf
EndIf
UsePNGImageDecoder()
LoadImage(0, file$)
Global w=ImageWidth(0)
Global h=ImageHeight(0)
; Create image with reflection
CreateImage(1, w, h << 1, 32, #PB_Image_Transparent)
StartDrawing(ImageOutput(1))
DrawAlphaImage(ImageID(0),0,0)
For y = 0 To h - 1
ClipOutput(0, h + y, w, 1)
DrawAlphaImage(ImageID(0), 0, y * 2, 255 - 255 * y / h)
Next
StopDrawing()
OpenWindow(0,0,0,w,h << 1,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(0,0,0,0,0,ImageID(1))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
Another possibility would be using the VectorDrawing library to draw a flipped image.
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:16 am
by netmaestro
Thanks #NULL, that's exactly what I was looking for.
Thanks Wilbert, very nice optimization!
Code in first post is modified to implement Wilbert and #NULL's improvements. Anyone looking to do this should follow this prescription imho, it's done right (now).
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:19 am
by wilbert
@Netmaestro,
I don't know if you also noticed my updated post with the additional ClipOutput example.
I don't know how it behaves on Windows but on OSX using ClipOutput seems to be faster compared to using GrabDrawingImage.
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:27 am
by netmaestro
I don't have time to test it but I'll take your word - if it's faster on OSX it'll probably be faster on Windows. Posted code now uses your ClipOutput example. Thanks again!
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:40 am
by netmaestro
One more avenue to explore, which I'll probably tackle tomorrow: DrawAlphaImage is notoriously slow, it would be worthwhile to speedtest it against a version written with DrawImage using the callback - the callback might just be faster since the 2DDrawing library overhaul. It seems unlikely, but since the overhaul drawing an image with DrawImage isn't as much faster as one might expect than doing it with nested loops and Plot(). Point and Plot now access the direct colorbits memory, which is why we can no longer get away with coloring outside the lines - it generates an error with the debugger and a crash without. It used to be safe though as it went to an intermediate location first. If it was out of bounds it just wasn't written the second time. "Safe" but "Shitty". (kind of like .net more or less)
Re: Reflection Effect
Posted: Mon Jan 30, 2017 11:47 am
by netmaestro
wilbert wrote:using ClipOutput seems to be faster compared to using DrabDrawingImage.
DrabDrawingImage is a little-known and undocumented PureBasic command for rendering boring and uninspiring images. I'm surprised you knew about it. It's faster but it just doesn't care if it works or not. It's profoundly depressed and keeps trying to deprecate itself. Maybe one day it'll succeed.
Re: Reflection Effect
Posted: Mon Jan 30, 2017 12:01 pm
by wilbert
netmaestro wrote:DrabDrawingImage
Should have been Grab of course
Using DrawingBuffer with SSE2 to process four pixels at once is probably quite a bit faster but I haven't tried that.
Re: Reflection Effect
Posted: Mon Jan 30, 2017 12:51 pm
by RASHAD
Nice work NM
Thanks
Here is my 2c
#1 : Windows
Code: Select all
; Fading reflection effect
; Authors: Lloyd Gallant (netmaestro), Wilbert, #NULL
; January 30, 2017
file$ = GetTemporaryDirectory()+"test_camera.png"
InitNetwork()
If FileSize(file$) = -1
If Not ReceiveHTTPFile("http://www.lloydsplace.com/camera.png", file$)
MessageRequester("oops!","Problem getting image... quitting")
EndIf
EndIf
UsePNGImageDecoder()
LoadImage(0, file$)
Global w=ImageWidth(0)
Global h=ImageHeight(0)
Procedure Image_Rotate(Image,Angle)
nimgw = h*Sin(Angle*#PI/180)+w*Cos(Angle*#PI/180)
nimgh = w*Sin(Angle*#PI/180) + h*Cos(Angle*#PI/180)
temp=CreateImage(#PB_Any,nimgw,nimgh)
Dim p.Point(2)
p(0)\x=0
p(0)\y=nimgh
p(1)\x=nimgw
p(1)\y=nimgh
p(2)\x=0
p(2)\y=0
ImageDc = CreateCompatibleDC_(0)
SelectObject_(ImageDc,ImageID(Image))
dc=StartDrawing(ImageOutput(temp))
PlgBlt_(dc,@p(),ImageDc,0,0,w,h,0,0,0)
StopDrawing()
CopyImage(temp,image)
FreeImage(temp)
EndProcedure
CopyImage(0,10)
Image_Rotate(10,0)
op = 130 ;Change to increease or decrease the reflection size
; Create image with reflection
CreateImage(1, w, h, 32, #PB_Image_Transparent)
StartDrawing(ImageOutput(1))
For y = 0 To h - 1
GrabImage(10,2,0,y,w,1)
DrawAlphaImage(ImageID(2),0,y,op)
op - 1
If op < 0
op = 0
EndIf
Next
StopDrawing()
FreeImage(2)
FreeImage(10)
OpenWindow(0,0,0,w,h << 1,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(0,0,0,w,h,ImageID(0))
ImageGadget(1,0,h,w,h,ImageID(1))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
#2 : Cross platform
Code: Select all
; Fading reflection effect
; Authors: Lloyd Gallant (netmaestro), Wilbert, #NULL
; January 30, 2017
file$ = GetTemporaryDirectory()+"test_camera.png"
InitNetwork()
If FileSize(file$) = -1
If Not ReceiveHTTPFile("http://www.lloydsplace.com/camera.png", file$)
MessageRequester("oops!","Problem getting image... quitting")
EndIf
EndIf
UsePNGImageDecoder()
LoadImage(0, file$)
Global w=ImageWidth(0)
Global h=ImageHeight(0)
Global trcolor = $FFFFFF
Procedure TransPNG(img,trcolor)
CopyImage(0,1)
StartDrawing(ImageOutput(1))
For x = 0 To w - 1
For y = 0 To h - 1
DrawingMode(#PB_2DDrawing_Default )
If Point(x,y) = trcolor
DrawingMode(#PB_2DDrawing_AllChannels )
Plot(x,y,RGBA(255, 255, 255,0))
EndIf
Next
Next
StopDrawing()
ProcedureReturn 1
EndProcedure
Procedure flipVal(img)
fimg = CreateImage(#PB_Any,w,h,32,trcolor)
StartVectorDrawing(ImageVectorOutput(fimg))
ResetCoordinates()
MovePathCursor(0,h)
FlipCoordinatesY(180)
DrawVectorImage(ImageID(img), 255)
StopVectorDrawing()
ProcedureReturn fimg
EndProcedure
TransPNG(0,#White)
fimg = flipVal(1)
op = 130 ;Change to increease or decrease the reflection size
; Create image with reflection
CreateImage(2, w, h, 32, #PB_Image_Transparent)
StartDrawing(ImageOutput(2))
For y = 0 To h - 1
GrabImage(fimg,3,0,y,w,1)
DrawAlphaImage(ImageID(3),0,y,op)
op - 1
If op < 0
op = 0
EndIf
Next
StopDrawing()
FreeImage(1)
FreeImage(3)
FreeImage(fimg)
OpenWindow(0,0,0,w,h << 1,"",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ImageGadget(0,0,0,w,h,ImageID(0))
ImageGadget(1,0,h,w,h,ImageID(2))
Repeat:Until WaitWindowEvent()=#PB_Event_CloseWindow
Edit : Modified # 2 for transparent color