├── .gitattributes
├── .gitignore
├── LICENSE.md
├── README.md
├── Triangle.NET.md
├── Triangle.dll
├── Trigrad.sln
├── Trigrad
├── ColorGraders
│ ├── AverageGrader.cs
│ ├── BarycentricGrader.cs
│ ├── BlindDitherGrader.cs
│ ├── DitherGrader.cs
│ ├── FillGrader.cs
│ ├── IGrader.cs
│ ├── TopGrader.cs
│ └── TriGrader.cs
├── DataTypes
│ ├── Barycentric.cs
│ ├── Calculation.cs
│ ├── Compression
│ │ ├── FileCompression.cs
│ │ ├── FileDecompression.cs
│ │ └── TrigradCompressed.cs
│ ├── DrawPoint.cs
│ ├── FrequencyTable.cs
│ ├── Sample.cs
│ ├── SampleTri.cs
│ ├── TrigradDecompressed.cs
│ └── TrigradOptions.cs
├── Extensions.cs
├── Filters
│ ├── AreaFilter.cs
│ ├── AverageFilter.cs
│ ├── Filter.cs
│ ├── GridFilter.cs
│ ├── MedianFilter.cs
│ └── NoiseFilter.cs
├── GPUT.c
├── GPUT.cs
├── MeshBuilder.cs
├── Properties
│ └── AssemblyInfo.cs
├── Renderers
│ ├── CenterFill.cs
│ ├── GradeFill.cs
│ ├── IFill.cs
│ └── ShapeFill.cs
├── TriangleRasterisation.cs
├── Trigrad.csproj
├── TrigradCompressor.cs
├── TrigradDecompressor.cs
├── TrigradOptimiser.cs
└── packages.config
└── TrigradTesting
├── App.config
├── Program.cs
├── Properties
└── AssemblyInfo.cs
├── TrigradTesting.csproj
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.sln.docstates
8 |
9 | # Build results
10 | [Dd]ebug/
11 | [Dd]ebugPublic/
12 | [Rr]elease/
13 | x64/
14 | build/
15 | bld/
16 | [Bb]in/
17 | [Oo]bj/
18 |
19 | # Roslyn cache directories
20 | *.ide/
21 |
22 | # MSTest test Results
23 | [Tt]est[Rr]esult*/
24 | [Bb]uild[Ll]og.*
25 |
26 | #NUNIT
27 | *.VisualState.xml
28 | TestResult.xml
29 |
30 | # Build Results of an ATL Project
31 | [Dd]ebugPS/
32 | [Rr]eleasePS/
33 | dlldata.c
34 |
35 | *_i.c
36 | *_p.c
37 | *_i.h
38 | *.ilk
39 | *.meta
40 | *.obj
41 | *.pch
42 | *.pdb
43 | *.pgc
44 | *.pgd
45 | *.rsp
46 | *.sbr
47 | *.tlb
48 | *.tli
49 | *.tlh
50 | *.tmp
51 | *.tmp_proj
52 | *.log
53 | *.vspscc
54 | *.vssscc
55 | .builds
56 | *.pidb
57 | *.svclog
58 | *.scc
59 |
60 | # Chutzpah Test files
61 | _Chutzpah*
62 |
63 | # Visual C++ cache files
64 | ipch/
65 | *.aps
66 | *.ncb
67 | *.opensdf
68 | *.sdf
69 | *.cachefile
70 |
71 | # Visual Studio profiler
72 | *.psess
73 | *.vsp
74 | *.vspx
75 |
76 | # TFS 2012 Local Workspace
77 | $tf/
78 |
79 | # Guidance Automation Toolkit
80 | *.gpState
81 |
82 | # ReSharper is a .NET coding add-in
83 | _ReSharper*/
84 | *.[Rr]e[Ss]harper
85 | *.DotSettings.user
86 |
87 | # JustCode is a .NET coding addin-in
88 | .JustCode
89 |
90 | # TeamCity is a build add-in
91 | _TeamCity*
92 |
93 | # DotCover is a Code Coverage Tool
94 | *.dotCover
95 |
96 | # NCrunch
97 | _NCrunch_*
98 | .*crunch*.local.xml
99 |
100 | # MightyMoose
101 | *.mm.*
102 | AutoTest.Net/
103 |
104 | # Web workbench (sass)
105 | .sass-cache/
106 |
107 | # Installshield output folder
108 | [Ee]xpress/
109 |
110 | # DocProject is a documentation generator add-in
111 | DocProject/buildhelp/
112 | DocProject/Help/*.HxT
113 | DocProject/Help/*.HxC
114 | DocProject/Help/*.hhc
115 | DocProject/Help/*.hhk
116 | DocProject/Help/*.hhp
117 | DocProject/Help/Html2
118 | DocProject/Help/html
119 |
120 | # Click-Once directory
121 | publish/
122 |
123 | # Publish Web Output
124 | *.[Pp]ublish.xml
125 | *.azurePubxml
126 | ## TODO: Comment the next line if you want to checkin your
127 | ## web deploy settings but do note that will include unencrypted
128 | ## passwords
129 | #*.pubxml
130 |
131 | # NuGet Packages Directory
132 | packages/*
133 | ## TODO: If the tool you use requires repositories.config
134 | ## uncomment the next line
135 | #!packages/repositories.config
136 |
137 | # Enable "build/" folder in the NuGet Packages folder since
138 | # NuGet packages use it for MSBuild targets.
139 | # This line needs to be after the ignore of the build folder
140 | # (and the packages folder if the line above has been uncommented)
141 | !packages/build/
142 |
143 | # Windows Azure Build Output
144 | csx/
145 | *.build.csdef
146 |
147 | # Windows Store app package directory
148 | AppPackages/
149 |
150 | # Others
151 | sql/
152 | *.Cache
153 | ClientBin/
154 | [Ss]tyle[Cc]op.*
155 | ~$*
156 | *~
157 | *.dbmdl
158 | *.dbproj.schemaview
159 | *.pfx
160 | *.publishsettings
161 | node_modules/
162 |
163 | # RIA/Silverlight projects
164 | Generated_Code/
165 |
166 | # Backup & report files from converting an old project file
167 | # to a newer Visual Studio version. Backup files are not needed,
168 | # because we have git ;-)
169 | _UpgradeReport_Files/
170 | Backup*/
171 | UpgradeLog*.XML
172 | UpgradeLog*.htm
173 |
174 | # SQL Server files
175 | *.mdf
176 | *.ldf
177 |
178 | # Business Intelligence projects
179 | *.rdl.data
180 | *.bim.layout
181 | *.bim_*.settings
182 |
183 | # Microsoft Fakes
184 | FakesAssemblies/
185 |
186 | # LightSwitch generated files
187 | GeneratedArtifacts/
188 | _Pvt_Extensions/
189 | ModelManifest.xml
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 ruarai
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Trigrad
2 | Triangle Gradient Image Compression
3 | See http://ruarai.github.io/Trigrad/ for a rundown of the algorithm.
4 |
5 | ## Requirements
6 | ### Triangle
7 | Trigrad uses the Triangle.NET library for generating the triangle mesh. The DLL file has been included under the MIT license.
8 | https://triangle.codeplex.com/license
9 | ### AForge.NET
10 | Trigrad uses the AForge.NET library for edge detection. AForge.NET can be downloaded automatically through NuGet.
11 |
--------------------------------------------------------------------------------
/Triangle.NET.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Christian Woltering
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Triangle.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ruarai/Trigrad/e07ada125cada6e930c910fd9db4bd2d8a23b6ff/Triangle.dll
--------------------------------------------------------------------------------
/Trigrad.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trigrad", "Trigrad\Trigrad.csproj", "{3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrigradTesting", "TrigradTesting\TrigradTesting.csproj", "{E984EACE-46E7-485E-8A1C-FCB5884698F0}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{14766101-0358-464C-AC12-5539CAB2D697}"
11 | ProjectSection(SolutionItems) = preProject
12 | LICENSE.md = LICENSE.md
13 | Triangle.NET.md = Triangle.NET.md
14 | EndProjectSection
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Debug|x64 = Debug|x64
20 | Release|Any CPU = Release|Any CPU
21 | Release|x64 = Release|x64
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Debug|x64.ActiveCfg = Debug|Any CPU
27 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Debug|x64.Build.0 = Debug|Any CPU
28 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}.Release|x64.ActiveCfg = Release|Any CPU
31 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
32 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
33 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Debug|x64.ActiveCfg = Debug|x64
34 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Debug|x64.Build.0 = Debug|x64
35 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
36 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Release|Any CPU.Build.0 = Release|Any CPU
37 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Release|x64.ActiveCfg = Release|x64
38 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}.Release|x64.Build.0 = Release|x64
39 | EndGlobalSection
40 | GlobalSection(SolutionProperties) = preSolution
41 | HideSolutionNode = FALSE
42 | EndGlobalSection
43 | EndGlobal
44 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/AverageGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills the triangle with an average of the three vertice samples.
13 | public class AverageGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | int R = u.Color.R + v.Color.R + w.Color.R;
19 | int G = u.Color.G + v.Color.G + w.Color.G;
20 | int B = u.Color.B + v.Color.B + w.Color.B;
21 |
22 | return new Pixel((byte) (R/3), (byte) (G/3), (byte) (B/3));
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/BarycentricGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills a triangle with a triangle gradient.
13 | public class BarycentricGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | byte R = (byte)(u.Color.R * p.BarycentricCoordinates.U + v.Color.R * p.BarycentricCoordinates.V + w.Color.R * p.BarycentricCoordinates.W);
19 | byte G = (byte)(u.Color.G * p.BarycentricCoordinates.U + v.Color.G * p.BarycentricCoordinates.V + w.Color.G * p.BarycentricCoordinates.W);
20 | byte B = (byte)(u.Color.B * p.BarycentricCoordinates.U + v.Color.B * p.BarycentricCoordinates.V + w.Color.B * p.BarycentricCoordinates.W);
21 |
22 | return new Pixel(R, G, B);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/BlindDitherGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills a triangle with a dithering that ignores the barycentric coordinates.
13 | public class BlindDitherGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | int val = (p.Point.X + p.Point.Y) % 3;
19 | if (val == 0)
20 | return u.Color;
21 | if (val == 1)
22 | return v.Color;
23 | return w.Color;
24 |
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/DitherGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills a triangle with a dithered output.
13 | public class DitherGrader : IGrader
14 | {
15 | private static Random r = new Random();
16 |
17 | /// Produces a color from the specified coordinates and colors.
18 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
19 | {
20 | if (p.BarycentricCoordinates.U >= 0.9)
21 | return u.Color;
22 | if (p.BarycentricCoordinates.V >= 0.9)
23 | return v.Color;
24 | if (p.BarycentricCoordinates.W >= 0.9)
25 | return w.Color;
26 |
27 |
28 | int valU = (int)(p.Point.X + p.Point.Y + p.BarycentricCoordinates.U + r.Next(0, 4)) % 4;
29 | int valV = (int)(p.Point.X + p.Point.Y + p.BarycentricCoordinates.V + r.Next(0, 4)) % 4;
30 | int valW = (int)(p.Point.X + p.Point.Y + p.BarycentricCoordinates.W + r.Next(0, 4)) % 4;
31 |
32 | if (p.BarycentricCoordinates.U >= p.BarycentricCoordinates.V && p.BarycentricCoordinates.U >= p.BarycentricCoordinates.W)
33 | return ditherFurther(u.Color, v.Color, w.Color, valU);
34 | if (p.BarycentricCoordinates.V >= p.BarycentricCoordinates.W)
35 | return ditherFurther(v.Color, w.Color, w.Color, valV);
36 |
37 | return ditherFurther(w.Color, v.Color, u.Color, valW);
38 | }
39 | private static Pixel ditherFurther(Pixel a, Pixel b, Pixel c, int val)
40 | {
41 | switch (val)
42 | {
43 | case 0:
44 | return a;
45 | case 1:
46 | return b;
47 | case 2:
48 | return a;
49 | case 3:
50 | return c;
51 | default:
52 | return a;
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/FillGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills a triangle with each point's nearest color.
13 | public class FillGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | if (p.BarycentricCoordinates.U >= p.BarycentricCoordinates.V && p.BarycentricCoordinates.U >= p.BarycentricCoordinates.W)
19 | return u.Color;
20 | if (p.BarycentricCoordinates.V >= p.BarycentricCoordinates.W)
21 | return v.Color;
22 | return w.Color;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/IGrader.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 | using PixelMapSharp;
3 | using Trigrad.DataTypes;
4 |
5 | namespace Trigrad.ColorGraders
6 | {
7 | /// Interface for producing color graders.
8 | public interface IGrader
9 | {
10 | /// Base method for color grading.
11 | Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/TopGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills the triangle with the highest valued vertice sample.
13 | public class TopGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | int uSum = u.Color.R + u.Color.G + u.Color.B;
19 | int vSum = v.Color.R + v.Color.G + v.Color.B;
20 | int wSum = w.Color.R + w.Color.G + w.Color.B;
21 |
22 | if (uSum > vSum && uSum > wSum)
23 | {
24 | return u.Color;
25 | }
26 | else if (vSum > wSum)
27 | return v.Color;
28 | else
29 | return w.Color;
30 |
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Trigrad/ColorGraders/TriGrader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.ColorGraders
11 | {
12 | /// Color grader that fills the triangle with the first sample color.
13 | public class TriGrader : IGrader
14 | {
15 | /// Produces a color from the specified coordinates and colors.
16 | public Pixel Grade(Sample u, Sample v, Sample w, DrawPoint p)
17 | {
18 | return u.Color;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Barycentric.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace Trigrad.DataTypes
4 | {
5 | public static class Barycentric
6 | {
7 | public static BarycentricCoordinates GetCoordinates(Point Pp, Point Pa, Point Pb, Point Pc)
8 | {
9 | double[] v0 = { Pb.X - Pa.X, Pb.Y - Pa.Y };
10 | double[] v1 = { Pc.X - Pa.X, Pc.Y - Pa.Y };
11 | double[] v2 = { Pp.X - Pa.X, Pp.Y - Pa.Y };
12 | double d00 = dotProduct(v0, v0);
13 | double d01 = dotProduct(v0, v1);
14 | double d11 = dotProduct(v1, v1);
15 | double d20 = dotProduct(v2, v0);
16 | double d21 = dotProduct(v2, v1);
17 | double denom = d00 * d11 - d01 * d01;
18 | double v = ((d11 * d20 - d01 * d21) / denom);
19 | double w = ((d00 * d21 - d01 * d20) / denom);
20 | double u = (1.0f - v - w);
21 |
22 | return new BarycentricCoordinates(u, v, w);
23 | }
24 |
25 | public static bool ValidCoords(BarycentricCoordinates coords)
26 | {
27 | return coords.U >= 0 && coords.V >= 0 && coords.W >= 0;
28 | }
29 |
30 | private static double dotProduct(double[] vec1, double[] vec2)
31 | {
32 | return vec1[0]*vec2[0] + vec1[1]*vec2[1];
33 | }
34 | }
35 | public struct BarycentricCoordinates
36 | {
37 | public BarycentricCoordinates(double u, double v, double w)
38 | {
39 | U = u;
40 | V = v;
41 | W = w;
42 | }
43 | public double U;
44 | public double V;
45 | public double W;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Calculation.cs:
--------------------------------------------------------------------------------
1 | using System.Drawing;
2 |
3 | namespace Trigrad.DataTypes
4 | {
5 | public class Calculation
6 | {
7 | public Point P;
8 |
9 | public Point A;
10 | public Point B;
11 | public Point C;
12 |
13 | public BarycentricCoordinates Coords;
14 |
15 | public SampleTri Tri;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Compression/FileCompression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using ICSharpCode.SharpZipLib.BZip2;
9 |
10 | namespace Trigrad.DataTypes.Compression
11 | {
12 | public partial class TrigradCompressed
13 | {
14 | /// Saves a TrigradCompressed image to a stream.
15 | public void Save(Stream s)
16 | {
17 | using (BZip2OutputStream zipper = new BZip2OutputStream(s))
18 | using (BinaryWriter writer = new BinaryWriter(zipper))
19 | {
20 | writer.Write((ushort)Width);
21 | writer.Write((ushort)Height);
22 |
23 | var samples = Mesh.SelectMany(t => t.Samples).Distinct().ToList();
24 |
25 | writer.Write((uint)samples.Count);
26 |
27 | var sorted = samples.OrderBy(kvp => kvp.Point.X * ushort.MaxValue + kvp.Point.Y).ToList();
28 | foreach (var sample in sorted)
29 | writer.Write((ushort)sample.Point.X);
30 | foreach (var sample in sorted)
31 | writer.Write((ushort)sample.Point.Y);
32 |
33 | foreach (var sample in sorted)
34 | writer.Write(sample.Color.R);
35 | foreach (var sample in sorted)
36 | writer.Write(sample.Color.G);
37 | foreach (var sample in sorted)
38 | writer.Write(sample.Color.B);
39 |
40 | writer.Write((uint)Mesh.Count);
41 |
42 | foreach (var tri in Mesh)
43 | writer.Write(sorted.FindIndex(p => p.Point == tri.U.Point));
44 | foreach (var tri in Mesh)
45 | writer.Write(sorted.FindIndex(p => p.Point == tri.V.Point));
46 | foreach (var tri in Mesh)
47 | writer.Write(sorted.FindIndex(p => p.Point == tri.W.Point));
48 |
49 |
50 | writer.Flush();
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Compression/FileDecompression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using ICSharpCode.SharpZipLib.BZip2;
9 | using PixelMapSharp;
10 |
11 | namespace Trigrad.DataTypes.Compression
12 | {
13 | public partial class TrigradCompressed
14 | {
15 | /// Loads a TrigradCompressed image from a stream.
16 | public TrigradCompressed(Stream s)
17 | {
18 | using (BZip2InputStream dezipper = new BZip2InputStream(s))
19 | using (BinaryReader reader = new BinaryReader(dezipper))
20 | {
21 | Width = reader.ReadUInt16();
22 | Height = reader.ReadUInt16();
23 |
24 | uint count = reader.ReadUInt32();
25 |
26 | Point[] points = new Point[count];
27 |
28 | for (int i = 0; i < count; i++)
29 | points[i].X = reader.ReadUInt16();
30 | for (int i = 0; i < count; i++)
31 | points[i].Y = reader.ReadUInt16();
32 |
33 | ColorStruct[] colors = new ColorStruct[count];
34 |
35 | for (int i = 0; i < count; i++)
36 | colors[i].R = reader.ReadByte();
37 | for (int i = 0; i < count; i++)
38 | colors[i].G = reader.ReadByte();
39 | for (int i = 0; i < count; i++)
40 | colors[i].B = reader.ReadByte();
41 |
42 | for (int i = 0; i < count; i++)
43 | {
44 | SampleTable.Add(points[i],colors[i].Color);
45 | }
46 |
47 | uint meshCount = reader.ReadUInt32();
48 |
49 | SampleTri[] tris = new SampleTri[meshCount];
50 |
51 |
52 | for (int i = 0; i < meshCount; i++)
53 | tris[i] = new SampleTri();
54 |
55 | for (int i = 0; i < meshCount; i++)
56 | tris[i].U = new Sample(points[reader.ReadInt32()], new Pixel(Color.Black));
57 |
58 | for (int i = 0; i < meshCount; i++)
59 | tris[i].V = new Sample(points[reader.ReadInt32()], new Pixel(Color.Black));
60 |
61 | for (int i = 0; i < meshCount; i++)
62 | tris[i].W = new Sample(points[reader.ReadInt32()], new Pixel(Color.Black));
63 |
64 | foreach (var tri in tris)
65 | {
66 | tri.U.Color = SampleTable[tri.U.Point];
67 | tri.V.Color = SampleTable[tri.V.Point];
68 | tri.W.Color = SampleTable[tri.W.Point];
69 | }
70 |
71 | Mesh = tris.ToList();
72 | }
73 | }
74 |
75 | internal struct ColorStruct
76 | {
77 | public byte R;
78 | public byte G;
79 | public byte B;
80 |
81 | public Pixel Color { get { return new Pixel(R, G, B); } }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Compression/TrigradCompressed.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using System.IO;
4 | using System.IO.Compression;
5 | using System.Linq;
6 | using System.Security.Cryptography.X509Certificates;
7 | using ICSharpCode.SharpZipLib.BZip2;
8 | using PixelMapSharp;
9 | using TriangleNet;
10 |
11 | namespace Trigrad.DataTypes.Compression
12 | {
13 | /// The TrigradCompressed form of a bitmap.
14 | public partial class TrigradCompressed
15 | {
16 | /// Constructs a TrigradCompressed without any initial data.
17 | public TrigradCompressed()
18 | {
19 |
20 | }
21 | /// A dictionary of sampled points to their corresponding colors.
22 | public Dictionary SampleTable = new Dictionary();
23 |
24 | public List Mesh = new List();
25 | /// The width of the bitmap.
26 | public int Width;
27 | /// The height of the bitmap.
28 | public int Height;
29 | /// Provides a visualisation of the SampleTable.
30 | public PixelMap DebugVisualisation()
31 | {
32 | PixelMap map = new PixelMap(Width, Height);
33 |
34 | for (int x = 0; x < Width; x++)
35 | {
36 | for (int y = 0; y < Height; y++)
37 | {
38 | map[x, y] = new Pixel(10, 10, 10);
39 | }
40 | }
41 |
42 | foreach (var value in SampleTable)
43 | {
44 | Point p = value.Key;
45 |
46 | map[p]= value.Value;
47 | }
48 | return map;
49 | }
50 |
51 | public PixelMap MeshOutput(PixelMap original)
52 | {
53 | return Mesh.DrawMesh(Width, Height);
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Trigrad/DataTypes/DrawPoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Trigrad.DataTypes
9 | {
10 | public class DrawPoint
11 | {
12 | public DrawPoint(BarycentricCoordinates coords, Point p)
13 | {
14 | BarycentricCoordinates = coords;
15 | Point = p;
16 | }
17 |
18 | public BarycentricCoordinates BarycentricCoordinates;
19 | public Point Point;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/FrequencyTable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Drawing;
3 | using PixelMapSharp;
4 |
5 | namespace Trigrad.DataTypes
6 | {
7 | /// A frequency table defining how likely a sample will be formed during a TrigradCompression.
8 | public class FrequencyTable
9 | {
10 | /// The underlying 2D frequency table, with values lying from 0 to 1.
11 | public double[,] Table;
12 |
13 | /// Constructs a frequency table using sobel edge detection.
14 | public FrequencyTable(PixelMap pixelmap,double power = 1.7)
15 | {
16 | Table = sobelFilter(pixelmap);
17 |
18 | for (int x = 0; x < Table.GetLength(0); x++)
19 | {
20 | for (int y = 0; y < Table.GetLength(1); y++)
21 | {
22 | Table[x, y] = Math.Pow(Table[x, y], power);
23 | }
24 | }
25 | }
26 |
27 | /// The sum of the FrequencyTable.
28 | public double Sum
29 | {
30 | get
31 | {
32 | double chanceSum = 0;
33 | for (int x = 0; x < Table.GetLength(0); x++)
34 | {
35 | for (int y = 0; y < Table.GetLength(1); y++)
36 | {
37 | chanceSum += Table[x, y];
38 | }
39 | }
40 | return chanceSum;
41 | }
42 | }
43 |
44 | /// Constructs a frequency table using a specified table of values.
45 | public FrequencyTable(double[,] table)
46 | {
47 | Table = table;
48 | }
49 |
50 | private double[,] sobelFilter(PixelMap map)
51 | {
52 | double[,] output = new double[map.Width, map.Height];
53 |
54 | double[,] kernelX =
55 | {
56 | {-1,0,1 },
57 | {-2,0,2 },
58 | {-1,0,1 }
59 | };
60 |
61 | double[,] kernelY =
62 | {
63 | {-1,-2,-1},
64 | {0,0,0},
65 | {1,2,1}
66 | };
67 |
68 |
69 | double[,] xFiltered = sobelPass(map, kernelX);
70 | double[,] yFiltered = sobelPass(map, kernelY);
71 |
72 | for (int x = 0; x < map.Width; x++)
73 | {
74 | for (int y = 0; y < map.Height; y++)
75 | {
76 | double xVal = xFiltered[x, y];
77 | double yVal = yFiltered[x, y];
78 |
79 | output[x, y] = Math.Sqrt(xVal * xVal + yVal * yVal);
80 | }
81 | }
82 |
83 | return output;
84 | }
85 |
86 | private double[,] sobelPass(PixelMap map, double[,] kernel)
87 | {
88 | double[,] output = new double[map.Width, map.Height];
89 |
90 | for (int x = 0; x < map.Width; x++)
91 | {
92 | for (int y = 0; y < map.Height; y++)
93 | {
94 | double sum = 0;
95 | for (int u = 0; u < 3; u++)
96 | {
97 | for (int v = 0; v < 3; v++)
98 | {
99 | Point samplePoint = new Point(x - 1 + u, y - 1 + v);
100 |
101 | if (map.Inside(samplePoint))
102 | {
103 | double kVal = kernel[u, v];
104 | double imgVal = map[samplePoint].Lightness;
105 |
106 | sum += kVal * imgVal;
107 | }
108 | else
109 | {
110 | sum += 0.5;
111 | }
112 | }
113 | }
114 | output[x, y] = sum;
115 | }
116 | }
117 | return output;
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/Sample.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 |
9 | namespace Trigrad.DataTypes
10 | {
11 |
12 | public class Sample
13 | {
14 | public Sample(Point p, Pixel c)
15 | {
16 | Point = p;
17 | Color = c;
18 | }
19 |
20 | public Point Point;
21 | public Pixel Color;
22 | public Pixel NewColor;
23 |
24 | public bool Optimised = true;
25 |
26 | public List Triangles = new List();
27 |
28 | public IEnumerable Samples
29 | {
30 | get { return Triangles.SelectMany(t => t.Samples); }
31 | }
32 |
33 | public List Points { get { return Triangles.SelectMany(t => t.Points).ToList(); } }
34 |
35 | public List DepthNeighbours(int depth)
36 | {
37 | return depthSelect(this, depth);
38 | }
39 |
40 | private static List depthSelect(Sample sample, int depth, List parents = null)
41 | {
42 | if (depth <= 0)
43 | return new List();
44 |
45 | List samples = new List();
46 | foreach (var child in sample.Samples)
47 | {
48 | if (parents != null && parents.Contains(child))
49 | continue;
50 |
51 | samples.Add(child);
52 | var result = depthSelect(child, depth - 1, samples);
53 |
54 | samples.AddRange(result);
55 | }
56 | return samples;
57 | }
58 |
59 |
60 | public override bool Equals(object obj)
61 | {
62 | // If parameter is null return false.
63 | if (obj == null)
64 | {
65 | return false;
66 | }
67 |
68 | // If parameter cannot be cast to Point return false.
69 | Sample s = obj as Sample;
70 | if (s == null)
71 | return false;
72 |
73 | // Return true if the fields match:
74 | return (Point == s.Point);
75 | }
76 | public override int GetHashCode()
77 | {
78 | return Point.GetHashCode();
79 | }
80 |
81 | public bool OnEdge(int width, int height)
82 | {
83 | return (Point.X == 0 || Point.Y == 0 ||
84 | Point.Y == width - 1 || Point.Y == height - 1);
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/SampleTri.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using TriangleNet.Data;
9 | using TriangleNet.Geometry;
10 | using Point = System.Drawing.Point;
11 |
12 | namespace Trigrad.DataTypes
13 | {
14 | public class SampleTri
15 | {
16 | public SampleTri()
17 | {
18 |
19 | }
20 |
21 | public SampleTri(ITriangle t)
22 | {
23 | Vertex u = t.GetVertex(0);
24 | Vertex v = t.GetVertex(1);
25 | Vertex w = t.GetVertex(2);
26 |
27 |
28 | U = new Sample(u.Point(), new Pixel(Color.Black));
29 | V = new Sample(v.Point(), new Pixel(Color.Black));
30 | W = new Sample(w.Point(), new Pixel(Color.Black));
31 | }
32 |
33 | public IEnumerable Samples
34 | {
35 | get { return new[] {U, V, W}.ToList(); }
36 | }
37 |
38 | public List Points = new List();
39 |
40 | public Sample U;
41 | public Sample V;
42 | public Sample W;
43 |
44 | public bool Busy;
45 |
46 | public Point CenterPoint
47 | {
48 | get { return new Point((int) Samples.Average(s => s.Point.X), (int) Samples.Average(s => s.Point.Y)); }
49 | }
50 | public Pixel CenterColor;
51 |
52 | public List TriangleNeighbours = new List();
53 | public List SampleTriNeighbours = new List();
54 |
55 | public override string ToString()
56 | {
57 | return string.Format("({0}),({1}),({2})", U.Point, V.Point, W.Point);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/TrigradDecompressed.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Drawing;
3 | using PixelMapSharp;
4 | using TriangleNet;
5 |
6 | namespace Trigrad.DataTypes
7 | {
8 | /// The results of a TrigradDecompression, containing both the output and debug bitmaps.
9 | public class TrigradDecompressed
10 | {
11 | /// Constructor for a TrigradDecompressed object, defining the width and height of output bitmaps.
12 | public TrigradDecompressed(int width, int height)
13 | {
14 | Output = new PixelMap(width, height);
15 | DebugOutput = new PixelMap(width, height);
16 | }
17 | /// The decompressed output bitmap.
18 | public PixelMap Output;
19 | /// The debug output bitmap, showing calculated barycentric coordinates.
20 | public PixelMap DebugOutput;
21 |
22 | internal List Mesh;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Trigrad/DataTypes/TrigradOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Trigrad.ColorGraders;
7 | using Trigrad.Renderers;
8 |
9 | namespace Trigrad.DataTypes
10 | {
11 | /// Options for the usage of the TrigradCompressor.
12 | public class TrigradOptions
13 | {
14 | /// Constructs a TrigradOptions with a random seed.
15 | public TrigradOptions()
16 | {
17 | Random = new Random();
18 | }
19 |
20 | /// Constructs a TrigradOptions with a specified seed.
21 | public TrigradOptions(int seed)
22 | {
23 | Random = new Random(seed);
24 | }
25 |
26 | /// The goal number of samples to be achieved.
27 | public int SampleCount = 1000;
28 |
29 | /// The frequency table providing the TrigradCompressor values regarding the chance a pixel will be sampled.
30 | public FrequencyTable FrequencyTable = null;
31 |
32 | /// The random number generator to be used by the TrigradCompressor.
33 | public Random Random;
34 |
35 | /// The number of resamples.
36 | public int Resamples = 25;
37 |
38 | /// The number of iterations performed during minimisation.
39 | public int Iterations = 4;
40 |
41 | public IFill Renderer;
42 |
43 | public bool ResampleColors = true;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Trigrad/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using TriangleNet.Data;
4 | using System.Drawing;
5 | using PixelMapSharp;
6 | using TriangleNet;
7 | using Trigrad.DataTypes;
8 |
9 | namespace Trigrad
10 | {
11 | public static class Extensions
12 | {
13 | public static Point Point(this Vertex t)
14 | {
15 | return new Point((int)t.X, (int)t.Y);
16 | }
17 |
18 | public static PixelMap DrawMesh(this List m,int width,int height)
19 | {
20 | Bitmap b = new Bitmap(width,height);
21 | Graphics g = Graphics.FromImage(b);
22 |
23 |
24 | foreach (var sampleTri in m)
25 | {
26 | g.DrawLine(new Pen(sampleTri.U.Color.Color), sampleTri.U.Point, sampleTri.V.Point);
27 | g.DrawLine(new Pen(sampleTri.U.Color.Color), sampleTri.V.Point, sampleTri.W.Point);
28 | g.DrawLine(new Pen(sampleTri.U.Color.Color), sampleTri.W.Point, sampleTri.U.Point);
29 | }
30 |
31 | return new PixelMap(b);
32 | }
33 |
34 | public static void Shuffle(this IList list,Random r)
35 | {
36 | int n = list.Count;
37 | while (n > 1)
38 | {
39 | n--;
40 | int k = r.Next(n + 1);
41 | T value = list[k];
42 | list[k] = list[n];
43 | list[n] = value;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Trigrad/Filters/AreaFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Trigrad.DataTypes;
8 |
9 | namespace Trigrad.Filters
10 | {
11 | public class AreaFilter : ITriGradFilter
12 | {
13 | public AreaFilter(int depth)
14 | {
15 | Depth = depth;
16 | }
17 |
18 | public int Depth;
19 |
20 | public void Run(List mesh)
21 | {
22 | double s = 2;
23 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).ToList(), sample =>
24 | {
25 | Point p = sample.Point;
26 |
27 | sample.Point = new Point(p.X + (int)(Math.Sin(p.X / s) * s), p.Y);
28 | });
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Trigrad/Filters/AverageFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.Filters
11 | {
12 | public class AverageFilter : ITriGradFilter
13 | {
14 | public AverageFilter(int depth)
15 | {
16 | Depth = depth;
17 | }
18 |
19 | public int Depth;
20 |
21 | public void Run(List mesh)
22 | {
23 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).ToList(), sample =>
24 | {
25 | var neighbours = sample.DepthNeighbours(Depth);
26 |
27 | var colors = neighbours.Select(s => s.Color);
28 |
29 | sample.Color = new Pixel((int)colors.Average(c => c.R), (int)colors.Average(c => c.G),(int)colors.Average(c => c.B));
30 | });
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Trigrad/Filters/Filter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Trigrad.DataTypes;
3 |
4 | namespace Trigrad.Filters
5 | {
6 | interface ITriGradFilter
7 | {
8 | void Run(List Mesh);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Trigrad/Filters/GridFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Trigrad.DataTypes;
8 |
9 | namespace Trigrad.Filters
10 | {
11 | public class GridFilter : ITriGradFilter
12 | {
13 | public GridFilter(int size)
14 | {
15 | Size = size;
16 | }
17 |
18 | public int Size;
19 | public void Run(List mesh)
20 | {
21 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).Distinct().ToList(), sample =>
22 | {
23 | sample.Point = new Point(sample.Point.X - sample.Point.X % Size, sample.Point.Y - sample.Point.Y % Size);
24 | //sample.Point = new Point(sample.Point.X + (int)(Math.Sin(sample.Point.X + sample.Point.Y) * (Size / 2)), sample.Point.Y + (int)(Math.Sin(sample.Point.X + sample.Point.Y) * (Size / 2)));
25 | });
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Trigrad/Filters/MedianFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Trigrad.DataTypes;
7 | using System.Drawing;
8 |
9 | namespace Trigrad.Filters
10 | {
11 | public class MedianFilter : ITriGradFilter
12 | {
13 | public MedianFilter(int depth)
14 | {
15 | Depth = depth;
16 | }
17 |
18 | public int Depth;
19 | public void Run(List mesh)
20 | {
21 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).Distinct().ToList(), sample =>
22 | {
23 | var neighbours = sample.DepthNeighbours(Depth);
24 |
25 | var colors = neighbours.Select(s => s.Color).OrderByDescending(c => c.Saturation).ToList();
26 |
27 | sample.NewColor = colors.Last();
28 | });
29 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).Distinct().ToList(), sample =>
30 | {
31 | sample.Color = sample.NewColor;
32 | });
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Trigrad/Filters/NoiseFilter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Trigrad.DataTypes;
7 |
8 | namespace Trigrad.Filters
9 | {
10 | public class NoiseFilter :ITriGradFilter
11 | {
12 | public NoiseFilter(int depth)
13 | {
14 | Depth = depth;
15 | }
16 |
17 | public int Depth;
18 | private static Random r = new Random();
19 | public void Run(List mesh)
20 | {
21 | Parallel.ForEach(mesh.SelectMany(m => m.Samples).Distinct().ToList(), sample =>
22 | {
23 | var neighbours = sample.DepthNeighbours(Depth);
24 |
25 | var colors = neighbours.ToList();
26 |
27 | sample.Color = colors[r.Next(0, colors.Count)].Color;
28 | });
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Trigrad/GPUT.c:
--------------------------------------------------------------------------------
1 | kernel void Barycentric(
2 | global read_only int2* p_p,
3 | global read_only int2* p_a,
4 | global read_only int2* p_b,
5 | global read_only int2* p_c,
6 | global write_only float4* c,
7 | global write_only int* c_valid)
8 | {
9 | int i = get_global_id(0);
10 |
11 | float v0[] = { p_b[i].x - p_a[i].x, p_b[i].y - p_a[i].y };
12 | float v1[] = { p_c[i].x - p_a[i].x, p_c[i].y - p_a[i].y };
13 | float v2[] = { p_p[i].x - p_a[i].x, p_p[i].y - p_a[i].y };
14 |
15 | float d00 = v0[0] * v0[0] + v0[1] * v0[1];
16 | float d01 = v0[0] * v1[0] + v0[1] * v1[1];
17 | float d11 = v1[0] * v1[0] + v1[1] * v1[1];
18 | float d20 = v2[0] * v0[0] + v2[1] * v0[1];
19 | float d21 = v2[0] * v1[0] + v2[1] * v1[1];
20 |
21 | float denom = d00 * d11 - d01 * d01;
22 |
23 | float v = ((d11 * d20 - d01 * d21) / denom);
24 | float w = ((d00 * d21 - d01 * d20) / denom);
25 | float u = (1 - v - w);
26 |
27 | c[i] = (float4)(u, v, w,0);
28 |
29 | if (u >= 0 && v >= 0 && w >= 0)
30 | {
31 | c_valid[i] = 1;
32 | }
33 | else
34 | {
35 | c_valid[i] = 0;
36 | }
37 | }
--------------------------------------------------------------------------------
/Trigrad/GPUT.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using Cloo;
5 | using Trigrad.DataTypes;
6 | using Parallel = System.Threading.Tasks.Parallel;
7 | using System.Drawing;
8 |
9 | namespace Trigrad
10 | {
11 | public class GPUT
12 | {
13 | static GPUT()
14 | {
15 | program.Build(new[] { context.Devices[0] }, null, null, IntPtr.Zero);
16 | }
17 |
18 | public static void CalculateMesh(List mesh)
19 | {
20 | List calculations = new List();
21 | foreach (var sampleTri in mesh)
22 | {
23 | sampleTri.Points.Clear();
24 | calculations.AddRange(TriangleRasterization.BuildTriCalculations(sampleTri));
25 | }
26 |
27 | Calculate(calculations);
28 | }
29 |
30 | private static ComputePlatform platform = ComputePlatform.Platforms[0];
31 | private static ComputeContextPropertyList properties = new ComputeContextPropertyList(platform);
32 | private static ComputeContext context = new ComputeContext(platform.Devices, properties, null, IntPtr.Zero);
33 |
34 | private static ComputeProgram program = new ComputeProgram(context, System.IO.File.ReadAllText("GPUT.c"));
35 |
36 | public static void Calculate(List calculations)
37 | {
38 | Stopwatch s = new Stopwatch();
39 | s.Start();
40 |
41 | int count = calculations.Count;
42 |
43 | IntVec2[] p_p = new IntVec2[count];
44 |
45 | IntVec2[] p_a = new IntVec2[count];
46 | IntVec2[] p_b = new IntVec2[count];
47 | IntVec2[] p_c = new IntVec2[count];
48 |
49 | FloatVec3[] c = new FloatVec3[count];
50 |
51 | int[] c_valid = new int[count];
52 |
53 | Parallel.For(0, count, i =>
54 | {
55 | var calc = calculations[i];
56 |
57 | p_p[i] = new IntVec2(calc.P);
58 | p_a[i] = new IntVec2(calc.A);
59 | p_b[i] = new IntVec2(calc.B);
60 | p_c[i] = new IntVec2(calc.C);
61 | });
62 |
63 | mark(s, "memory init");
64 |
65 | ComputeBuffer _p_p = new ComputeBuffer(context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, p_p);
66 |
67 | ComputeBuffer _p_a = new ComputeBuffer(context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, p_a);
68 |
69 | ComputeBuffer _p_b = new ComputeBuffer(context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, p_b);
70 |
71 | ComputeBuffer _p_c = new ComputeBuffer(context, ComputeMemoryFlags.ReadOnly | ComputeMemoryFlags.CopyHostPointer, p_c);
72 |
73 | ComputeBuffer _c = new ComputeBuffer(context, ComputeMemoryFlags.WriteOnly, c.Length);
74 | ComputeBuffer _c_valid = new ComputeBuffer(context, ComputeMemoryFlags.WriteOnly, c_valid.Length);
75 |
76 | mark(s, "memory buffer init");
77 |
78 | ComputeKernel kernel = program.CreateKernel("Barycentric");
79 | kernel.SetMemoryArgument(0, _p_p);
80 |
81 | kernel.SetMemoryArgument(1, _p_a);
82 |
83 | kernel.SetMemoryArgument(2, _p_b);
84 |
85 | kernel.SetMemoryArgument(3, _p_c);
86 |
87 | kernel.SetMemoryArgument(4, _c);
88 | kernel.SetMemoryArgument(5, _c_valid);
89 |
90 | mark(s, "memory init 2");
91 |
92 | ComputeEventList eventList = new ComputeEventList();
93 |
94 | ComputeCommandQueue commands = new ComputeCommandQueue(context, context.Devices[0], ComputeCommandQueueFlags.None);
95 |
96 | commands.Execute(kernel, null, new long[] { count }, null, eventList);
97 |
98 | mark(s, "execute");
99 |
100 | commands.ReadFromBuffer(_c, ref c, false, eventList);
101 | commands.ReadFromBuffer(_c_valid, ref c_valid, false, eventList);
102 | commands.Finish();
103 |
104 | mark(s, "read 1");
105 |
106 | Parallel.For(0, count, i =>
107 | {
108 | var calc = calculations[i];
109 | calc.Coords = new BarycentricCoordinates(c[i].U,c[i].V,c[i].W);
110 |
111 | if (c_valid[i] == 1)
112 | {
113 | lock (calc.Tri)
114 | calc.Tri.Points.Add(new DrawPoint(calc.Coords, calc.P));
115 | }
116 | });
117 |
118 | mark(s, "read 2");
119 |
120 |
121 | // cleanup commands
122 | commands.Dispose();
123 |
124 | // cleanup events
125 | foreach (ComputeEventBase eventBase in eventList)
126 | {
127 | eventBase.Dispose();
128 | }
129 | eventList.Clear();
130 |
131 | // cleanup kernel
132 | kernel.Dispose();
133 |
134 | _p_p.Dispose();
135 |
136 | _p_a.Dispose();
137 | _p_b.Dispose();
138 | _p_c.Dispose();
139 |
140 | _c.Dispose();
141 | _c_valid.Dispose();
142 |
143 | mark(s, "dispose");
144 | }
145 |
146 | private static void mark(Stopwatch s, string str)
147 | {
148 | Console.WriteLine(str + " completed in " + s.ElapsedMilliseconds);
149 | s.Restart();
150 | }
151 |
152 | private struct IntVec2
153 | {
154 | public IntVec2(Point p)
155 | {
156 | X = p.X;
157 | Y = p.Y;
158 | }
159 |
160 | public int X;
161 | public int Y;
162 | }
163 |
164 | private struct FloatVec3
165 | {
166 | public float U;
167 | public float V;
168 | public float W;
169 | public float nil;//dummy value for memory alignment
170 | }
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/Trigrad/MeshBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using PixelMapSharp;
8 | using TriangleNet;
9 | using TriangleNet.Geometry;
10 | using Trigrad.DataTypes;
11 | using Point = System.Drawing.Point;
12 |
13 | namespace Trigrad
14 | {
15 | public static class MeshBuilder
16 | {
17 | public static List BuildMesh(Dictionary pointIndex)
18 | {
19 | InputGeometry g = new InputGeometry();
20 | foreach (var value in pointIndex)
21 | {
22 | g.AddPoint(value.Key.X, value.Key.Y);
23 | }
24 |
25 | Mesh m = new Mesh();
26 | m.Triangulate(g);
27 |
28 | List sampleMesh = new List();
29 |
30 | Dictionary table = new Dictionary();
31 |
32 | Dictionary sampleTable = new Dictionary();
33 |
34 | foreach (var mTri in m.Triangles)
35 | {
36 | SampleTri tri = new SampleTri(mTri);
37 |
38 | for (int i = 0; i < 3; i++)
39 | tri.TriangleNeighbours.Add(mTri.GetNeighbor(i));
40 |
41 | sampleMesh.Add(tri);
42 | table.Add(mTri, tri);
43 |
44 | if (sampleTable.ContainsKey(tri.U.Point))
45 | tri.U = sampleTable[tri.U.Point];
46 | else
47 | sampleTable[tri.U.Point] = tri.U;
48 |
49 | if (sampleTable.ContainsKey(tri.V.Point))
50 | tri.V = sampleTable[tri.V.Point];
51 | else
52 | sampleTable[tri.V.Point] = tri.V;
53 |
54 | if (sampleTable.ContainsKey(tri.W.Point))
55 | tri.W = sampleTable[tri.W.Point];
56 | else
57 | sampleTable[tri.W.Point] = tri.W;
58 | }
59 |
60 | foreach (var tri in sampleMesh)
61 | {
62 | foreach (var triangleNeighbour in tri.TriangleNeighbours)
63 | {
64 | if (triangleNeighbour != null)
65 | tri.SampleTriNeighbours.Add(table[triangleNeighbour]);
66 | }
67 | tri.U.Triangles.Add(tri);
68 | tri.V.Triangles.Add(tri);
69 | tri.W.Triangles.Add(tri);
70 |
71 | tri.U.Color = pointIndex[tri.U.Point];
72 | tri.V.Color = pointIndex[tri.V.Point];
73 | tri.W.Color = pointIndex[tri.W.Point];
74 |
75 | tri.CenterColor = tri.U.Color;
76 | }
77 |
78 | return sampleMesh;
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Trigrad/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Trigrad")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("Trigrad")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b3554048-7521-4e2a-983e-5ce14ddbf86c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Trigrad/Renderers/CenterFill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using PixelMapSharp;
7 | using Trigrad.DataTypes;
8 |
9 | namespace Trigrad.Renderers
10 | {
11 | public class CenterFill : IFill
12 | {
13 | public void Fill(SampleTri t, PixelMap map)
14 | {
15 | foreach (var drawPoint in t.Points)
16 | {
17 | Pixel gradedColor = t.CenterColor;
18 |
19 | map[drawPoint.Point] = gradedColor;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Trigrad/Renderers/GradeFill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using PixelMapSharp;
7 | using Trigrad.ColorGraders;
8 | using Trigrad.DataTypes;
9 |
10 | namespace Trigrad.Renderers
11 | {
12 | public class GradeFill : IFill
13 | {
14 | public GradeFill(IGrader grader)
15 | {
16 | Grader = grader;
17 | }
18 |
19 | public IGrader Grader;
20 |
21 | public void Fill(SampleTri t, PixelMap map)
22 | {
23 | foreach (var drawPoint in t.Points)
24 | {
25 | Pixel gradedColor = Grader.Grade(t.U, t.V, t.W, drawPoint);
26 |
27 | map[drawPoint.Point] = gradedColor;
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Trigrad/Renderers/IFill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using PixelMapSharp;
7 | using Trigrad.DataTypes;
8 |
9 | namespace Trigrad.Renderers
10 | {
11 | public interface IFill
12 | {
13 | void Fill(SampleTri t, PixelMap map);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Trigrad/Renderers/ShapeFill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using PixelMapSharp;
6 | using Trigrad.DataTypes;
7 |
8 | namespace Trigrad.Renderers
9 | {
10 | public class ShapeFill : IFill
11 | {
12 | public ShapeFill(int sides)
13 | {
14 | ShapeFunction = t => Math.Cos(Math.PI/sides)/Math.Cos(t%((2*Math.PI)/sides) - Math.PI/sides);
15 | }
16 |
17 | public ShapeFill(Func function)
18 | {
19 | ShapeFunction = function;
20 | }
21 |
22 | public Func ShapeFunction = t => 1;
23 |
24 | public void Fill(SampleTri t, PixelMap map)
25 | {
26 | Point center = t.CenterPoint;
27 |
28 | int radius = (int)t.Samples.Max(s => dist(s.Point, center));
29 |
30 | for (int x = center.X - radius; x < center.X + radius; x++)
31 | {
32 | for (int y = center.Y - radius; y < center.Y + radius; y++)
33 | {
34 | Point fillPoint = new Point(x, y);
35 | double theta = Math.PI+Math.Atan2(fillPoint.Y - center.Y,fillPoint.X - center.X);
36 | double distance = dist(fillPoint, center);
37 |
38 | if (map.Inside(fillPoint) && distance < ShapeFunction(theta)*radius)
39 | {
40 | map[fillPoint] = t.CenterColor;
41 |
42 | //map[fillPoint] = new Pixel(theta*180/Math.PI,0.5,0.5);
43 | }
44 |
45 | if (distance > 1000)
46 | {
47 | Console.WriteLine("wat");
48 | }
49 | }
50 | }
51 |
52 | }
53 |
54 | private double dist(Point a, Point b)
55 | {
56 | int dX = a.X - b.X;
57 | int dY = a.Y - b.Y;
58 |
59 | return Math.Sqrt(dX * dX + dY * dY);
60 | }
61 |
62 |
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Trigrad/TriangleRasterisation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using Trigrad.DataTypes;
6 |
7 | namespace Trigrad
8 | {
9 | internal static class TriangleRasterization
10 | {
11 | public static IEnumerable BuildTriCalculations(SampleTri t)
12 | {
13 | int minX = t.U.Point.X < t.V.Point.X && t.U.Point.X < t.W.Point.X ? t.U.Point.X : (t.V.Point.X < t.W.Point.X ? t.V.Point.X : t.W.Point.X);
14 | int minY = t.U.Point.Y < t.V.Point.Y && t.U.Point.Y < t.W.Point.Y ? t.U.Point.Y : (t.V.Point.Y < t.W.Point.Y ? t.V.Point.Y : t.W.Point.Y);
15 |
16 | int maxX = t.U.Point.X > t.V.Point.X && t.U.Point.X > t.W.Point.X ? t.U.Point.X : (t.V.Point.X > t.W.Point.X ? t.V.Point.X : t.W.Point.X);
17 | int maxY = t.U.Point.Y > t.V.Point.Y && t.U.Point.Y > t.W.Point.Y ? t.U.Point.Y : (t.V.Point.Y > t.W.Point.Y ? t.V.Point.Y : t.W.Point.Y);
18 |
19 | for (int x = minX; x < maxX + 1; x++)
20 | {
21 | for (int y = minY; y < maxY + 1; y++)
22 | {
23 | Point p = new Point(x, y);
24 |
25 | Calculation c = new Calculation();
26 | c.A = t.U.Point;
27 | c.B = t.V.Point;
28 | c.C = t.W.Point;
29 |
30 | c.P = p;
31 | c.Tri = t;
32 |
33 | yield return c;
34 | }
35 | }
36 | }
37 | public static IEnumerable PointsInTriangle(SampleTri t)
38 | {
39 | int minX = t.U.Point.X < t.V.Point.X && t.U.Point.X < t.W.Point.X ? t.U.Point.X : (t.V.Point.X < t.W.Point.X ? t.V.Point.X : t.W.Point.X);
40 | int minY = t.U.Point.Y < t.V.Point.Y && t.U.Point.Y < t.W.Point.Y ? t.U.Point.Y : (t.V.Point.Y < t.W.Point.Y ? t.V.Point.Y : t.W.Point.Y);
41 |
42 | int maxX = t.U.Point.X > t.V.Point.X && t.U.Point.X > t.W.Point.X ? t.U.Point.X : (t.V.Point.X > t.W.Point.X ? t.V.Point.X : t.W.Point.X);
43 | int maxY = t.U.Point.Y > t.V.Point.Y && t.U.Point.Y > t.W.Point.Y ? t.U.Point.Y : (t.V.Point.Y > t.W.Point.Y ? t.V.Point.Y : t.W.Point.Y);
44 |
45 | for (int x = minX; x < maxX + 1; x++)
46 | {
47 | for (int y = minY; y < maxY + 1; y++)
48 | {
49 | Point p = new Point(x, y);
50 |
51 | var coords = Barycentric.GetCoordinates(p, t.U.Point,t.V.Point,t.W.Point);
52 |
53 | if (Barycentric.ValidCoords(coords))
54 | {
55 | yield return new DrawPoint(coords, p);
56 | }
57 | }
58 | }
59 | }
60 |
61 | public static void CalculateMesh(List mesh)
62 | {
63 | foreach (var t in mesh)
64 | {
65 | t.Points = PointsInTriangle(t).ToList();
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Trigrad/Trigrad.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3E743CD4-6FB3-43DA-AA7B-F4B2EEEAFA85}
8 | Library
9 | Properties
10 | Trigrad
11 | Trigrad
12 | v4.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 | true
24 | bin\Debug\Trigrad.XML
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 | ..\packages\Sourceforge.Cloo.0.9.1\lib\net35\Cloo.dll
37 |
38 |
39 | ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll
40 |
41 |
42 | ..\packages\MathNet.Numerics.3.7.0\lib\net40\MathNet.Numerics.dll
43 |
44 |
45 | ..\packages\PixelMap.1.0.1\lib\PixelMap.dll
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ..\Triangle.dll
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | Always
105 |
106 |
107 |
108 |
115 |
--------------------------------------------------------------------------------
/Trigrad/TrigradCompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Drawing;
4 | using System.Linq;
5 | using System.Runtime.InteropServices;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using PixelMapSharp;
9 | using TriangleNet;
10 | using TriangleNet.Data;
11 | using TriangleNet.Geometry;
12 | using Trigrad.DataTypes;
13 | using Trigrad.DataTypes.Compression;
14 | using Point = System.Drawing.Point;
15 |
16 | namespace Trigrad
17 | {
18 | public delegate void CompressorProgressUpdate(double progress);
19 |
20 | /// Holds methods for compressing trigrad compressed imagery.
21 | public static class TrigradCompressor
22 | {
23 | public static event CompressorProgressUpdate OnUpdate;
24 |
25 | /// Compresses a bitmap using TrigradCompression.
26 | /// The input bitmap.
27 | /// TrigradOptions specifying how the image will be compressed.
28 | public static TrigradCompressed CompressBitmap(PixelMap pixelmap, TrigradOptions options)
29 | {
30 | TrigradCompressed compressed = new TrigradCompressed { Height = pixelmap.Height, Width = pixelmap.Width };
31 |
32 | double baseChance = options.SampleCount / (options.FrequencyTable.Sum);
33 |
34 | int i = 0;
35 | int count = pixelmap.Width * pixelmap.Height;
36 | for (int x = 0; x < pixelmap.Width; x++)
37 | {
38 | for (int y = 0; y < pixelmap.Height; y++)
39 | {
40 | if ((x == 0 && y == 0) ||
41 | (x == pixelmap.Width - 1 && y == 0) ||
42 | (x == 0 && y == pixelmap.Height - 1) ||
43 | (x == pixelmap.Width - 1 && y == pixelmap.Height - 1))
44 | {
45 | compressed.SampleTable[new Point(x, y)] = pixelmap[new Point(x, y)];
46 | continue;
47 | }
48 |
49 | double chance = ((options.FrequencyTable != null)
50 | ? options.FrequencyTable.Table[x, y]
51 | : 1d) * baseChance;
52 |
53 | lock(options.Random)
54 | if (options.Random.NextDouble() < chance)
55 | {
56 | lock (compressed.SampleTable)
57 | compressed.SampleTable[new Point(x, y)] = pixelmap[new Point(x, y)];
58 | }
59 |
60 |
61 | if (i % 50 == 0 && OnUpdate != null)
62 | OnUpdate((double)i / count);
63 |
64 | i++;
65 | }
66 | }
67 |
68 |
69 | return compressed;
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Trigrad/TrigradDecompressor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Drawing;
5 | using System.Drawing.Imaging;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using PixelMapSharp;
9 | using TriangleNet;
10 | using TriangleNet.Data;
11 | using TriangleNet.Geometry;
12 | using Trigrad.ColorGraders;
13 | using Trigrad.DataTypes;
14 | using Trigrad.DataTypes.Compression;
15 | using Point = System.Drawing.Point;
16 |
17 | namespace Trigrad
18 | {
19 | public delegate void DecompressorProgressUpdate(double progress);
20 | /// Holds methods for decompressing trigrad compressed imagery.
21 | public static class TrigradDecompressor
22 | {
23 | public static event DecompressorProgressUpdate OnUpdate;
24 |
25 | /// Decompresses a trigrad compressed bitmap.
26 | /// The TrigradCompressed data.
27 | /// The original image to determine the most effect fill mode.
28 | /// Options dictating the decompression.
29 | public static TrigradDecompressed DecompressBitmap(TrigradCompressed compressionData, TrigradOptions options)
30 | {
31 | TrigradDecompressed decompressed = new TrigradDecompressed(compressionData.Width, compressionData.Height);
32 |
33 | for (int x = 0; x < compressionData.Width; x++)
34 | for (int y = 0; y < compressionData.Height; y++)
35 | decompressed.Output[x, y] = new Pixel(Color.HotPink);
36 |
37 | drawMesh(compressionData.Mesh, decompressed.Output, options);
38 |
39 |
40 | fillGaps(decompressed.Output);
41 |
42 | return decompressed;
43 | }
44 |
45 |
46 | private static void drawMesh(List mesh, PixelMap output, TrigradOptions options)
47 | {
48 | int i = 0;
49 | int count = mesh.Count;
50 | foreach (var triangle in mesh)
51 | {
52 | options.Renderer.Fill(triangle,output);
53 |
54 |
55 | if (i % 50 == 0 && OnUpdate != null)
56 | OnUpdate((double)i / count);
57 |
58 | i++;
59 | }
60 | }
61 |
62 | private static void fillGaps(PixelMap p)
63 | {
64 | Pixel lastColor = p[0];
65 | Pixel pink = new Pixel(Color.HotPink);
66 |
67 | for (int x = 0; x < p.Width; x++)
68 | {
69 | for (int y = 0; y < p.Height; y++)
70 | {
71 | if (alike(p[x, y],pink))
72 | {
73 | p[x, y] = lastColor;
74 | }
75 | else
76 | {
77 | lastColor = p[x, y];
78 | }
79 | }
80 | }
81 | }
82 |
83 | static bool alike(Pixel a, Pixel b)
84 | {
85 | return a.R == b.R && a.G == b.G && a.B == b.B;
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Trigrad/TrigradOptimiser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Drawing;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using PixelMapSharp;
11 | using TriangleNet;
12 | using TriangleNet.Data;
13 | using TriangleNet.Geometry;
14 | using Trigrad.ColorGraders;
15 | using Trigrad.DataTypes;
16 | using Trigrad.DataTypes.Compression;
17 | using Point = System.Drawing.Point;
18 |
19 | namespace Trigrad
20 | {
21 | public delegate void OptimiserProgressUpdate(double progress);
22 |
23 | public static class TrigradOptimiser
24 | {
25 | public static event OptimiserProgressUpdate OnUpdate;
26 |
27 |
28 | public static void OptimiseMesh(TrigradCompressed compressionData, PixelMap original, TrigradOptions options)
29 | {
30 | var mesh = compressionData.Mesh;
31 | GPUT.CalculateMesh(mesh);
32 |
33 | var samples = mesh.SelectMany(t => t.Samples).Distinct().ToList();
34 |
35 | for (int i = 0; i < options.Iterations; i++)
36 | {
37 | minimiseMesh(samples, options, original);
38 |
39 | Console.WriteLine("{0}/{1}", i, options.Iterations);
40 | }
41 |
42 | compressionData.Mesh = mesh;
43 | }
44 |
45 |
46 | static void minimiseMesh(List samples, TrigradOptions options, PixelMap original)
47 | {
48 | tempMap = new PixelMap(original.Width,original.Height);
49 |
50 | int o = 0;
51 | int count = samples.Count;
52 | foreach (var sample in samples)
53 | {
54 | minimiseSample(sample, options.Resamples, original, options);
55 |
56 | o++;
57 |
58 | if (o%1000 == 0)
59 | Console.WriteLine("{0}/{1}", o, samples.Count);
60 |
61 | if (o%100 == 0 && OnUpdate != null)
62 | OnUpdate((double)o/count);
63 | }
64 | }
65 |
66 |
67 | private static void minimiseSample(Sample s, int resamples, PixelMap original, TrigradOptions options)
68 | {
69 | if (s.Point.X == 0 || s.Point.Y == 0)
70 | return;
71 |
72 | if (s.Point.X == original.Width - 1 || s.Point.Y == original.Height - 1)
73 | return;
74 |
75 |
76 | var curPoints = s.Points;
77 |
78 | double minError = errorPolygon(s, original, options);
79 | Point bestPoint = s.Point;
80 |
81 | if (polygonConvex(s))
82 | return;
83 |
84 | int count = curPoints.Count;
85 | int skip = count / resamples;
86 | if (skip == 0)
87 | skip = 1;
88 |
89 | foreach (var drawPoint in curPoints.Where((x, i) => i % skip == 0))
90 | {
91 | s.Point = drawPoint.Point;
92 |
93 | TriangleRasterization.CalculateMesh(s.Triangles);
94 |
95 | double error = errorPolygon(s, original, options);
96 | if (error < minError)
97 | {
98 | bestPoint = drawPoint.Point;
99 | minError = error;
100 | }
101 | }
102 |
103 | s.Point = bestPoint;
104 | TriangleRasterization.CalculateMesh(s.Triangles);
105 | }
106 |
107 | private static PixelMap tempMap;
108 | private static double errorPolygon(Sample s, PixelMap original, TrigradOptions options)
109 | {
110 | if(options.ResampleColors)
111 | foreach (var sample in s.Samples)
112 | {
113 | sample.Color = original[sample.Point];
114 | }
115 |
116 | double error = 0d;
117 | foreach (var t in s.Triangles)
118 | {
119 | t.CenterColor = original[t.CenterPoint];
120 |
121 | options.Renderer.Fill(t,tempMap);
122 |
123 | foreach (var drawPoint in t.Points)
124 | {
125 | Pixel a = original[drawPoint.Point];
126 | Pixel b = tempMap[drawPoint.Point];
127 |
128 | Pixel diff = a - b;
129 |
130 | error += diff.R;
131 | error += diff.G;
132 | error += diff.B;
133 | }
134 | }
135 | return error;
136 | }
137 |
138 | private static bool polygonConvex(Sample s)
139 | {
140 | List outerPolygonPoints = s.Samples.Except(new[]{s}).Select(sample=>sample.Point).ToList();
141 |
142 | bool got_negative = false;
143 | bool got_positive = false;
144 | int num_points = outerPolygonPoints.Count();
145 | int B, C;
146 | for (int A = 0; A < num_points; A++)
147 | {
148 | B = (A + 1) % num_points;
149 | C = (B + 1) % num_points;
150 |
151 | float cross_product =
152 | crossProductMagnitude(
153 | outerPolygonPoints[A].X, outerPolygonPoints[A].Y,
154 | outerPolygonPoints[B].X, outerPolygonPoints[B].Y,
155 | outerPolygonPoints[C].X, outerPolygonPoints[C].Y);
156 | if (cross_product < 0)
157 | {
158 | got_negative = true;
159 | }
160 | else if (cross_product > 0)
161 | {
162 | got_positive = true;
163 | }
164 | if (got_negative && got_positive) return false;
165 | }
166 |
167 | // If we got this far, the polygon is convex.
168 | return true;
169 | }
170 | private static float crossProductMagnitude(float Ax, float Ay,
171 | float Bx, float By, float Cx, float Cy)
172 | {
173 | // Get the vectors' coordinates.
174 | float BAx = Ax - Bx;
175 | float BAy = Ay - By;
176 | float BCx = Cx - Bx;
177 | float BCy = Cy - By;
178 |
179 | // Calculate the Z coordinate of the cross product.
180 | return (BAx * BCy - BAy * BCx);
181 | }
182 |
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/Trigrad/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/TrigradTesting/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TrigradTesting/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Drawing;
5 | using System.IO;
6 | using System.Linq;
7 | using PixelMapSharp;
8 | using Trigrad;
9 | using Trigrad.ColorGraders;
10 | using Trigrad.DataTypes;
11 | using Trigrad.DataTypes.Compression;
12 | using Trigrad.Filters;
13 | using Trigrad.Renderers;
14 |
15 | namespace TrigradTesting
16 | {
17 | class Program
18 | {
19 | private static string backup = @"E:\deepstorage";
20 |
21 | static void Main(string[] args)
22 | {
23 | Stopwatch s = new Stopwatch();
24 | s.Start();
25 | Console.WriteLine("Trigrad");
26 | string input = "tests\\input\\Tulips.jpg";
27 |
28 | PixelMap inputBitmap = PixelMap.SlowLoad(new Bitmap(input));
29 | FrequencyTable table = new FrequencyTable(inputBitmap,1);
30 |
31 | var options = new TrigradOptions
32 | {
33 | SampleCount = 40000,
34 | FrequencyTable = table,
35 | Resamples = 4,
36 | Iterations =0,
37 | Random = new Random(0),
38 | ResampleColors = true,
39 | Renderer = new ShapeFill(3)
40 | };
41 |
42 | var results = TrigradCompressor.CompressBitmap(inputBitmap, options);
43 |
44 | results.DebugVisualisation().GetBitmap().Save("tests\\points.png");
45 |
46 | results.Mesh = MeshBuilder.BuildMesh(results.SampleTable);
47 | results.MeshOutput(inputBitmap).GetBitmap().Save("tests\\mesh_a.png");
48 |
49 | TrigradOptimiser.OptimiseMesh(results, inputBitmap, options);
50 |
51 |
52 | GPUT.CalculateMesh(results.Mesh);
53 |
54 | //results.Save(new FileStream("tests\\out.tri", FileMode.Create));
55 |
56 | results.MeshOutput(inputBitmap).GetBitmap().Save("tests\\mesh_b.png");
57 |
58 | Console.WriteLine(results.SampleTable.Count);
59 |
60 | //var loaded = new TrigradCompressed(new FileStream("tests\\out.tri", FileMode.Open));
61 |
62 | //results.Mesh = results.Mesh.OrderBy(t => t.CenterColor.Lightness).ToList();
63 | results.Mesh.Shuffle(options.Random);
64 |
65 | var returned = TrigradDecompressor.DecompressBitmap(results, options);
66 |
67 | returned.Output.GetBitmap().Save("tests\\output.png");
68 | returned.DebugOutput.GetBitmap().Save("tests\\debug_output.png");
69 |
70 | int error = errorBitmap(inputBitmap, returned.Output);
71 | double avgError = Math.Round((double)error / (inputBitmap.Width * inputBitmap.Height * 3), 2);
72 |
73 | Console.WriteLine("{0} error", avgError);
74 | Console.WriteLine("{0} s", Math.Round(s.ElapsedMilliseconds / 1000d, 2));
75 |
76 | saveBackup(avgError, Path.GetFileNameWithoutExtension(input), options);
77 |
78 | Console.Beep();
79 | Console.ReadKey();
80 | }
81 |
82 | static void saveBackup(double error, string file, TrigradOptions options)
83 | {
84 | Random r = new Random();
85 |
86 | var path = Path.Combine(backup, string.Format("{0} Test #{1}, {2} err, {3} samples, {4} resamples, {5} iterations", file, r.Next(), error, options.SampleCount, options.Resamples, options.Iterations));
87 | Directory.CreateDirectory(path);
88 |
89 | File.Copy("tests\\points.png", Path.Combine(path, "points.png"));
90 | File.Copy("tests\\output.png", Path.Combine(path, "output.png"));
91 | //File.Copy("tests\\debug_output.png", Path.Combine(path, "debug_output.png"));
92 | File.Copy("tests\\mesh_a.png", Path.Combine(path, "mesh_a.png"));
93 | File.Copy("tests\\mesh_b.png", Path.Combine(path, "mesh_b.png"));
94 | File.Copy("tests\\error.png", Path.Combine(path, "error.png"));
95 |
96 | }
97 |
98 | static int errorBitmap(PixelMap a, PixelMap b)
99 | {
100 | int error = 0;
101 | PixelMap output = new PixelMap(a.Width, a.Height);
102 | for (int x = 0; x < a.Width; x++)
103 | {
104 | for (int y = 0; y < a.Height; y++)
105 | {
106 | Pixel cA = a[x, y];
107 | Pixel cB = b[x, y];
108 |
109 | Pixel diff = cA - cB;
110 |
111 | error += (diff.R + diff.G + diff.B);
112 |
113 | output[x, y] = diff;
114 | }
115 | }
116 | output.GetBitmap().Save("tests\\error.png");
117 |
118 | return error;
119 | }
120 |
121 | static TrigradCompressed fauxResults(PixelMap input)
122 | {
123 | var results = new TrigradCompressed();
124 |
125 | results.Width = input.Width;
126 | results.Height = input.Height;
127 |
128 | List samplePoints = new List();
129 |
130 | samplePoints.Add(new Point(0, 0));
131 | samplePoints.Add(new Point(input.Width - 1, 0));
132 | samplePoints.Add(new Point(0, input.Height - 1));
133 | samplePoints.Add(new Point(input.Width - 1, input.Height - 1));
134 |
135 | int cellsize = 8;
136 |
137 |
138 |
139 | for (int x = 0; x < input.Width / cellsize; x++)
140 | {
141 | for (int y = 0; y < input.Height / cellsize; y++)
142 | {
143 | samplePoints.Add(new Point(x * cellsize, y * cellsize));
144 | }
145 | }
146 |
147 | foreach (var samplePoint in samplePoints)
148 | {
149 | results.SampleTable[samplePoint] = input[samplePoint];
150 | }
151 |
152 | results.Mesh = MeshBuilder.BuildMesh(results.SampleTable);
153 |
154 | return results;
155 | }
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/TrigradTesting/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TrigradTesting")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("TrigradTesting")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b638631e-4e61-419e-a561-7eae4a4d7102")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/TrigradTesting/TrigradTesting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E984EACE-46E7-485E-8A1C-FCB5884698F0}
8 | Exe
9 | Properties
10 | TrigradTesting
11 | TrigradTesting
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 | true
36 | bin\x64\Debug\
37 | DEBUG;TRACE
38 | full
39 | x64
40 | prompt
41 | MinimumRecommendedRules.ruleset
42 | true
43 |
44 |
45 | bin\x64\Release\
46 | TRACE
47 | true
48 | pdbonly
49 | x64
50 | prompt
51 | MinimumRecommendedRules.ruleset
52 | true
53 |
54 |
55 |
56 | ..\packages\PixelMap.1.0.1\lib\PixelMap.dll
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | {3e743cd4-6fb3-43da-aa7b-f4b2eeeafa85}
78 | Trigrad
79 |
80 |
81 |
82 |
89 |
--------------------------------------------------------------------------------
/TrigradTesting/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------