#Region Includes
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <Color.au3>
#include <GDIPlus.au3>
#include <Misc.au3>
#EndRegion


#Region Declarations
;~ Window
Global $wWidth = @DesktopWidth
Global $wHeight = @DesktopHeight
Global $wCenter_x = $wWidth / 2
Global $wCenter_y = $wHeight / 2
Global $center_x = @DesktopWidth/2
Global $center_y = @DesktopHeight/2
Global $wZero_x = $center_x-($wWidth/2)
Global $wZero_y = $center_y-($wHeight/2)

;~ Environment
Global $pi = 3.141592653589793
Global $hist_on, $animation, $info, $tooltip
Global $mouseX, $mouseY
Global $mode, $mode_num
$hist_on = -1
$animation = -1
$info = 1
$tooltip = 1
$mode = 0
$mode_num = 8

;~ Object
Global $size = 4
Global $num = 1000
Global $aPoints[$num+1][2]
Global $t, $t_min, $t_max, $t_step
Global $scale
Global $rand_x[19], $rand_y[19]
$aPoints[0][0] = $num
$t_min = -0.5
$t_max = 0.5
$t_step = 0.001
$scale = 500

;~ Infobox (topleft)
Global $string_x, $string_y, $string_mode[$mode_num+1], $summand[19]
$summand[1] = "-t^2"
$summand[2] = "-y^2"
$summand[3] = "-x^2"
$summand[5] = "-xt"
$summand[6] = "-xy"
$summand[7] = "-t"
$summand[8] = "-y"
$summand[9] = "-x"
$summand[10] = "t^1"
$summand[11] = "y^2"
$summand[12] = "x^2"
$summand[13] = "yt"
$summand[14] = "xt"
$summand[15] = "xy"
$summand[16] = "t"
$summand[17] = "y"
$summand[18] = "x"
$string_mode[1] = "Star"
$string_mode[2] = "Seastar"
$string_mode[3] = "Tornado"
$string_mode[4] = "Universe"
$string_mode[5] = "Cubicaluniverse"
$string_mode[6] = "Square"
$string_mode[7] = "Party"
$string_mode[8] = "Random"
#EndRegion


#Region Gui
$hGui = GUICreate("Form1", $wWidth, $wHeight, $wZero_x, $wZero_y, -2147483648)
GUISetState(@SW_SHOW)
Opt("GUIOnEventMode", 1)
GUISetOnEvent($GUI_EVENT_CLOSE, "SpecialEvents")
GUIRegisterMsg($WM_MOUSEWHEEL, "_WM_MOUSEWHEEL")
#EndRegion


#Region ### START GDI+ ###
_GDIPlus_Startup()
$hGraphic = _GDIPlus_GraphicsCreateFromHWND($hGui)

;~ Bitmaps
$hGraphicBitmap = _GDIPlus_BitmapCreateFromGraphics($wWidth, $wHeight, $hGraphic)
$hHistoryBitmap = _GDIPlus_BitmapCreateFromScan0($wWidth, $wHeight)
$hCurrentBitmap = _GDIPlus_BitmapCreateFromScan0($wWidth, $wHeight)

;~ Buffers
$hGraphicBuffer = _GDIPlus_ImageGetGraphicsContext($hGraphicBitmap)
$hHistoryBuffer = _GDIPlus_ImageGetGraphicsContext($hHistoryBitmap)
$hCurrentBuffer = _GDIPlus_ImageGetGraphicsContext($hCurrentBitmap)

;~ PixxelOfset
_GDIPlus_GraphicsSetPixelOffsetMode($hGraphicBuffer, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)
_GDIPlus_GraphicsSetPixelOffsetMode($hHistoryBuffer, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)
_GDIPlus_GraphicsSetPixelOffsetMode($hCurrentBuffer, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)

;~ Smoothing
_GDIPlus_GraphicsSetSmoothingMode($hGraphicBuffer, 4)
_GDIPlus_GraphicsSetSmoothingMode($hHistoryBuffer, 4)
_GDIPlus_GraphicsSetSmoothingMode($hCurrentBuffer, 4)

;~ First clearing
_GDIPlus_GraphicsClear($hGraphicBuffer, 0xFFFFFFFF)
_GDIPlus_GraphicsClear($hHistoryBuffer, 0xFFFFFFFF)
_GDIPlus_GraphicsClear($hCurrentBuffer, 0xFFFFFFFF)

;~ Pens
$hPen = _GDIPlus_PenCreate(0x44000000, 1)

;~ Brushes
Global $hBrush_col[3], $hBrush[$num+1], $step
$hBrush_col[0] = 0xFF
$hBrush_col[1] = 0x00
$hBrush_col[2] = 0xFF
$step = 40
For $i = 1 To $num Step 1
   If $i <= 1*$step Then
	  $hBrush_col[2] -= 0x06
   ElseIf $i <= 2*$step Then
	  $hBrush_col[1] += 0x06
   ElseIf $i <= 3*$step Then
	  $hBrush_col[0] -= 0x06
   ElseIf $i <= 4*$step Then
	  $hBrush_col[2] += 0x06
   ElseIf $i <= 5*$step Then
	  $hBrush_col[1] -= 0x06
   ElseIf $i <= 6*$step Then
	  $hBrush_col[0] += 0x06
   EndIf
   $hBrush[$i] = _GDIPlus_BrushCreateSolid()
   _GDIPlus_BrushSetSolidColor($hBrush[$i], "0xFF" & Hex(_ColorSetRGB($hBrush_col), 6))
Next
$hBrush_hist = _GDIPlus_BrushCreateSolid(0x110000FF)
$hBrush_info = _GDIPlus_BrushCreateSolid(0xFF000000)

;~ Letters (topleft)
$hFormat = _GDIPlus_StringFormatCreate()
$hFamily = _GDIPlus_FontFamilyCreate ("Arial")
$hFont = _GDIPlus_FontCreate ($hFamily, 15, 0)
#EndRegion ### END GDI+ ###


#Region HotKeySet
HotKeySet("{c}", "_clear")
HotKeySet("{h}", "_hist_on")
HotKeySet("{r}", "_random")
HotKeySet("{m}", "_mode")
HotKeySet("{t}", "_tooltip")
HotKeySet("{a}", "_animation")
HotKeySet("{s}", "_smaller")
HotKeySet("{b}", "_bigger")
HotKeySet("{i}", "_info")
HotKeySet("{f}", "_faster")
HotKeySet("{l}", "_lazier")
#EndRegion


#Region INIT & Loop
_random()
_mode()
While 1
   _Calc()
   _Draw_normal()
WEnd
#EndRegion


#Region Functions Process
Func _Calc()
;~    Declare 't' depending on mouses Y-Position or on variable $animation
   If $animation == 1 Then
	  If $t < $t_max Then
		 $t += $t_step
	  EndIf
   Else
	  $mouseY = MouseGetPos(0)
	  $t = $t_min + ($mouseY / @DesktopWidth) * ($t_max-$t_min)
   EndIf

;~    Show 't' in tooltip
   If $tooltip == 1 Then
	  ToolTip("t = " & Round($t, 3))
   Else
	  ToolTip("",0,0)
   EndIf

;~    Start point (corresponding to the video, its 't' for both coordinates)
   $aPoints[1][0] = $t
   $aPoints[1][1] = $t

;~    Following points (every point is depending on its previous one in the timeserie)
   For $i = 2 To $num Step 1
	  $aPoints[$i][0] = _choice($aPoints[$i-1][0], $aPoints[$i-1][1], 0, $mode)
	  $aPoints[$i][1] = _choice($aPoints[$i-1][0], $aPoints[$i-1][1], 1, $mode)
   Next

;~    Move picture to the middle of the image and scale it
   For $i = 1 To $num Step 1
	  $aPoints[$i][0] = $wCenter_x + $aPoints[$i][0]*$scale - $size/2
	  $aPoints[$i][1] = $wCenter_y + $aPoints[$i][1]*$scale - $size/2
   Next
EndFunc


Func _Draw_normal()
   ;~    Clear
   _GDIPlus_GraphicsDrawImageRect($hCurrentBuffer, $hHistoryBitmap, 0, 0, $wWidth, $wHeight)

   ;~    Draw X- and Y-Axis
   _GDIPlus_GraphicsDrawLine($hCurrentBuffer, $wCenter_x, 0, $wCenter_x, $wHeight, $hPen)
   _GDIPlus_GraphicsDrawLine($hCurrentBuffer, 0, $wCenter_y, $wWidth, $wCenter_y, $hPen)

   ;~    Draw pieces
   For $i = 1 To $num Step 1
	  _GDIPlus_GraphicsFillEllipse($hCurrentBuffer, $aPoints[$i][0], $aPoints[$i][1], $size, $size, $hBrush[$i])
   Next

   ;~    Draw history
   If $hist_on == 1 Then
	  For $i = 1 To $num Step 1
		 _GDIPlus_GraphicsFillEllipse($hHistoryBuffer, $aPoints[$i][0], $aPoints[$i][1], $size, $size, $hBrush_hist)
	  Next
   EndIf

;~    Information about curve (topleft)
   If $info == 1 Then
	  Local $string_info = $string_x & @CRLF & $string_y & @CRLF & "Mode = " & $string_mode[$mode] & @CRLF & _
						   "t-min/max = +- " & $t_max & @CRLF & "Zoom-Factor = " & $scale & @CRLF & "Animation-Speed = " & $t_step
	  $tLayout = _GDIPlus_RectFCreate (10, 10, 0, 0)
	  $aInfo = _GDIPlus_GraphicsMeasureString ($hGraphic, $string_info, $hFont, $tLayout, $hFormat)
	  _GDIPlus_GraphicsDrawStringEx ($hCurrentBuffer, $string_info, $hFont, $aInfo[0], $hFormat, $hBrush_info)
   EndIf

;~    Draw finally
   _GDIPlus_GraphicsDrawImageRect($hGraphicBuffer, $hHistoryBitmap,0, 0, $wWidth, $wHeight)
   _GDIPlus_GraphicsDrawImageRect($hGraphicBuffer, $hCurrentBitmap,0, 0, $wWidth, $wHeight)
   _GDIPlus_GraphicsDrawImageRect($hGraphic, $hGraphicBitmap, 0, 0, $wWidth, $wHeight)
EndFunc


Func _mode()
;~    Increase or reset/init 'mode'
   If $mode < $mode_num Then
	  $mode += 1
   Else
	  $mode = 1
   EndIf

;~    Update information (topleft)
   If $mode == 1 Then
	  $string_x = "X = -(x^2) + x*t + y"
	  $string_y = "Y = x^2 - y^2 - t^2 - x*y + y*t - x + y"
   ElseIf $mode == 2 Then
	  $string_x = "X = y + t + y*t - (x^2)"
	  $string_y = "Y = -x + y - t - y*t + t^2"
   ElseIf $mode == 3 Then
	  $string_x = "X = -(y^2) - t^2 - x*y - x*t - y*t - x - t"
	  $string_y = "Y = t^2 - x*t - y"
   ElseIf $mode == 4 Then
	  $string_x = "X = x^2 - x*t + y + t"
	  $string_y = "Y = x^2 + y^2 + t^2 - x*t - x + y"
   ElseIf $mode == 5 Then
	  $string_x = "X = -x + y + x*t + x^2 + y^2 + t^2"
	  $string_y = "Y = -y - x*t + y^2 + t^2"
   ElseIf $mode == 6 Then
	  $string_x = "X = y - t - x*y - y^2 + t^2"
	  $string_y = "Y = -x - t -x*t -y*t"
   ElseIf $mode == 7 Then
	  $string_x = "X = -x + y + x*y - x*t + y*t - x^2"
	  $string_y = "Y = x + x*y - x*t - y^2"
   ElseIf $mode == 8 Then
	  $string_x = "X = "
	  $string_y = "Y = "
	  For $i = 1 To 18 Step 1
		 If $rand_x[$i] == 1 Then
			$string_x = $string_x & $summand[$i] & " ; "
		 EndIf
		 If $rand_y[$i] == 1 Then
			$string_y = $string_y & $summand[$i] & " ; "
		 EndIf
	  Next
   EndIf
EndFunc


Func _choice($x, $y, $var, $m)
;~    Make calculation depending on current 'mode'
   If $m == 1 Then
	  Return (_star($x, $y, $var))
   ElseIf $m == 2 Then
	  Return (_seastar($x, $y, $var))
   ElseIf $m == 3 Then
	  Return (_tornado($x, $y, $var))
   ElseIf $m == 4 Then
	  Return (_universe($x, $y, $var))
   ElseIf $m == 5 Then
	  Return (_cubicaluniverse($x, $y, $var))
   ElseIf $m == 6 Then
	  Return (_square($x, $y, $var))
   ElseIf $m == 7 Then
	  Return (_party($x, $y, $var))
   ElseIf $m == 8 Then
	  Return (_rand($x, $y, $var))
   EndIf
EndFunc


Func _random()
;~    Generate a random calculation
   $string_x = "X = "
   $string_y = "Y = "
   ConsoleWrite("New Random Numbers are: " & @CRLF)
   For $i = 1 To 18 Step 1
	  $rand_x[$i] = Random(0, 1, 1)
	  $rand_y[$i] = Random(0, 1, 1)
	  If $rand_x[$i] == 1 Then
		 $string_x = $string_x & $summand[$i] & " ; "
	  EndIf
	  If $rand_y[$i] == 1 Then
		 $string_y = $string_y & $summand[$i] & " ; "
	  EndIf
   Next
   ConsoleWrite($string_x & @CRLF)
   ConsoleWrite($string_y & @CRLF)
EndFunc


Func _hist_on()
   $hist_on *= -1
EndFunc


Func _tooltip()
   $tooltip *= -1
EndFunc


Func _smaller()
   $t_min += 0.05
   $t_max -= 0.05
EndFunc


Func _bigger()
   $t_min -= 0.05
   $t_max += 0.05
EndFunc


Func _faster()
   $t_step *= 2
EndFunc


Func _lazier()
   $t_step /= 2
EndFunc


Func _animation()
   $animation *= -1
EndFunc


Func _info()
   $info *= -1
EndFunc


Func _clear()
   _GDIPlus_GraphicsClear($hGraphicBuffer, 0xFFFFFFFF)
   _GDIPlus_GraphicsClear($hHistoryBuffer, 0xFFFFFFFF)
   _GDIPlus_GraphicsClear($hCurrentBuffer, 0xFFFFFFFF)
EndFunc


Func _Exit()
   _GDIPlus_GraphicsDispose($hGraphic)
   _GDIPlus_PenDispose($hPen)
   _GDIPlus_Shutdown()
   Exit
EndFunc
#EndRegion


#Region Mathematical Functions
Func _star($x, $y, $var)
   If $var == 0 Then
	  Return (-($x^2) + $x*$t + $y)
   ElseIf $var == 1 Then
	  Return ($x^2 - $y^2 - $t^2 - $x*$y + $y*$t - $x + $y)
   EndIf
EndFunc


Func _seastar($x, $y, $var)
   If $var == 0 Then
	  Return ($y + $t + $y*$t - ($x^2))
   ElseIf $var == 1 Then
	  Return (-$x + $y - $t - $y*$t + $t^2)
   EndIf
EndFunc


Func _tornado($x, $y, $var)
   If $var == 0 Then
	  Return (-($y^2) - $t^2 - $x*$y - $x*$t - $y*$t - $x - $t)
   ElseIf $var == 1 Then
	  Return ($t^2 - $x*$t - $y)
   EndIf
EndFunc


Func _universe($x, $y, $var)
   If $var == 0 Then
	  Return ($x^2 - $x*$t + $y + $t)
   ElseIf $var == 1 Then
	  Return ($x^2 + $y^2 + $t^2 - $x*$t - $x + $y)
   EndIf
EndFunc


Func _cubicaluniverse($x, $y, $var)
   If $var == 0 Then
	  Return (-$x + $y + $x*$t + $x^2 + $y^2 + $t^2)
   ElseIf $var == 1 Then
	  Return (-$y - $x*$t + $y^2 + $t^2)
   EndIf
EndFunc


Func _square($x, $y, $var)
   If $var == 0 Then
	  Return ($y - $t - $x*$y - $y^2 + $t^2)
   ElseIf $var == 1 Then
	  Return (-$x - $t -$x*$t -$y*$t)
   EndIf
EndFunc


Func _party($x, $y, $var)
   If $var == 0 Then
	  Return (-$x + $y + $x*$y - $x*$t + $y*$t - $x^2)
   ElseIf $var == 1 Then
	  Return ($x + $x*$y - $x*$t - $y^2)
   EndIf
EndFunc


Func _rand($x, $y, $var)
   If $var == 0 Then
	  Return ($rand_x[1]* -($t^2)+ _
			   $rand_x[2]* -($y^2)+ _
			   $rand_x[3]* -($x^2)+ _
			   $rand_x[4]* -($y*$t)+ _
			   $rand_x[5]* -($x*$t)+ _
			   $rand_x[6]* -($x*$y)+ _
			   $rand_x[7]* -($t) + _
			   $rand_x[8]* -($y) + _
			   $rand_x[9]* -($x) + _
			   $rand_x[10]* $t^2 + _
			   $rand_x[11]* $y^2 + _
			   $rand_x[12]* $x^2 + _
			   $rand_x[13]* $y*$t + _
			   $rand_x[14]* $x*$t + _
			   $rand_x[15]* $x*$y + _
			   $rand_x[16]* $t + _
			   $rand_x[17]* $y + _
			   $rand_x[18]* $x)
;~ 	  Return (-$y - $y*$t)
   ElseIf $var == 1 Then
	  Return ($rand_y[1]* -($t^2)+ _
			   $rand_y[2]* -($y^2)+ _
			   $rand_y[3]* -($x^2)+ _
			   $rand_y[4]* -($y*$t)+ _
			   $rand_y[5]* -($x*$t)+ _
			   $rand_y[6]* -($x*$y)+ _
			   $rand_y[7]* -($t) + _
			   $rand_y[8]* -($y) + _
			   $rand_y[9]* -($x) + _
			   $rand_y[10]* $t^2 + _
			   $rand_y[11]* $y^2 + _
			   $rand_y[12]* $x^2 + _
			   $rand_y[13]* $y*$t + _
			   $rand_y[14]* $x*$t + _
			   $rand_y[15]* $x*$y + _
			   $rand_y[16]* $t + _
			   $rand_y[17]* $y + _
			   $rand_y[18]* $x)
;~ 	  Return ($x^2 + $y^2 - $x - $t^2)
   EndIf
EndFunc
#EndRegion


#Region Event Functions and HotKeySet
Func _WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)
   If $wParam = 0x00780000 Then
	  $scale += 50
   ElseIf $wParam = 0xFF880000 Then
	  $scale -= 50
   EndIf
EndFunc


Func SpecialEvents()
   Select
      Case @GUI_CtrlId = $GUI_EVENT_CLOSE
         GUIDelete()
         _Exit()
   EndSelect
EndFunc
#EndRegion