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

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
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

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 :wink:

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