Reflection Effect

Just starting out? Need help? Post your questions and find answers here.
coder14
Enthusiast
Enthusiast
Posts: 327
Joined: Tue Jun 21, 2011 10:39 am

Reflection Effect

Post 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:
Image

Can PB do this through code?
User avatar
Shield
Addict
Addict
Posts: 1021
Joined: Fri Jan 21, 2011 8:25 am
Location: 'stralia!
Contact:

Re: Reflection Effect

Post 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. :)
Image
Blog: Why Does It Suck? (http://whydoesitsuck.com/)
"You can disagree with me as much as you want, but during this talk, by definition, anybody who disagrees is stupid and ugly."
- Linus Torvalds
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post by netmaestro »

Image

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
Last edited by netmaestro on Mon Jan 30, 2017 11:25 am, edited 3 times in total.
BERESHEIT
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Reflection Effect

Post 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
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post 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.
Last edited by netmaestro on Mon Jan 30, 2017 1:33 pm, edited 1 time in total.
BERESHEIT
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Reflection Effect

Post by Keya »

#NULL
Addict
Addict
Posts: 1499
Joined: Thu Aug 30, 2007 11:54 pm
Location: right here

Re: Reflection Effect

Post 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
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Reflection Effect

Post 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.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post 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).
BERESHEIT
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Reflection Effect

Post 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.
Last edited by wilbert on Mon Jan 30, 2017 11:53 am, edited 1 time in total.
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post 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!
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post 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)
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: Reflection Effect

Post 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.
BERESHEIT
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3943
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Reflection Effect

Post by wilbert »

netmaestro wrote:DrabDrawingImage
Should have been Grab of course :wink:

Using DrawingBuffer with SSE2 to process four pixels at once is probably quite a bit faster but I haven't tried that.
Windows (x64)
Raspberry Pi OS (Arm64)
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4955
Joined: Sun Apr 12, 2009 6:27 am

Re: Reflection Effect

Post 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
Last edited by RASHAD on Mon Jan 30, 2017 1:58 pm, edited 3 times in total.
Egypt my love
Post Reply