Advertisement
Hadlock

Show-BoxDemo 3d graphical powershell v5

Jun 28th, 2015
316
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#
  2. requires ps v5.0 or higher (uses ps classes)
  3. http://www.leeholmes.com/blog/2014/10/09/playing-with-classes-in-powershell-v5-preview/
  4. Playing with Classes in PowerShell v5 Preview
  5.  
  6. Thursday, 9 October 2014
  7. One of the features we’re working on in the latest version of PowerShell is the ability to define custom classes.
  8.  
  9. If you’ve ever used a PSCustomObject or a Hashtable in a script for storing related data, you’ll probably find classes to be a useful addition to your scripting toolkit.
  10.  
  11. And Show-BoxDemo in all of its glory. TAB switches between objects, and there are a few other hotkeys in the source.
  12.  
  13. http://www.leeholmes.com/projects/boxdemo/Show-BoxDemo.ps1
  14.  
  15. #>
  16. [CmdletBinding()]
  17. param()
  18.  
  19. ## Class to hold a 3d point
  20. class Point
  21. {    
  22.     Point($xCoord, $yCoord, $zCoord)
  23.     {
  24.         $this.X = $xCoord
  25.         $this.Y = $yCoord
  26.         $this.Z = $zCoord
  27.     }
  28.  
  29.     [double] $X
  30.     [double] $Y
  31.     [double] $Z
  32. }
  33.  
  34. ## Class that represents a 3d object that can be populated, rotated, and drawn.
  35. class GraphicObject
  36. {
  37.     ## Creates an instance of the GraphicObject class with no default
  38.     ## points.
  39.     GraphicObject()
  40.     {
  41.         $this.Points = [System.Collections.Generic.List[Point]]::New()
  42.         $this._backBuffer = " " * ([Console]::WindowWidth * ([Console]::WindowHeight - 1))
  43.     }
  44.    
  45.     ## The list of points in this object
  46.     [System.Collections.Generic.List[Point]] $Points
  47.  
  48.     ## A virtual console buffer to make updates appear smoother
  49.     [char[]] $_backBuffer
  50.  
  51.     ## Some scale factors to account for console dimensions and character aspect
  52.     ## ratios
  53.     $Transpose = ([Console]::WindowWidth / 2), ([Console]::WindowHeight / 2)
  54.     $Scale = 2, 2
  55.     $CharacterType = [CharacterType]::Dot
  56.  
  57.  
  58.     ## Draws the object
  59.     [Void] Draw()
  60.     {
  61.         $pointList = [System.Collections.Generic.List[Point]]::New()
  62.         foreach($point in $this.Points)
  63.         {
  64.             $pointlist.Add( [Point]::New( $point.X, $point.Y, $point.Z ))
  65.         }
  66.  
  67.         $this.Draw($pointlist, $this.CharacterType)
  68.     }
  69.  
  70.     ## Draws the object with the given character type
  71.     [Void] Draw($PointsToDraw, [CharacterType] $character)
  72.     {
  73.         $this._backBuffer = " " * ([Console]::WindowWidth * ([Console]::WindowHeight - 1))
  74.  
  75.         ## Map the enum to an actual character
  76.         $charToDraw = switch($character)
  77.         {
  78.             ([CharacterType]::Dot) { '.' }
  79.             ([CharacterType]::Star) { '*' }
  80.         }
  81.  
  82.         ## Iterate through the points in the object. We do this from far to near, although
  83.         ## it doesn't actually matter in this example.
  84.         foreach($point in $PointsToDraw | Sort-Object -Descending -Property Z)
  85.         {
  86.             $this._PutPixel($point.X, $point.Y, $point.Z, $charToDraw)
  87.         }
  88.  
  89.         ## Replace the console text with what we drew to the background buffer
  90.         [Console]::SetCursorPosition(0,0)
  91.         [Console]::Write($this._backBuffer)
  92.     }
  93.  
  94.     ## Rotates the object along x, y, and z.
  95.     [void] Rotate($xDegrees, $yDegrees, $zDegrees)
  96.     {
  97.         $xRadians = $this._DegreesToRadians($xDegrees)
  98.         $yRadians = $this._DegreesToRadians($yDegrees)
  99.         $zRadians = $this._DegreesToRadians($zDegrees)
  100.  
  101.         foreach($point in $this.Points)
  102.         {
  103.             ## Rotate on X
  104.             $oldX = $point.X
  105.             $oldY = $point.Y
  106.             $oldZ = $point.Z
  107.  
  108.             $point.Y = [Math]::Cos($xRadians) * $oldY -
  109.                        [Math]::Sin($xRadians) * $oldZ
  110.  
  111.             $point.Z = [Math]::Sin($xRadians) * $oldY +
  112.                        [Math]::Cos($xRadians) * $oldZ
  113.  
  114.             ## Rotate on Y
  115.             $oldX = $point.X
  116.             $oldY = $point.Y
  117.             $oldZ = $point.Z
  118.  
  119.             $point.X = [Math]::Cos($yRadians) * $oldX -
  120.                        [Math]::Sin($yRadians) * $oldZ
  121.  
  122.             $point.Z = [Math]::Sin($yRadians) * $oldX +
  123.                        [Math]::Cos($yRadians) * $oldZ
  124.  
  125.  
  126.             ## Rotate on Z
  127.             $oldX = $point.X
  128.             $oldY = $point.Y
  129.             $oldZ = $point.Z
  130.  
  131.             $point.X = [Math]::Cos($zRadians) * $oldX -
  132.                        [Math]::Sin($zRadians) * $oldY
  133.  
  134.             $point.Y = [Math]::Sin($zRadians) * $oldX +
  135.                        [Math]::Cos($zRadians) * $oldY
  136.         }              
  137.     }
  138.  
  139.     ## Helper function to write a character to the screen in the given location
  140.     [void] _PutPixel($x, $y, $z, $character)
  141.     {
  142.         $scaledX = [int] ($x  * $this.scale[0] + $this.transpose[0])
  143.         $scaledY = [int] ($y  * (3/4) * $this.scale[1] + $this.transpose[1])
  144.  
  145.         ## If we wanted to account for perspective or camera distance,
  146.         ## we would apply that to X and Y based on the Z coordinate. Skip
  147.         ## that for simplicity.
  148.  
  149.         $this._backBuffer[([Console]::WindowWidth * $scaledY) + $scaledX] = $character
  150.     }
  151.  
  152.     ## Helper function to convert degrees to radians
  153.     [double] _DegreesToRadians($degrees)
  154.     {
  155.         return $degrees / 180 * [Math]::Pi
  156.     }
  157.  
  158.     ## Static methods to return interesting object types
  159.     static [GraphicObject] Box()
  160.     {
  161.         $object = [GraphicObject]::New()
  162.         $min = -1 * [Console]::WindowHeight / 3
  163.         $max = [Console]::WindowHeight / 3
  164.         for($x = $min; $x -lt $max; $x++)
  165.         {
  166.             $object.Points.Add([Point]::New($x, $min, $min))
  167.             $object.Points.Add([Point]::New($x, $max, $min))
  168.             $object.Points.Add([Point]::New($x, $min, $max))
  169.             $object.Points.Add([Point]::New($x, $max, $max))
  170.         }
  171.  
  172.         for($y = $min; $y -lt $max; $y++)
  173.         {
  174.             $object.Points.Add([Point]::New($min, $y, $min))
  175.             $object.Points.Add([Point]::New($max,$y, $min))
  176.             $object.Points.Add([Point]::New($min, $y, $max))
  177.             $object.Points.Add([Point]::New($max, $y, $max))
  178.         }
  179.  
  180.         for($z = $min; $z -lt $max; $z++)
  181.         {
  182.             $object.Points.Add([Point]::New($min, $min, $z))
  183.             $object.Points.Add([Point]::New($max, $min, $z))
  184.             $object.Points.Add([Point]::New($min, $max, $z))
  185.             $object.Points.Add([Point]::New($max, $max, $z))
  186.         }
  187.  
  188.         $object.Transpose = ([Console]::WindowWidth / 2), ([Console]::WindowHeight / 2)
  189.  
  190.         $scaleFactor = [Console]::WindowHeight / ($max - $min) * 2/3
  191.         $object.Scale = $scaleFactor, $scaleFactor
  192.         return $object
  193.     }
  194.  
  195.     static [GraphicObject] Saddle()
  196.     {
  197.         $object = [GraphicObject]::New()
  198.         $min = -1
  199.         $max = 1
  200.         $increment = 0.15
  201.         for($x = $min; $x -lt $max; $x += $increment)
  202.         {
  203.             for($y = $min; $y -lt $max; $y += $increment)
  204.             {
  205.                 $object.Points.Add([Point]::New($x, $y, ($x * $x) - ($y * $y)))
  206.             }
  207.         }
  208.  
  209.         $object.Transpose = ([Console]::WindowWidth / 2), ([Console]::WindowHeight / 2)
  210.  
  211.         $scaleFactor = [Console]::WindowHeight / ($max - $min) * 2/3
  212.         $object.Scale = $scaleFactor, $scaleFactor
  213.         return $object
  214.     }
  215.  
  216.     static [GraphicObject] Helix()
  217.     {
  218.         $object = [GraphicObject]::New()
  219.  
  220.         $rotationDegrees = 0
  221.         for($z = -1; $z -lt 1; $z += 0.01)
  222.         {
  223.             $object.Points.Add([Point]::New([Math]::Sin($rotationDegrees), [Math]::Cos($rotationDegrees), $z))
  224.             $rotationDegrees += 0.1 % (2 * [Math]::Pi)
  225.         }
  226.  
  227.         $object.Transpose = ([Console]::WindowWidth / 2), ([Console]::WindowHeight / 2)
  228.  
  229.         $scaleFactor = [Console]::WindowHeight / 3
  230.         $object.Scale = $scaleFactor, $scaleFactor
  231.         return $object
  232.     }
  233.  
  234.     static [GraphicObject] PowerShell()
  235.     {
  236.         $centerX = 115
  237.         $centerY = 168
  238.  
  239.         $max = 180
  240.         $min = 1
  241.  
  242.         $object = [GraphicObject]::New()
  243.  
  244.         foreach($zIndex in -10,0,10)
  245.         {
  246.             [System.Collections.Generic.List[Point]] $newPoints =
  247.                 [GraphicObject]::DrawLine(74 - $centerX, 196 - $centerY, 194 - $centerX, 113 - $centerY, $zIndex)
  248.             $object.Points.AddRange($newPoints)
  249.  
  250.  
  251.             [System.Collections.Generic.List[Point]] $newPoints =
  252.                 [GraphicObject]::DrawLine(106 - $centerX, 34 - $centerY, 194 - $centerX, 113 - $centerY, $zIndex)
  253.             $object.Points.AddRange($newPoints)
  254.  
  255.             [System.Collections.Generic.List[Point]] $newPoints =
  256.                 [GraphicObject]::DrawLine(134 - $centerX, 186 - $centerY, 204 - $centerX, 186 - $centerY, $zIndex)
  257.             $object.Points.AddRange($newPoints)
  258.         }
  259.  
  260.         $scaleFactor = [Console]::WindowHeight / ($max - $min) * 2/3
  261.         $object.Scale = $scaleFactor, $scaleFactor
  262.         return $object
  263.     }
  264.    
  265.     ## Basic implementation of the Bresenham line drawing algorithm
  266.     static [System.Collections.Generic.List[Point]] DrawLine($startX, $startY, $endX, $endY, $zIndex)
  267.     {
  268.         [System.Collections.Generic.List[Point]] $newPoints =
  269.             [System.Collections.Generic.List[Point]]::New()
  270.  
  271.         $deltaX = $endX - $startX
  272.         $deltaY = $endY - $startY
  273.         $error = 0
  274.         $deltaError = [Math]::Abs($deltaY / $deltaX)
  275.  
  276.         $y = $startY
  277.         $yIncr = 1;
  278.         $xIncr = 1;
  279.         $xCount = [Math]::Abs($endX - $startX)
  280.  
  281.         if($endY -lt $startY) { $yIncr = -1 }
  282.         if($endX -lt $startX) { $xIncr = -1 }
  283.  
  284.         $x = $startX
  285.         while($xCount -gt 0)
  286.         {
  287.             $newPoints.Add( ([Point]::New($x, $y, $zIndex)) )
  288.             $error =  $error + $deltaError
  289.             if($error -gt 0.5)
  290.             {
  291.                 $y += $yIncr
  292.                 $error--
  293.             }
  294.  
  295.             $xCount--
  296.             $x +=$xIncr
  297.         }
  298.  
  299.         return $newPoints
  300.     }
  301. }
  302.  
  303. ## call.
  304. enum CharacterType
  305. {
  306.     Dot = 0
  307.     Star = 1
  308. }
  309.  
  310.  
  311. ## Now play with the objects
  312. cls
  313.  
  314. ## The GraphicObject class has three static factory methods to generate
  315. ## interesting versions of itself. Store these so that we can cycle through
  316. ## them with the TAB key.
  317. $objects = "Saddle", "PowerShell", "Box", "Helix"
  318. $currentObject = 0
  319. $object = [GraphicObject]::($objects[$currentObject]).Invoke()
  320.  
  321.  
  322. $startTime = Get-Date
  323. $frames = 0
  324.  
  325. $xRot = 1
  326. $yRot = 1
  327. $zRot = 2
  328.  
  329. $shouldExit = $false
  330. while(-not $shouldExit)
  331. {
  332.     if([Console]::KeyAvailable)
  333.     {
  334.         $key = [Console]::ReadKey()
  335.  
  336.         switch($key.Key)
  337.         {
  338.             ## Change rotation speed
  339.             RightArrow { $yRot++ }
  340.             LeftArrow { $yRot-- }
  341.             DownArrow { $xRot-- }
  342.             UpArrow { $xRot++ }
  343.             SpaceBar {
  344.                 $xRot, $yRot, $zRot = 1..3 | % { Get-Random -Min -5 -Max 5 }
  345.             }
  346.             P { $xRot, $yRot, $zRot = 0, 0, 0 }
  347.  
  348.             ## Change drawing characters
  349.             D8 { $object.CharacterType = "Star" }
  350.             OemPeriod { $object.CharacterType = "Dot" }
  351.  
  352.             ## Change objects
  353.             Tab {
  354.                 $currentObject = ($currentObject + 1) % $objects.Length
  355.                 $object = [GraphicObject]::($objects[$currentObject]).Invoke()
  356.             }
  357.  
  358.             ## Quit
  359.             Q { $shouldExit = $true }
  360.  
  361.             default { if($PSBoundParameters["Debug"]) { $host.EnterNestedPrompt() } }
  362.         }
  363.     }
  364.  
  365.     $object.Draw()
  366.     $object.Rotate($xRot, $yRot, $zRot)
  367.     $frames++
  368. }
  369.  
  370. $endTime = Get-Date
  371. if($PSBoundParameters['Debug']) { "`r`nFrame rate: {0} FPS" -f ($frames / ($endTime - $startTime).TotalSeconds) }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement