;coded by UEZ build 2016-04-21
#pragma compile(Icon, "c:\Program Files (x86)\AutoIt3\Icons\au3.ico")
#AutoIt3Wrapper_Run_Au3Stripper=y
#Au3Stripper_Parameters=/so /pe /rm
#AutoIt3Wrapper_Run_After=del /f /q "%scriptdir%\%scriptfile%_stripped.au3"

#include <Array.au3>
#include <GDIPlus.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>

_GDIPlus_Startup()
Global $hGUI, $iFPS = 0, $iShowFPS = 0, $bExit, $i
Global Const $iW = 1000, $iH = 800, $iWh = $iW / 2, $iHh = $iH / 2, $sTitle = "GDI+ 3D Object Rotation v1.1.6 alpha"
Global Const $fPi = ACos(-1), $fRad = $fPi / 180, $fDeg = 180 / $fPi

AutoItSetOption("GUIOnEventMode", 1)

GDIPlus_3DRotation()

AutoItSetOption("GUIOnEventMode", 0)
_GDIPlus_Shutdown()


Func GDIPlus_3DRotation()
	$bExit = False
	$hGUI = GUICreate($sTitle, $iW, $iH) ;, -1, -1, $WS_POPUP)
	GUISetState(@SW_SHOW, $hGUI)

	;create canvas elements
	Local Const $hDC = _WinAPI_GetDC($hGUI)
	Local Const $hHBitmap = _WinAPI_CreateCompatibleBitmap($hDC, $iW, $iH)
	Local Const $hDC_backbuffer = _WinAPI_CreateCompatibleDC($hDC)
	Local Const $DC_obj = _WinAPI_SelectObject($hDC_backbuffer, $hHBitmap)
	Local Const $hCanvas = _GDIPlus_GraphicsCreateFromHDC($hDC_backbuffer)
	_GDIPlus_GraphicsSetSmoothingMode($hCanvas, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
	_GDIPlus_GraphicsSetPixelOffsetMode($hCanvas, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)

	Local Const $hBrush_Clr = _GDIPlus_BrushCreateSolid(0xFF000000), _
				$hBrush_FPS = _GDIPlus_BrushCreateSolid(0xFFA0A0A0), _
				$hBrush_Fill = _GDIPlus_BrushCreateSolid(0xA0F0F0F0), _
				$hBrush_Fill_Dark = _GDIPlus_BrushCreateSolid(0x30F0F0F0), _
				$hPen_Line = _GDIPlus_PenCreate(0x80808080, 2), _
				$hPen_Line_Dark = _GDIPlus_PenCreate(0x60707070), _
				$hFormat_FPS = _GDIPlus_StringFormatCreate(), _
				$hFamily_FPS = _GDIPlus_FontFamilyCreate("Arial"), _
				$hFont_FPS = _GDIPlus_FontCreate($hFamily_FPS, 8), _
				$tLayout_FPS = _GDIPlus_RectFCreate(0, 0, 60, 16)

	_GDIPlus_PenSetLineJoin($hPen_Line, 2)
	_GDIPlus_PenSetLineJoin($hPen_Line_Dark, 2)

	$iFPS = 0

	Local Const $hPath = _GDIPlus_PathCreate(), $hFamily = _GDIPlus_FontFamilyCreate("Impact"), $tLayout = _GDIPlus_RectFCreate()
    _GDIPlus_PathAddString($hPath, ChrW(9787) & "AutoIt rulez", $tLayout, $hFamily, 1, 125, 0)
	Local Const $fRadius = 300, $aWorldBounds = _GDIPlus_PathGetWorldBounds($hPath)
	_GDIPlus_FontFamilyDispose($hFamily)
	Local $hMatrix = _GDIPlus_MatrixCreate()
	_GDIPlus_MatrixTranslate($hMatrix, 0, $fRadius - ($aWorldBounds[3] / 2 - $aWorldBounds[1]))
	_GDIPlus_PathTransform($hPath, $hMatrix)

	Local Const $aData = _GDIPlus_PathGetData($hPath)
	ConsoleWrite("Polygon count: " & _GDIPlus_PathGetPointCount($hPath) & @CRLF)

	Local $aSphere = CreateSphere($hPath, $iWh, $iHh, $fRadius)

	Local $iSubPathes = $aSphere[0][0], $aTmp[$iSubPathes + 1][2]
	ConsoleWrite("#Sub pathes = " & $iSubPathes & @CRLF)

	Local $fRotX = 270 * $fRad, $fRotY = 150 * $fRad, $fRotZ = 180 * $fRad, $iFillMode = 0, $i, $j, $fZ, $hPath2
	Local $fRotA = 22.5 * $fRad, $g = 0, $fEllipse = 725, $fEllipse2 = $fEllipse / 2

	_GDIPlus_PathReset($hPath)
	_GDIPlus_PathAddEllipse($hPath, $iWh - $fEllipse2, $iHh - $fEllipse2, $fEllipse, $fEllipse)
	Local $hBrush_Ellipse = _GDIPlus_PathBrushCreateFromPath($hPath)
    _GDIPlus_PathBrushSetCenterColor($hBrush_Ellipse, 0xD0A0A0FF)
    _GDIPlus_PathBrushSetCenterPoint($hBrush_Ellipse, $iWh + 150, $iHh - 150)
    _GDIPlus_PathBrushSetSurroundColor($hBrush_Ellipse, 0xB0080808)
    _GDIPlus_PathBrushSetGammaCorrection($hBrush_Ellipse, True)

	Local Const $hBitmap_Sphere = _GDIPlus_BitmapCreateFromScan0($iW, $iH), $hGfx_Sphere = _GDIPlus_ImageGetGraphicsContext($hBitmap_Sphere)
	_GDIPlus_GraphicsSetSmoothingMode($hGfx_Sphere, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
	_GDIPlus_GraphicsSetPixelOffsetMode($hGfx_Sphere, $GDIP_PIXELOFFSETMODE_HIGHQUALITY)
	_GDIPlus_GraphicsFillPath($hGfx_Sphere, $hPath, $hBrush_Ellipse)

	GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit_About")
	AdlibRegister("CalcFPS", 1000)

	Do
		DllCall($__g_hGDIPDll, "int", "GdipFillRectangle", "handle", $hCanvas, "handle", $hBrush_Clr, "float", 0, "float", 0, _
				"float", $iW, "float", $iH) ;erase canvas background

;~ 		DllCall($__g_hGDIPDll, "int", "GdipFillPath", "handle", $hCanvas, "handle", $hBrush_Ellipse, "handle", $hPath)
		DllCall($__g_hGDIPDll, "int", "GdipDrawImageRect", "handle", $hCanvas, "handle", $hBitmap_Sphere, "float", 0, "float", 0, "float", $iW, "float", $iH)

		For $i = 1 To $iSubPathes
			$tPoints = DllStructCreate("float dots[" & 2 * $aSphere[$i][0] & "]")
			$fZ = 100000
			For $j = 1 To $aSphere[$i][0]
				Switch $i
					Case 1
						Translate3Dto2D($aSphere[$i][1], $j, $fRotA, -$fRotA, 9 * $fRad, $iWh, $iHh, 1, 500)
					Case Else
						Translate3Dto2D($aSphere[$i][1], $j, $fRotX, $fRotY, $fRotZ, $iWh, $iHh, 1, 500)
				EndSwitch
				$tPoints.dots((2 * $j - 1)) = $aSphere[$i][1].fX(($j))
				$tPoints.dots((2 * $j)) = $aSphere[$i][1].fY(($j))
				$fZ = $aSphere[$i][1].fZ(($j)) < $fZ ? $aSphere[$i][1].fZ(($j)) : $fZ
			Next
			$hPath2 = DllCall($__g_hGDIPDll, "int", "GdipCreatePath2", "struct*", $tPoints, "struct*", $aSphere[$i][2], "int", $aSphere[$i][0], "int", 0, "handle*", 0)[5]

			If $fZ > -220 Then ;back
				DllCall($__g_hGDIPDll, "int", "GdipFillPath", "handle", $hCanvas, "handle", $hBrush_Fill_Dark, "handle", $hPath2)
				If $i = 1 Then DllCall($__g_hGDIPDll, "int", "GdipDrawPath", "handle", $hCanvas, "handle", $hPen_Line_Dark, "handle", $hPath2)
			Else ;front
				$iAlpha = Int(Abs($fZ + 0x40))
				$iAlpha = $iAlpha > 0xF0 ? 0xF0 : $iAlpha < 0x50 ? 0x50 : $iAlpha
				_GDIPlus_BrushSetSolidColor($hBrush_Fill, 0x1000000 * $iAlpha + 0xF0F0F0)
				DllCall($__g_hGDIPDll, "int", "GdipFillPath", "handle", $hCanvas, "handle", $hBrush_Fill, "handle", $hPath2)
				DllCall($__g_hGDIPDll, "int", "GdipDrawPath", "handle", $hCanvas, "handle", $hPen_Line, "handle", $hPath2)
			EndIf
			DllCall($__g_hGDIPDll, "int", "GdipDeletePath", "handle", $hPath2)
		Next

		$fRotX -= 0.0025
		$fRotY += 0.02
		$fRotZ += 0.001

		_GDIPlus_GraphicsDrawStringEx($hCanvas, "FPS: " & $iShowFPS, $hFont_FPS, $tLayout_FPS, $hFormat_FPS, $hBrush_FPS) ;draw background message text
		_WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_backbuffer, 0, 0, $SRCCOPY) ;blit drawn bitmap to GUI

		$iFPS += 1
		If $bExit Then ExitLoop
	Until Not Sleep(10)

	AdlibUnRegister("CalcFPS")
	;release resources
	_GDIPlus_MatrixDispose($hMatrix)
    _GDIPlus_PathDispose($hPath)
	_GDIPlus_FontDispose($hFont_FPS)
	_GDIPlus_FontFamilyDispose($hFamily_FPS)
	_GDIPlus_StringFormatDispose($hFormat_FPS)
	_GDIPlus_BrushDispose($hBrush_Clr)
	_GDIPlus_BrushDispose($hBrush_FPS)
	_GDIPlus_BrushDispose($hBrush_Fill)
	_GDIPlus_BrushDispose($hBrush_Ellipse)
	_GDIPlus_PenDispose($hPen_Line)
	_GDIPlus_PenDispose($hPen_Line_Dark)
	_GDIPlus_GraphicsDispose($hCanvas)
	_GDIPlus_GraphicsDispose($hGfx_Sphere)
	_GDIPlus_ImageDispose($hBitmap_Sphere)
	_WinAPI_SelectObject($hDC_backbuffer, $DC_obj)
	_WinAPI_DeleteDC($hDC_backbuffer)
	_WinAPI_DeleteObject($hHBitmap)
	_WinAPI_ReleaseDC($hGUI, $hDC)
	GUIDelete($hGUI)
EndFunc   ;==>GDIPlus_3DRotation

Func Translate3Dto2D(ByRef $tStruct, $iPos, $fRotX, $fRotY, $fRotZ, $fCenterX = 0, $fCenterY = 0, $fScale = 1, $fZDeepCorrection = 1000)
	Local Const $fCosRotX = Cos($fRotX), $fSinRotX = Sin($fRotX), _
				$fCosRotY = Cos($fRotY), $fSinRotY = Sin($fRotY), _
				$fCosRotZ = Cos($fRotZ), $fSinRotZ = Sin($fRotZ), _
				$f1 = $fCosRotY * $tStruct.x(($iPos)), _
				$f2 = $fSinRotX * $tStruct.y(($iPos)), _
				$f3 = $fCosRotX * $tStruct.z(($iPos)), _
				$f4 = $fCosRotX * $tStruct.y(($iPos)), _
				$f5 = $fSinRotX * $tStruct.z(($iPos)), _
				$f6 = $f1 - $fSinRotY * ($f2 + $f3), _
				$fXPos = ($fCosRotZ * $f6 - $fSinRotZ * ($f4 - $f5)) * $fScale, _
				$fYPos = ($fSinRotZ * $f6 + $fCosRotZ * ($f4 - $f5)) * $fScale, _
				$fZPos = ($fSinRotY * $tStruct.x(($iPos)) + $fCosRotY * ($f2 + $f3)) * $fScale, _
				$fZPerspCorrection = 1 / ($fZPos / $fZDeepCorrection + 1)
	$tStruct.fX(($iPos)) = $fXPos * $fZPerspCorrection + $fCenterX
	$tStruct.fY(($iPos)) = $fYPos * $fZPerspCorrection + $fCenterY
	$tStruct.fZ(($iPos)) = $fZPos
EndFunc   ;==>Translate3Dto2D

Func _Exit_About()
	$bExit = True
EndFunc   ;==>_Exit_About

Func CalcFPS() ;display FPS
	$iShowFPS = $iFPS
	$iFPS = 0
EndFunc   ;==>CalcFPS

Func CreateSphere($hPath, $iWh, $iHh, $fRadius = 200)
	Local $hIter = _GDIPlus_PathIterCreate($hPath)
	Local $iIterCnt = _GDIPlus_PathIterGetSubpathCount($hIter)
	Local $aPathes[$iIterCnt + 2][4], $aDataPath
	$aPathes[0][0] = $iIterCnt + 1
	For $i = 2 To $iIterCnt + 1
		$hPath_tmp = _GDIPlus_PathCreate()
		$iAmountDots = _GDIPlus_PathIterNextMarkerPath($hIter, $hPath_tmp)
		$aDataPath = _GDIPlus_PathGetData($hPath_tmp)
		$aPathes[$i][0] = $iAmountDots
		$aPathes[$i][1] = DllStructCreate("struct;float x[" & $iAmountDots & "];float y[" & $iAmountDots & "];float z[" & $iAmountDots & "];float fX[" & $iAmountDots & "];float fY[" & $iAmountDots & "];float fZ[" & $iAmountDots & "];endstruct")
		$aPathes[$i][2] = DllStructCreate("struct;byte type[" & $iAmountDots & "];endstruct")
		For $j = 1 To $iAmountDots
			$fLongitude = ($iWh - $aDataPath[$j][0]) / $fRadius
			$fLatitude = 2 * ATan(2.718281828^(($iHh - $aDataPath[$j][1]) / $fRadius)) - ($fPi / 2)
			$aPathes[$i][1].x(($j)) = $fRadius * Cos(-$fLatitude) * Cos(-$fLongitude)
			$aPathes[$i][1].y(($j)) = $fRadius * Cos(-$fLatitude) * Sin(-$fLongitude)
			$aPathes[$i][1].z(($j)) = $fRadius * Sin($fLatitude)
			$aPathes[$i][2].type(($j)) = $aDataPath[$j][2]
		Next
		_GDIPlus_PathDispose($hPath_tmp)
	Next
	_GDIPlus_PathIterDispose($hIter)
	$iAmountDots = 6
	Local $fLength = 250
	$aPathes[1][0] = $iAmountDots
	$aPathes[1][1] = DllStructCreate("struct;float x[" & $iAmountDots & "];float y[" & $iAmountDots & "];float z[" & $iAmountDots & "];float fX[" & $iAmountDots & "];float fY[" & $iAmountDots & "];float fZ[" & $iAmountDots & "];endstruct")
	$aPathes[1][2] = DllStructCreate("struct;byte type[" & $iAmountDots & "];endstruct")
	$aPathes[1][1].x((1)) = 0
	$aPathes[1][1].y((1)) = -$fLength
	$aPathes[1][1].z((1)) = 0
	$aPathes[1][2].type((1)) = 0
	$aPathes[1][1].x((2)) = 0
	$aPathes[1][1].y((2)) = $fLength
	$aPathes[1][1].z((2)) = 0
	$aPathes[1][2].type((2)) = 0x1

	$aPathes[1][1].x((3)) = -$fLength
	$aPathes[1][1].y((3)) = 0
	$aPathes[1][1].z((3)) = 0
	$aPathes[1][2].type((3)) = 0
	$aPathes[1][1].x((4)) = $fLength
	$aPathes[1][1].y((4)) = 0
	$aPathes[1][1].z((4)) = 0
	$aPathes[1][2].type((4)) = 0x1

	$aPathes[1][1].x((5)) = 0
	$aPathes[1][1].y((5)) = 0
	$aPathes[1][1].z((5)) = -$fLength
	$aPathes[1][2].type((5)) = 0
	$aPathes[1][1].x((6)) = 0
	$aPathes[1][1].y((6)) = 0
	$aPathes[1][1].z((6)) = $fLength
	$aPathes[1][2].type((6)) = 0x1

	Return $aPathes
EndFunc