UnderwareDESIGN

PlayBASIC => Resources => Source Codes => Topic started by: kevin on December 01, 2013, 09:01:36 AM

Title: Kaleidoscope (optimized)
Post by: kevin on December 01, 2013, 09:01:36 AM
   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 (http://www.underwaredesign.com/forums/index.php?topic=2548.0)
        *  Drawing A Pie Chart (http://www.underwaredesign.com/forums/index.php?topic=4090.0)

Title: Re: Kaleidoscope (optimized)
Post by: monkeybot on December 01, 2013, 10:43:49 AM
i don't get anything with mode 3
Title: Re: Kaleidoscope (optimized)
Post by: kevin on December 01, 2013, 09:22:15 PM

    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.

[pbcode]


;   -----------------------------------------------------------------------------
;   --[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. 

Psub Kaleidoscope_ORIGINAL(Twist#)

   XScreenMiddle = GetScreenWidth() / 2
   YScreenMiddle = GetScreenHeight() / 2

   Twist#=wrapangle(Twist#)

   For Radius = 0 To MaxRadius - 1   

      RotateAngle = 0

      For PieceOfPie = 1 To 4

         AngularIncrement# = Twist#

         lockbuffer
            ThisRGB=point(0,0)
            For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
               XScreen# = Radius * Cos(Angle#)
               YScreen# = Radius * Sin(Angle#)
               DotC XScreenMiddle + XScreen#,YScreenMiddle + YScreen#,Colours(AngularIncrement#,Radius)
               AngularIncrement# = WrapAngle(AngularIncrement#,0.1)
            Next Angle#

            AngularDecrement# = Twist# + 45
            RotateAngle = RotateAngle + 45
      
      
            For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
               XScreen# = Radius * Cos(Angle#)
               YScreen# = Radius * Sin(Angle#)
               DotC XScreenMiddle + XScreen#,YScreenMiddle + YScreen#,Colours(AngularDecrement#,Radius)
               AngularDecrement# = WrapAngle(AngularDecrement#,-0.1)
            Next Angle#
         unLockbuffer

         RotateAngle = RotateAngle + 45

      Next PieceOfPie
   Next Radius


   Method$= "Original Brute Force"

EndPsub Method$




;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;                     
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
Psub Kaleidoscope_Inverted_Loops(Twist#)

   XScreenMiddle = GetScreenWidth() / 2
   YScreenMiddle = GetScreenHeight() / 2

   Twist#=wrapangle(Twist#)

   RotateAngle = 0

   For PieceOfPie = 1 To 4

      AngularIncrement# = Twist#

      lockbuffer
            ThisRGB=point(0,0)
   ;         For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
            For AngleLp = RotateAngle*10 To (RotateAngle + 45)*10
            
               Angle#=Anglelp/10.0
               ca#=Cos(Angle#)
               sa#=sin(Angle#)
               
               AngularIncrementInt=AngularIncrement#
            
               For Radius = 0 To MaxRadius - 1   
                  XScreen = Radius * ca#
                  YScreen = Radius * sa#
                  Dotc XScreenMiddle + XScreen,YScreenMiddle + YScreen,Colours(AngularIncrementInt,Radius)
               Next Radius

               AngularIncrement# = WrapAngle(AngularIncrement#,0.1)

            Next AngleLP

            AngularDecrement# = Twist# + 45
            RotateAngle = RotateAngle + 45
      
         
            For AngleLp = RotateAngle*10 To (RotateAngle + 45)*10
               Angle#=Anglelp/10.0

               ca#=Cos(Angle#)
               sa#=sin(Angle#)
               AngularDecrementInt=AngularDecrement#
            
               For Radius = 0 To MaxRadius - 1   
                  XScreen = Radius * ca#
                  YScreen = Radius * sa#
                  Dotc XScreenMiddle + XScreen,YScreenMiddle + YScreen,Colours(AngularDecrementInt,Radius)
               Next Radius
               AngularDecrement# = WrapAngle(AngularDecrement#,-0.1)
   
            Next AngleLP
         unLockbuffer

         RotateAngle = RotateAngle + 45

      Next PieceOfPie
      
   Method$= "Inverted Brute Force"

EndPsub Method$
   
   

;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;                        >> Kaleidoscope_Single_Pass_Version <<    
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;
; This version of the effect scan the fill region and computes the radius and
; angle to the center of the effect so it only renders each pixel once.
;
;   -----------------------------------------------------------------------------


Psub Kaleidoscope_Single_Pass_Version(Twist#)

      XScreenMiddle = GetScreenWidth() / 2
      YScreenMiddle = GetScreenHeight() / 2

      YScreenMiddle2 =YScreenMiddle+MaxRadius

      Twist#=wrapangle(twist#)

      For Anglelp=0 to 45
         Angle#=Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      For Anglelp=45 to 90
         Angle#=90-Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      MaxRadiusMinusOne=MaxRadius-1

      lockbuffer      
      ThisRGB=Point(0,0)
      For ylp= 0 to MaxRadiusMinusOne
         For xlp= 0 to MaxRadiusMinusOne

               Dist=GetDistance2d(0,0,xlp,ylp)
               if Dist<=MaxRadius   

                     AngleToPixel=GetAngle2d(0,0,xlp,ylp)         
   
                     Angle       =DirectionTable(AngleToPixel)
                     ThisColour=Colours(Angle,Dist)            
                  
                     Ypos=YScreenMiddle + Ylp
                     fastDot XScreenMiddle + xlp,Ypos ,ThisColour
                     fastDot XScreenMiddle - xlp,Ypos ,ThisColour

                     Ypos=YScreenMiddle - Ylp
                     fastDot XScreenMiddle + xlp,Ypos ,ThisColour
                     fastDot XScreenMiddle - xlp,Ypos ,ThisColour
                  
            endif
         next
      next
      unlockbuffer      
      
      Method$ ="Single Pass Version"

EndPsub Method$

   



;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;            >> Kaleidoscope_Single_Pass_With Cached Scanlines Version <<    
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;
;  This version caches each scan line and renders them as image strips, it also
; pre-computes the radius and angle tables.  Making it about 40% faster than the
; previous single pass version.
;
;   -----------------------------------------------------------------------------


Psub Kaleidoscope_Single_Pass_Cache_Scanline_Version(Twist#)

      XScreenMiddle = GetScreenWidth() / 2
      YScreenMiddle = GetScreenHeight() / 2

      YScreenMiddle2 =YScreenMiddle+MaxRadius

      Twist#=wrapangle(twist#)

      For Anglelp=0 to 45
         Angle#=Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      For Anglelp=45 to 90
         Angle#=90-Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      MaxRadiusMinusOne=MaxRadius-1


      // create scan line cache and pre-compute the distance and angle tables
      if ScanlineBuffer=0
         ScanLineBuffer=NewFXImage((maxradius*2),1)

         Dim DistanceTable(MaxRadius*MaxRadius)
         Dim AngleTable(MaxRadius*MaxRadius)

         For ylp= 0 to MaxRadiusMinusOne
               For xlp= 0 to MaxRadiusMinusOne
                     pos=ylp*MaxRadius+xlp
                     DistanceTable(pos)   =GetDistance2d(0,0,xlp,ylp) 
                     AngleTable(pos)      =GetAngle2d(0,0,xlp,ylp)         
               next
         next

      endif


      Xpos=XscreenMiddle-MaxRadius

      For ylp= 0 to MaxRadiusMinusOne

               rendertoimage  ScanLineBuffer
            
               cls 0
               
               lockbuffer      
                  ThisRGB=Point(0,0)

                  RowYPos=Ylp*MaxRAdius
   
                  For xlp= RowYpos to RowYpos+MaxRadiusMinusOne
                     Dist=DistanceTable(xlp)
                     if Dist<=MaxRadius   

                        AngleToPixel=AngleTable(xlp)
                        Angle       =DirectionTable(AngleToPixel)
                        ThisColour=Colours(Angle,Dist)            
                  
                        Xlp2=Xlp-RowYpos
                        fastDot maxradius + xlp2,0 ,ThisColour
                        fastDot maxradius - xlp2,0 ,ThisColour
                  
                     endif
                  next

               unlockbuffer      
               rendertoscreen

               lockbuffer      
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle + Ylp,false
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle - Ylp,false
               unlockbuffer      

      next
            
Done:            
      Method$ ="Single Pass Version with cached strips"

EndPsub Method$


[/pbcode]

Title: Re: Kaleidoscope (optimized)
Post by: monkeybot on December 02, 2013, 11:30:57 AM
woo number 4 is speeedy!
Title: Re: Kaleidoscope (optimized)
Post by: kevin on December 02, 2013, 11:04:25 PM
  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.. 

[pbcode]


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



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

Psub Kaleidoscope_ORIGINAL(Twist#)

   XScreenMiddle = GetScreenWidth() / 2
   YScreenMiddle = GetScreenHeight() / 2

   Twist#=wrapangle(Twist#)

   For Radius = 0 To MaxRadius - 1   

      RotateAngle = 0

      For PieceOfPie = 1 To 4

         AngularIncrement# = Twist#

         lockbuffer
            ThisRGB=point(0,0)
            For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
               XScreen# = Radius * Cos(Angle#)
               YScreen# = Radius * Sin(Angle#)
               DotC XScreenMiddle + XScreen#,YScreenMiddle + YScreen#,Colours(AngularIncrement#,Radius)
               AngularIncrement# = WrapAngle(AngularIncrement#,0.1)
            Next Angle#

            AngularDecrement# = Twist# + 45
            RotateAngle = RotateAngle + 45
      
      
            For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
               XScreen# = Radius * Cos(Angle#)
               YScreen# = Radius * Sin(Angle#)
               DotC XScreenMiddle + XScreen#,YScreenMiddle + YScreen#,Colours(AngularDecrement#,Radius)
               AngularDecrement# = WrapAngle(AngularDecrement#,-0.1)
            Next Angle#
         unLockbuffer

         RotateAngle = RotateAngle + 45

      Next PieceOfPie
   Next Radius


   Method$= "Original Brute Force"

EndPsub Method$




;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;                     
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
Psub Kaleidoscope_Inverted_Loops(Twist#)

   XScreenMiddle = GetScreenWidth() / 2
   YScreenMiddle = GetScreenHeight() / 2

   Twist#=wrapangle(Twist#)

   RotateAngle = 0

   For PieceOfPie = 1 To 4

      AngularIncrement# = Twist#

      lockbuffer
            ThisRGB=point(0,0)
   ;         For Angle# = RotateAngle To RotateAngle + 45 Step 0.1   
            For AngleLp = RotateAngle*10 To (RotateAngle + 45)*10
            
               Angle#=Anglelp/10.0
               ca#=Cos(Angle#)
               sa#=sin(Angle#)
               
               AngularIncrementInt=AngularIncrement#
            
               For Radius = 0 To MaxRadius - 1   
                  XScreen = Radius * ca#
                  YScreen = Radius * sa#
                  Dotc XScreenMiddle + XScreen,YScreenMiddle + YScreen,Colours(AngularIncrementInt,Radius)
               Next Radius

               AngularIncrement# = WrapAngle(AngularIncrement#,0.1)

            Next AngleLP

            AngularDecrement# = Twist# + 45
            RotateAngle = RotateAngle + 45
      
         
            For AngleLp = RotateAngle*10 To (RotateAngle + 45)*10
               Angle#=Anglelp/10.0

               ca#=Cos(Angle#)
               sa#=sin(Angle#)
               AngularDecrementInt=AngularDecrement#
            
               For Radius = 0 To MaxRadius - 1   
                  XScreen = Radius * ca#
                  YScreen = Radius * sa#
                  Dotc XScreenMiddle + XScreen,YScreenMiddle + YScreen,Colours(AngularDecrementInt,Radius)
               Next Radius
               AngularDecrement# = WrapAngle(AngularDecrement#,-0.1)
   
            Next AngleLP
         unLockbuffer

         RotateAngle = RotateAngle + 45

      Next PieceOfPie
      
   Method$= "Inverted Brute Force"

EndPsub Method$
   
   

;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;                        >> Kaleidoscope_Single_Pass_Version <<    
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;
; This version of the effect scan the fill region and computes the radius and
; angle to the center of the effect so it only renders each pixel once.
;
;   -----------------------------------------------------------------------------


Psub Kaleidoscope_Single_Pass_Version(Twist#)

      XScreenMiddle = GetScreenWidth() / 2
      YScreenMiddle = GetScreenHeight() / 2

      YScreenMiddle2 =YScreenMiddle+MaxRadius

      Twist#=wrapangle(twist#)

      For Anglelp=0 to 45
         Angle#=Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      For Anglelp=45 to 90
         Angle#=90-Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      MaxRadiusMinusOne=MaxRadius-1

      lockbuffer      
      ThisRGB=Point(0,0)
      For ylp= 0 to MaxRadiusMinusOne
         For xlp= 0 to MaxRadiusMinusOne

               Dist=GetDistance2d(0,0,xlp,ylp)
               if Dist<=MaxRadius   

                     AngleToPixel=GetAngle2d(0,0,xlp,ylp)         
   
                     Angle       =DirectionTable(AngleToPixel)
                     ThisColour=Colours(Angle,Dist)            
                  
                     Ypos=YScreenMiddle + Ylp
                     fastDot XScreenMiddle + xlp,Ypos ,ThisColour
                     fastDot XScreenMiddle - xlp,Ypos ,ThisColour

                     Ypos=YScreenMiddle - Ylp
                     fastDot XScreenMiddle + xlp,Ypos ,ThisColour
                     fastDot XScreenMiddle - xlp,Ypos ,ThisColour
                  
            endif
         next
      next
      unlockbuffer      
      
      Method$ ="Single Pass Version"

EndPsub Method$

   



;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;            >> Kaleidoscope_Single_Pass_With Cached Scanlines Version <<    
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;
;  This version caches each scan line and renders them as image strips, it also
; pre-computes the radius and angle tables.  Making it about 40% faster than the
; previous single pass version.
;
;   -----------------------------------------------------------------------------


Psub Kaleidoscope_Single_Pass_Cache_Scanline_Version(Twist#)

      XScreenMiddle = GetScreenWidth() / 2
      YScreenMiddle = GetScreenHeight() / 2

      YScreenMiddle2 =YScreenMiddle+MaxRadius

      Twist#=wrapangle(twist#)

      For Anglelp=0 to 45
         Angle#=Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      For Anglelp=45 to 90
         Angle#=90-Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      MaxRadiusMinusOne=MaxRadius-1


      // create scan line cache and pre-compute the distance and angle tables
      if ScanlineBuffer=0
         ScanLineBuffer=NewFXImage((maxradius*2),1)

         Dim DistanceTable(MaxRadius*MaxRadius)
         Dim AngleTable(MaxRadius*MaxRadius)

         For ylp= 0 to MaxRadiusMinusOne
               For xlp= 0 to MaxRadiusMinusOne
                        pos=ylp*MaxRadius+xlp
                        DistanceTable(pos)   =GetDistance2d(0,0,xlp,ylp)
                        AngleTable(pos)      =GetAngle2d(0,0,xlp,ylp)         
               next
         next

      endif


      Xpos=XscreenMiddle-MaxRadius

      For ylp= 0 to MaxRadiusMinusOne

               rendertoimage  ScanLineBuffer
            
               cls 0
               
               lockbuffer      
                  ThisRGB=Point(0,0)

                  RowYPos=Ylp*MaxRAdius
   
                  For xlp= RowYpos to RowYpos+MaxRadiusMinusOne
                     Dist=DistanceTable(xlp)
                     if Dist<=MaxRadius   

                        AngleToPixel=AngleTable(xlp)
                        Angle       =DirectionTable(AngleToPixel)
                        ThisColour=Colours(Angle,Dist)            
                  
                        Xlp2=Xlp-RowYpos
                        fastDot maxradius + xlp2,0 ,ThisColour
                        fastDot maxradius - xlp2,0 ,ThisColour
                  
                     endif
                  next

               unlockbuffer      
               rendertoscreen

               lockbuffer      
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle + Ylp,false
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle - Ylp,false
               unlockbuffer      

      next
            
Done:            
      Method$ ="Single Pass Version with cached strips"

EndPsub Method$






;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;            >> Kaleidoscope_Single_Pass_With Cached Scanlines Version <<    
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;   -----------------------------------------------------------------------------
;
;  This removes the compare from the version caches each scan line and renders them as image strips, it also
; pre-computes the radius and angle tables.  Making it about 40% faster than the
; previous single pass version.
;
;   -----------------------------------------------------------------------------


Psub Kaleidoscope_Single_Pass_Cache_Scanline_Version2(Twist#)

      XScreenMiddle = GetScreenWidth() / 2
      YScreenMiddle = GetScreenHeight() / 2

      YScreenMiddle2 =YScreenMiddle+MaxRadius

      Twist#=wrapangle(twist#)

      For Anglelp=0 to 45
         Angle#=Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      For Anglelp=45 to 90
         Angle#=90-Anglelp
         DirectionTable(Anglelp)=wrapangle(angle#+twist#)
      next   

      MaxRadiusMinusOne=MaxRadius-1


      // create scan line cache and pre-compute the distance and angle tables
      if ScanlineBuffer=0
         ScanLineBuffer=NewFXImage((maxradius*2),1)

         Dim DistanceTable(MaxRadius*MaxRadius)
         Dim AngleTable(MaxRadius*MaxRadius)

         For ylp= 0 to MaxRadiusMinusOne
               For xlp= 0 to MaxRadiusMinusOne
                     Dist=GetDistance2d(0,0,xlp,ylp)
                     if Dist<=MaxRadius
                        pos=ylp*MaxRadius+xlp
                        DistanceTable(pos)   =Dist+1
                        AngleTable(pos)      =GetAngle2d(0,0,xlp,ylp)         
                     endif
               next
         next

      endif


      Xpos=XscreenMiddle-MaxRadius

      For ylp= 0 to MaxRadiusMinusOne

               rendertoimage  ScanLineBuffer
            
               cls 0
               
               lockbuffer      
                  ThisRGB=Point(0,0)

                  RowYPos=Ylp*MaxRAdius
   
                  For xlp= RowYpos to RowYpos+MaxRadiusMinusOne
                     Dist=DistanceTable(xlp)

                     ; here we've removed the need for the compare, since Dist
                     ; is now offset from 1 to MaxRadius, so it'll return zero
                     ; when outside the circle.
                     if Dist
                     
                        AngleToPixel=AngleTable(xlp)
                        Angle         =DirectionTable(AngleToPixel)
                        ThisColour  =Colours2(Angle,Dist)            
                  
                        Xlp2=Xlp-RowYpos
                        fastDot maxradius + xlp2,0 ,ThisColour
                        fastDot maxradius - xlp2,0 ,ThisColour
                  
                     endif
                  next

               unlockbuffer      
               rendertoscreen

               lockbuffer      
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle + Ylp,false
                  drawimage ScanLineBuffer,Xpos,YScreenMiddle - Ylp,false
               unlockbuffer      

      next
            
Done:            
      Method$ ="Single Pass Version with cached strips Version #2"

EndPsub Method$

[/pbcode]
Title: Re: Kaleidoscope (optimized)
Post by: kevin on January 31, 2019, 11:18:59 AM
   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