mirror of
https://github.com/Smaug123/ray-tracing-fsharp
synced 2025-10-09 22:08:39 +00:00
Writer
This commit is contained in:
48
RayTracing.App/Program.fs
Normal file
48
RayTracing.App/Program.fs
Normal file
@@ -0,0 +1,48 @@
|
||||
namespace RayTracing.App
|
||||
|
||||
open RayTracing
|
||||
open System.IO.Abstractions
|
||||
open Spectre.Console
|
||||
|
||||
module Program =
|
||||
|
||||
type ProgressTask with
|
||||
member this.Increment (prog : float<progress>) = this.Increment (prog / 1.0<progress>)
|
||||
|
||||
let go (ctx : ProgressContext) =
|
||||
let fs = FileSystem()
|
||||
let output =
|
||||
fs.Path.GetTempFileName ()
|
||||
|> fun s -> fs.Path.ChangeExtension (s, ".ppm")
|
||||
|> fs.FileInfo.FromFileName
|
||||
|
||||
let task = ctx.AddTask "[green]Generating image[/]"
|
||||
let maxProgress, image = SampleImages.gradient task.Increment
|
||||
task.MaxValue <- maxProgress / 1.0<progress>
|
||||
|
||||
let image = image |> Async.RunSynchronously
|
||||
|
||||
let outputTask = ctx.AddTask "[green]Writing image[/]"
|
||||
let maxProgress, writer = ImageOutput.toPpm outputTask.Increment image output
|
||||
outputTask.MaxValue <- maxProgress / 1.0<progress>
|
||||
|
||||
writer |> Async.RunSynchronously
|
||||
|
||||
printfn "%s" output.FullName
|
||||
|
||||
[<EntryPoint>]
|
||||
let main (_ : string []) : int =
|
||||
let prog =
|
||||
AnsiConsole.Progress()
|
||||
.Columns(
|
||||
TaskDescriptionColumn(),
|
||||
ProgressBarColumn(),
|
||||
PercentageColumn(),
|
||||
RemainingTimeColumn(),
|
||||
SpinnerColumn()
|
||||
)
|
||||
prog.HideCompleted <- false
|
||||
prog.AutoClear <- false
|
||||
|
||||
prog.Start go
|
||||
0
|
20
RayTracing.App/RayTracing.App.fsproj
Normal file
20
RayTracing.App/RayTracing.App.fsproj
Normal file
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RayTracing\RayTracing.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Spectre.Console" Version="0.38.1-preview.0.17" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@@ -1,10 +1,49 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RayTracing", "RayTracing\RayTracing.fsproj", "{865D12F3-3694-4E1B-A1E2-B5867B48F58C}"
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.6.30114.105
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RayTracing", "RayTracing\RayTracing.fsproj", "{AE2CD8DA-FFA5-49BE-B5C9-1A96A3928325}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "TestRayTracing", "TestRayTracing\TestRayTracing.fsproj", "{3C554C00-650A-4DEA-B37F-F0831D21CF37}"
|
||||
EndProject
|
||||
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "RayTracing.App", "RayTracing.App\RayTracing.App.fsproj", "{94792D42-3D22-4FAE-A15B-B89AAF6DB732}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3C554C00-650A-4DEA-B37F-F0831D21CF37}.Release|x86.Build.0 = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|x64.Build.0 = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{94792D42-3D22-4FAE-A15B-B89AAF6DB732}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
24
RayTracing/Domain.fs
Normal file
24
RayTracing/Domain.fs
Normal file
@@ -0,0 +1,24 @@
|
||||
namespace RayTracing
|
||||
|
||||
[<Measure>]
|
||||
type progress
|
||||
|
||||
[<Struct>]
|
||||
type Pixel =
|
||||
{
|
||||
Red : byte
|
||||
Green : byte
|
||||
Blue : byte
|
||||
}
|
||||
|
||||
type Image =
|
||||
| Image of Pixel [] []
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module Image =
|
||||
let rowCount (Image i) : int =
|
||||
i.Length
|
||||
|
||||
let colCount (Image i) : int =
|
||||
i.[0].Length
|
||||
|
37
RayTracing/ImageOutput.fs
Normal file
37
RayTracing/ImageOutput.fs
Normal file
@@ -0,0 +1,37 @@
|
||||
namespace RayTracing
|
||||
|
||||
open System.IO
|
||||
open System.IO.Abstractions
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module PixelOutput =
|
||||
let toPpm (pixel : Pixel) : string =
|
||||
sprintf "%i %i %i" pixel.Red pixel.Green pixel.Blue
|
||||
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module ImageOutput =
|
||||
|
||||
let toPpm
|
||||
(progressIncrement : float<progress> -> unit)
|
||||
(image : Image)
|
||||
(file : IFileInfo)
|
||||
: float<progress> * Async<unit>
|
||||
=
|
||||
(float (Image.rowCount image)) * 1.0<progress>,
|
||||
async {
|
||||
use outputStream = file.OpenWrite ()
|
||||
use writer = new StreamWriter (outputStream)
|
||||
writer.Write "P3\n"
|
||||
writer.Write (sprintf "%i %i\n" (Image.colCount image) (Image.rowCount image))
|
||||
writer.Write "255\n"
|
||||
|
||||
match image with
|
||||
| Image arr ->
|
||||
for row in arr do
|
||||
for pixel in row do
|
||||
writer.Write (PixelOutput.toPpm pixel)
|
||||
writer.Write " "
|
||||
writer.Write "\n"
|
||||
progressIncrement 1.0<progress>
|
||||
}
|
@@ -1,5 +0,0 @@
|
||||
namespace RayTracing
|
||||
|
||||
module Say =
|
||||
let hello name =
|
||||
printfn "Hello %s" name
|
@@ -5,7 +5,13 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Library.fs"/>
|
||||
<Compile Include="Domain.fs" />
|
||||
<Compile Include="ImageOutput.fs" />
|
||||
<Compile Include="SampleImages.fs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Abstractions" Version="13.2.28" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
22
RayTracing/SampleImages.fs
Normal file
22
RayTracing/SampleImages.fs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace RayTracing
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module SampleImages =
|
||||
|
||||
let gradient (progressIncrement : float<progress> -> unit) : float<progress> * Image Async =
|
||||
let pixelAt i j =
|
||||
{
|
||||
Red = (byte i)
|
||||
Green = (byte j)
|
||||
Blue = 64uy
|
||||
}
|
||||
|
||||
256.0<progress>,
|
||||
async {
|
||||
return Array.init 256 (fun i ->
|
||||
let output = Array.init 256 (pixelAt i)
|
||||
progressIncrement 1.0<progress>
|
||||
output
|
||||
)
|
||||
|> Image
|
||||
}
|
5
TestRayTracing/PpmOutputExample.txt
Normal file
5
TestRayTracing/PpmOutputExample.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
P3
|
||||
3 2
|
||||
255
|
||||
255 0 0 0 255 0 0 0 255
|
||||
255 255 0 255 255 255 0 0 0
|
36
TestRayTracing/TestPpmOutput.fs
Normal file
36
TestRayTracing/TestPpmOutput.fs
Normal file
@@ -0,0 +1,36 @@
|
||||
namespace TestRayTracing
|
||||
|
||||
open RayTracing
|
||||
open NUnit.Framework
|
||||
open FsUnitTyped
|
||||
open System.IO.Abstractions.TestingHelpers
|
||||
|
||||
[<TestFixture>]
|
||||
module TestRayTracing =
|
||||
|
||||
[<Test>]
|
||||
let ``Wikipedia example of PPM output`` () =
|
||||
let fs = MockFileSystem ()
|
||||
let expected = TestUtils.getEmbeddedResource "PpmOutputExample.txt"
|
||||
|
||||
let image =
|
||||
[|
|
||||
[|
|
||||
{ Red = 255uy ; Blue = 0uy ; Green = 0uy }
|
||||
{ Red = 0uy ; Blue = 0uy ; Green = 255uy }
|
||||
{ Red = 0uy ; Blue = 255uy ; Green = 0uy }
|
||||
|]
|
||||
[|
|
||||
{ Red = 255uy ; Blue = 0uy ; Green = 255uy }
|
||||
{ Red = 255uy ; Blue = 255uy ; Green = 255uy }
|
||||
{ Red = 0uy ; Blue = 0uy ; Green = 0uy }
|
||||
|]
|
||||
|]
|
||||
|> Image
|
||||
|
||||
let outputFile = fs.Path.GetTempFileName () |> fs.FileInfo.FromFileName
|
||||
let _, writer = ImageOutput.toPpm ignore image outputFile
|
||||
writer |> Async.RunSynchronously
|
||||
|
||||
fs.File.ReadAllText outputFile.FullName
|
||||
|> shouldEqual expected
|
25
TestRayTracing/TestRayTracing.fsproj
Normal file
25
TestRayTracing/TestRayTracing.fsproj
Normal file
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="TestUtils.fs" />
|
||||
<Compile Include="TestPpmOutput.fs" />
|
||||
<EmbeddedResource Include="PpmOutputExample.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FsUnit" Version="4.0.4" />
|
||||
<PackageReference Include="NUnit" Version="3.13.1" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.0.0-beta.1" />
|
||||
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="13.2.28" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RayTracing\RayTracing.fsproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
20
TestRayTracing/TestUtils.fs
Normal file
20
TestRayTracing/TestUtils.fs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace TestRayTracing
|
||||
|
||||
open System.IO
|
||||
open System.Reflection
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
module TestUtils =
|
||||
|
||||
type Dummy = class end
|
||||
|
||||
let getEmbeddedResource (filename : string) : string =
|
||||
let filename =
|
||||
Assembly.GetAssembly(typeof<Dummy>).GetManifestResourceNames ()
|
||||
|> Seq.filter (fun s -> s.EndsWith filename)
|
||||
|> Seq.exactlyOne
|
||||
use stream =
|
||||
Assembly.GetAssembly(typeof<Dummy>).GetManifestResourceStream filename
|
||||
|
||||
use reader = new StreamReader (stream)
|
||||
reader.ReadToEnd().Replace("\r\n", "\n")
|
Reference in New Issue
Block a user