;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.7 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(0xA0101010, 1), _
				$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

	;Lucida Sans Unicode = 1328
	;Lucida Console = 1363
	;Franklin Gothic Medium = 1451
	;Trebuchet MS = 1569

	Local Const $hPath = _GDIPlus_PathCreate(), $hFamily = _GDIPlus_FontFamilyCreate("Lucida Sans Unicode"), $tLayout = _GDIPlus_RectFCreate()
    _GDIPlus_PathAddString($hPath, "This is a scroller around a sphere using GDI+", $tLayout, $hFamily, 1, 20, 0)
	Local Const $fRadius = 300, $aWorldBounds = _GDIPlus_PathGetWorldBounds($hPath)
	_GDIPlus_FontFamilyDispose($hFamily)
	Local $hMatrix = _GDIPlus_MatrixCreate()
	_GDIPlus_MatrixTranslate($hMatrix, 0, 383)
	_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 = -240 * $fRad, $fRotZ = 180 * $fRad, $iFillMode = 0, $i, $j, $fZ, $hPath2, $tPoints, $iAlpha
	Local $fRotA = 22.5 * $fRad, $g = 0, $fEllipse = 740, $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, 0xFFFFE21B)
    _GDIPlus_PathBrushSetCenterPoint($hBrush_Ellipse, $iWh + 150, $iHh - 150)
    _GDIPlus_PathBrushSetSurroundColor($hBrush_Ellipse, 0xE0101010)
;~     _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)


;~ 	_GDIPlus_PathCreate2
	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", "GdipDrawImageRect", "handle", $hCanvas, "handle", $hBitmap_Sphere, "float", 0, "float", 0, "float", $iW, "float", $iH)
;~ 		DllCall($__g_hGDIPDll, "int", "GdipFillPath", "handle", $hBitmap_Sphere, "handle", $hBrush_Ellipse, "handle", $hPath) ;slow!
;~ 		_GDIPlus_GraphicsDrawLine($hCanvas, 0, $iHh, $iW, $iHh, $hPen_Line)

		For $i = 1 To $iSubPathes
			$tPoints = DllStructCreate("struct;float dots[" & 2 * $aSphere[$i][0] & "];endstruct")
			$fZ = 10000
			For $j = 1 To $aSphere[$i][0]
				Translate3Dto2D($aSphere[$i][1], $j, $fRotX, $fRotY, $fRotZ, $iWh, $iHh, 1, 500)
				$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
			If $fZ < -185 Then ;front
				$hPath2 = DllCall($__g_hGDIPDll, "int", "GdipCreatePath2", "struct*", $tPoints, "struct*", $aSphere[$i][2], "int", $aSphere[$i][0], "int", 0, "handle*", 0)[5]
				$iAlpha = Int(Abs($fZ + 0xB0))
				$iAlpha = $iAlpha > 0xF0 ? 0xF0 : $iAlpha < 0x10 ? 0x10 : $iAlpha
				DllCall($__g_hGDIPDll, "int", "GdipSetSolidFillColor", "handle", $hBrush_Fill, "dword", 0x1000000 * $iAlpha + 0xFFFFFF)
				DllCall($__g_hGDIPDll, "int", "GdipFillPath", "handle", $hCanvas, "handle", $hBrush_Fill, "handle", $hPath2)
;~ 				DllCall($__g_hGDIPDll, "int", "GdipDrawPath", "handle", $hCanvas, "handle", $hPen_Line, "handle", $hPath2)
				DllCall($__g_hGDIPDll, "int", "GdipDeletePath", "handle", $hPath2)
			EndIf
		Next

;~ 		$fRotX -= 0.0025
		$fRotY += 0.01
;~ 		$fRotZ += 0.01

		_GDIPlus_GraphicsDrawStringEx($hCanvas, "FPS: " & $iShowFPS, $hFont_FPS, $tLayout_FPS, $hFormat_FPS, $hBrush_FPS)
		_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, $iFlatten = 1)
;~ 	_GDIPlus_PathWindingModeOutline($hPath, 0, 0.252)
	Local $hIter = _GDIPlus_PathIterCreate($hPath)
	Local $iIterCnt = _GDIPlus_PathIterGetSubpathCount($hIter)
	Local $aPathes[$iIterCnt + 1][3], $aDataPath
	$aPathes[0][0] = $iIterCnt
	For $i = 1 To $iIterCnt
		$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)
	Return $aPathes
EndFunc