News:

Building a 3D Ray Tracer  By stevmjon

Main Menu

Kaleidoscope (optimized)

Started by kevin, December 01, 2013, 09:01:36 AM

Previous topic - Next topic

kevin

   Kaleidoscope (optimized)

      This example was originally written by Scott Brosious, while it worked  the method it used would compute each pixel multiple times. Making the effect  much slower than need be.

     This example includes three revisions of the original demo  there's a tweaked version of the original code, plus an inverted version of the that.  The inverted version is about twice as fast, but still uses the same brute force method.

     The last version flips the problem upside down so it computes the  distance and angle from the center for each unique pixel, then pulls the rotated   angle from a displacement table and gets the colour.  The result is around  9->10 times faster than the original on my system.  

  Related Articles:

       * A Crash Course In BASIC program Optimization
        * Drawing A Pie Chart


monkeybot

i don't get anything with mode 3

kevin


    Kaleidoscope (optimized #2)

         This version has one extra mode which pre-computes most of the heavy lifting as well as tweaks to the other methods.   


          Note: requires the media from the first post.

PlayBASIC Code: [Select]
;   -----------------------------------------------------------------------------
; --[ABOUT]--------------------------------------------------------------------
; -----------------------------------------------------------------------------
; This example was originally written by Scott Brosious, while it worked
; the method it used would compute each pixel multiple times. Making the effect
; much slower than need be. This version includes three revisions of the demo
; there's a tweaked version of the original, plus an inverted version of the that.
; The inverted version is about twice as fast, but still uses the same brute force
; method. The last version flips the problem upside down so it computes the
; distance and angle from the center for each unique pixel, then pulls the rotated
; angle from a displacement table and gets the colour. The result is around
; 9->10 times faster than the original on my system.
;
; Have fun,

; Kevin Picone
; UnderwareDesign.com PlayBASIC.com
; -----------------------------------------------------------------------------






Loadfont "verdana",1,14


LoadFxImage "test01.png",1


XSize = 512
YSize = 512

global MaxRadius = XSize / 2

Dim Colours(3600,MaxRadius)

; Note to self: You can read the image before you clear the screen.

Print "loading "
sync
rendertoimage 1
CenterX=Xsize/2
CenterY=YSise/2
For AngleLP = 0 To 3600
ca#= Cos(Angle#)
ca#= Sin(Angle#)
Angle#=Anglelp/10.0

lockbuffer
For Radius = 0 To MaxRadius - 1
XScreen# = Radius * ca#
YScreen# = Radius * sa#
Colours(Angle#,Radius) = Point(CenterX + XScreen#,CenterY + YScreen#)
Next
unlockbuffer
Next

rendertoscreen
; Here is where you can come back to after an update.


// This table is used to compute the angles of two of the quadrants
Dim DirectionTable(90)

rendermode =2


; --------------------------------------------------------------------------
Do ; ------ [Main Loop ]
; --------------------------------------------------------------------------

Cls Rgb(0,0,0)


if SpaceKey()
RenderMode++
if RenderMode>3 then RenderMode=0
frames=0
tt#=0
flushkeys
endif



StartTime=Timer()
Select RenderMode
; -------------------------------------------
case 0
; -------------------------------------------
MEthodname$=Kaleidoscope_ORIGINAL(Twist#)

; -------------------------------------------
case 1
; -------------------------------------------
MEthodname$=Kaleidoscope_Inverted_Loops(Twist#)


; -------------------------------------------
case 2
; -------------------------------------------
MEthodname$=Kaleidoscope_Single_Pass_Version(Twist#)


; -------------------------------------------
case 3
; -------------------------------------------
MEthodname$=Kaleidoscope_Single_Pass_Cache_Scanline_Version(Twist#)

EndSelect
tt#+=Timer()-StartTime



; --------------------------------------------------------
; Display render time info
; --------------------------------------------------------
Frames++

print " Render Method #"+str$(RenderMode+1)+" of 4 [ "+MethodName$+" ]"
print " Twist Angle:"+str$(Twist#)
print " Render Time In Ticks:"+str$(tt#/frames)
print " Space to swap methods"


Sync

Twist# = WrapAngle(Twist#,10)

Loop esckey()


end




; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
; >> Render Kaleidoscope
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;
; This is the original routine with a few tweaks, it's main problem is it's
; it's potentially rendering each pixel more than once.
Login required to view complete source code



monkeybot


kevin

#4
  Kaleidoscope (optimized #3)

  And here's one last tiny change (mode #5) to show the thought progression.     The 5th version just changes the table data so that the range of the data is from 1 to MaxRadius.  This means we can remove a compare operation  from the inner loop.  Might not seem like much, but since the inner loop is running 1000's of times, this  wins us back another few milliseconds across the effect.    You could remove it entirely by computing the span width for each scan line just like you would when drawing a filled circle.   Could probably pack the table data differently to push further also.. 

PlayBASIC Code: [Select]
;   -----------------------------------------------------------------------------
; --[ABOUT]--------------------------------------------------------------------
; -----------------------------------------------------------------------------
; This example was originally written by Scott Brosious, while it worked
; the method it used would compute each pixel multiple times. Making the effect
; much slower than need be. This version includes three revisions of the demo
; there's a tweaked version of the original, plus an inverted version of the that.
; The inverted version is about twice as fast, but still uses the same brute force
; method. The last version flips the problem upside down so it computes the
; distance and angle from the center for each unique pixel, then pulls the rotated
; angle from a displacement table and gets the colour. The result is around
; 9->10 times faster than the original on my system.
;
; Have fun,

; Kevin Picone
; UnderwareDesign.com PlayBASIC.com
; -----------------------------------------------------------------------------






Loadfont "verdana",1,14


LoadFxImage "test01.png",1


XSize = 512
YSize = 512

global MaxRadius = XSize / 2

Dim Colours(3600,MaxRadius)
Dim Colours2(3600,MaxRadius+1) ; Only but by the 5th version of the routine

; Note to self: You can read the image before you clear the screen.

Print "loading "
sync
rendertoimage 1
CenterX=Xsize/2
CenterY=YSise/2
For AngleLP = 0 To 3600

Angle#=Anglelp/10.0
ca#= Cos(Angle#)
ca#= Sin(Angle#)

lockbuffer
For Radius = 0 To MaxRadius - 1
XScreen# = Radius * ca#
YScreen# = Radius * sa#
ThisRGB=Point(CenterX + XScreen#,CenterY + YScreen#)
Colours(Angle#,Radius) = ThisRGB
Colours2(Angle#,Radius+1)=ThisRGB ; Colour table offset from 1 to maxradius
Next
unlockbuffer
Next

rendertoscreen
; Here is where you can come back to after an update.


// This table is used to compute the angles of two of the quadrants
Dim DirectionTable(90)

rendermode =2


; --------------------------------------------------------------------------
Do ; ------ [Main Loop ]
; --------------------------------------------------------------------------

Cls Rgb(0,0,0)


if SpaceKey()
RenderMode++
if RenderMode>4 then RenderMode=0
frames=0
tt#=0
flushkeys
endif



StartTime=Timer()
Select RenderMode
; --------------------------------------------------------------
case 0
; --------------------------------------------------------------
MEthodname$=Kaleidoscope_ORIGINAL(Twist#)

; --------------------------------------------------------------
case 1
; --------------------------------------------------------------
MEthodname$=Kaleidoscope_Inverted_Loops(Twist#)


; --------------------------------------------------------------
case 2
; --------------------------------------------------------------
MEthodname$=Kaleidoscope_Single_Pass_Version(Twist#)

; --------------------------------------------------------------
case 3
; --------------------------------------------------------------
MEthodname$=Kaleidoscope_Single_Pass_Cache_Scanline_Version(Twist#)

; --------------------------------------------------------------
case 4
; --------------------------------------------------------------
MEthodname$=Kaleidoscope_Single_Pass_Cache_Scanline_Version2(Twist#)

EndSelect
tt#+=Timer()-StartTime



; --------------------------------------------------------
; Display render time info
; --------------------------------------------------------
Frames++

print " Render Method #"+str$(RenderMode+1)+" of 5 [ "+MethodName$+" ]"
print " Twist Angle:"+str$(Twist#)
print " Render Time In Ticks:"+str$(tt#/frames)
print " Space to swap methods"


Sync

Twist# = WrapAngle(Twist#,10)

Loop esckey()


end




; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
Login required to view complete source code

kevin

#5
   Kaleidoscope (optimized #4)

    This version is only slightly tweaked version of the previous snippets, the main difference is it's targeted at running on Windows 8 / Windows 10 which have trouble with direct draw emulation, namely they can slow execution down a huge amount.   It generally manifests itself when trying to draw lots of small image fragments, which is used within this demo used in the fourth and fifth editions of the routine.  To counter this, we just render everything to and FX screen and then draw that to the screen.  


Video


   


   music by: https://bensound.com



Download


  Attached