From c76ca34eeeb23b8986fb53bba8b8f3723c151e3b Mon Sep 17 00:00:00 2001 From: larsbrubaker Date: Sun, 19 Apr 2015 20:15:40 -0700 Subject: [PATCH] Made an experimental thumbnail ray tracer. --- CustomWidgets/PartThumbnailWidget.cs | 102 +++++------ CustomWidgets/ThumbnailTracer.cs | 242 +++++++++++++++++++++++++++ MatterControl.csproj | 5 + MatterControl.sln | 31 ++++ Submodules/agg-sharp | 2 +- 5 files changed, 333 insertions(+), 49 deletions(-) create mode 100644 CustomWidgets/ThumbnailTracer.cs diff --git a/CustomWidgets/PartThumbnailWidget.cs b/CustomWidgets/PartThumbnailWidget.cs index 8f1c9e0e8..e4d92c70a 100644 --- a/CustomWidgets/PartThumbnailWidget.cs +++ b/CustomWidgets/PartThumbnailWidget.cs @@ -27,6 +27,8 @@ of the authors and should not be interpreted as representing official policies, either expressed or implied, of the FreeBSD Project. */ +//#define RENDER_RAYTRACED + using MatterHackers.Agg; using MatterHackers.Agg.Image; using MatterHackers.Agg.PlatformAbstract; @@ -37,10 +39,12 @@ using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.PolygonMesh; using MatterHackers.PolygonMesh.Processors; +using MatterHackers.RayTracer; using MatterHackers.VectorMath; using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.IO; namespace MatterHackers.MatterControl @@ -234,7 +238,11 @@ namespace MatterHackers.MatterControl string stlHashCode = thumbnailWidget.PrintItem.FileHashCode.ToString(); +#if RENDER_RAYTRACED + Point2D bigRenderSize = new Point2D(115, 115); +#else Point2D bigRenderSize = new Point2D(460, 460); +#endif ImageBuffer bigRender = LoadImageFromDisk(thumbnailWidget, stlHashCode, bigRenderSize); if (bigRender == null) { @@ -242,7 +250,14 @@ namespace MatterHackers.MatterControl { return; } + List loadedMeshGroups = MeshFileIo.Load(thumbnailWidget.PrintItem.FileLocation); +#if RENDER_RAYTRACED + ThumbnailTracer tracer = new ThumbnailTracer(loadedMeshGroups, bigRenderSize.x, bigRenderSize.y); + tracer.DoTrace(); + + bigRender = tracer.destImage; +#else thumbnailWidget.thumbnailImage = new ImageBuffer(thumbnailWidget.buildingThumbnailImage); thumbnailWidget.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); @@ -251,42 +266,37 @@ namespace MatterHackers.MatterControl { bigRender = new ImageBuffer(thumbnailWidget.noThumbnailImage); } +#endif + // and save it to disk + string imageFileName = GetImageFileName(stlHashCode, bigRenderSize); + + if (partExtension == ".png") + { + ImageIO.SaveImageData(imageFileName, bigRender); + } + else + { + ImageTgaIO.SaveImageData(imageFileName, bigRender); + } } - switch (thumbnailWidget.Size) + ImageBuffer unScaledImage = new ImageBuffer(bigRender.Width, bigRender.Height, 32, new BlenderBGRA()); + unScaledImage.NewGraphics2D().Render(bigRender, 0, 0); + // If the source image (the one we downloaded) is more than twice as big as our dest image. + while (unScaledImage.Width > Width * 2) { - case ImageSizes.Size50x50: - { - ImageBuffer halfWay1 = new ImageBuffer(200, 200, 32, new BlenderBGRA()); - halfWay1.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - halfWay1.NewGraphics2D().Render(bigRender, 0, 0, 0, (double)halfWay1.Width / bigRender.Width, (double)halfWay1.Height / bigRender.Height); - - ImageBuffer halfWay2 = new ImageBuffer(100, 100, 32, new BlenderBGRA()); - halfWay2.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - halfWay2.NewGraphics2D().Render(halfWay1, 0, 0, 0, (double)halfWay2.Width / halfWay1.Width, (double)halfWay2.Height / halfWay1.Height); - - thumbnailWidget.thumbnailImage = new ImageBuffer((int)Width, (int)Height, 32, new BlenderBGRA()); - thumbnailWidget.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - thumbnailWidget.thumbnailImage.NewGraphics2D().Render(halfWay2, 0, 0, 0, (double)thumbnailWidget.thumbnailImage.Width / halfWay2.Width, (double)thumbnailWidget.thumbnailImage.Height / halfWay2.Height); - } - break; - - case ImageSizes.Size115x115: - { - ImageBuffer halfWay1 = new ImageBuffer(230, 230, 32, new BlenderBGRA()); - halfWay1.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - halfWay1.NewGraphics2D().Render(bigRender, 0, 0, 0, (double)halfWay1.Width / bigRender.Width, (double)halfWay1.Height / bigRender.Height); - - thumbnailWidget.thumbnailImage = new ImageBuffer((int)Width, (int)Height, 32, new BlenderBGRA()); - thumbnailWidget.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); - thumbnailWidget.thumbnailImage.NewGraphics2D().Render(halfWay1, 0, 0, 0, (double)thumbnailWidget.thumbnailImage.Width / halfWay1.Width, (double)thumbnailWidget.thumbnailImage.Height / halfWay1.Height); - } - break; - - default: - throw new NotImplementedException(); + // The image sampler we use is a 2x2 filter so we need to scale by a max of 1/2 if we want to get good results. + // So we scale as many times as we need to to get the Image to be the right size. + // If this were going to be a non-uniform scale we could do the x and y separatly to get better results. + ImageBuffer halfImage = new ImageBuffer(unScaledImage.Width / 2, unScaledImage.Height / 2, 32, new BlenderBGRA()); + halfImage.NewGraphics2D().Render(unScaledImage, 0, 0, 0, halfImage.Width / (double)unScaledImage.Width, halfImage.Height / (double)unScaledImage.Height); + unScaledImage = halfImage; } + thumbnailWidget.thumbnailImage = new ImageBuffer((int)Width, (int)Height, 32, new BlenderBGRA()); + thumbnailWidget.thumbnailImage.NewGraphics2D().Clear(new RGBA_Bytes(255, 255, 255, 0)); + thumbnailWidget.thumbnailImage.NewGraphics2D().Render(unScaledImage, 0, 0, 0, (double)thumbnailWidget.thumbnailImage.Width / unScaledImage.Width, (double)thumbnailWidget.thumbnailImage.Height / unScaledImage.Height); + UiThread.RunOnIdle(thumbnailWidget.EnsureImageUpdated); } } @@ -397,23 +407,6 @@ namespace MatterHackers.MatterControl } } - // and save it to disk - string imageFileName = GetFilenameForSize(stlHashCode, size); - string folderToSavePrintsTo = Path.GetDirectoryName(imageFileName); - - if (!Directory.Exists(folderToSavePrintsTo)) - { - Directory.CreateDirectory(folderToSavePrintsTo); - } - if (partExtension == ".png") - { - ImageIO.SaveImageData(imageFileName, tempImage); - } - else - { - ImageTgaIO.SaveImageData(imageFileName, tempImage); - } - // and give it back return tempImage; } @@ -421,6 +414,19 @@ namespace MatterHackers.MatterControl return null; } + private static string GetImageFileName(string stlHashCode, Point2D size) + { + string imageFileName = GetFilenameForSize(stlHashCode, size); + string folderToSavePrintsTo = Path.GetDirectoryName(imageFileName); + + if (!Directory.Exists(folderToSavePrintsTo)) + { + Directory.CreateDirectory(folderToSavePrintsTo); + } + + return imageFileName; + } + private void createThumbnailWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { createThumbnailWorker = null; diff --git a/CustomWidgets/ThumbnailTracer.cs b/CustomWidgets/ThumbnailTracer.cs new file mode 100644 index 000000000..6198a37b3 --- /dev/null +++ b/CustomWidgets/ThumbnailTracer.cs @@ -0,0 +1,242 @@ +/* +Copyright (c) 2013, Lars Brubaker +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using MatterHackers.Agg; +using MatterHackers.Agg.Image; +using MatterHackers.Agg.OpenGlGui; +using MatterHackers.DataConverters3D; +using MatterHackers.PolygonMesh; +using MatterHackers.RayTracer.Traceable; +using MatterHackers.VectorMath; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace MatterHackers.RayTracer +{ + using MatterHackers.RayTracer.Light; + + public class ThumbnailTracer + { + public ImageBuffer destImage; + + private IPrimitive allObjects; + + private Transform allObjectsHolder; + + private MeshGroup loadedMeshGroup; + + //RayTracer raytracer = new RayTracer(AntiAliasing.None, true, true, true, true, true); + //RayTracer raytracer = new RayTracer(AntiAliasing.Low, true, true, true, true, true); + //RayTracer raytracer = new RayTracer(AntiAliasing.Medium, true, true, true, true, true); + //RayTracer raytracer = new RayTracer(AntiAliasing.High, true, true, true, true, true); + private RayTracer raytracer = new RayTracer(AntiAliasing.VeryHigh, true, true, true, true, true); + + private List renderCollection = new List(); + private bool SavedTimes = false; + private Scene scene; + private Point2D size; + private TrackballTumbleWidget trackballTumbleWidget; + public ThumbnailTracer(List meshGroups, int width, int height) + { + size = new Point2D(width, height); + trackballTumbleWidget = new TrackballTumbleWidget(); + trackballTumbleWidget.DoOpenGlDrawing = false; + trackballTumbleWidget.LocalBounds = new RectangleDouble(0, 0, width, height); + + SetRenderPosition(0); + + trackballTumbleWidget.AnchorCenter(); + + CreateScene(meshGroups); + } + + public void DoTrace() + { + RectangleInt rect = new RectangleInt(0, 0, size.x, size.y); + if (destImage == null || destImage.Width != rect.Width || destImage.Height != rect.Height) + { + destImage = new ImageBuffer(rect.Width, rect.Height, 32, new BlenderBGRA()); + } + + raytracer.RayTraceScene(rect, scene); + raytracer.CopyColorBufferToImage(destImage, rect); + } + + public void SetRenderPosition(int index) + { + trackballTumbleWidget.TrackBallController.Reset(); + trackballTumbleWidget.TrackBallController.Scale = .03; + + trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(0, 0, MathHelper.Tau / 16))); + trackballTumbleWidget.TrackBallController.Rotate(Quaternion.FromEulerAngles(new Vector3(-MathHelper.Tau * .19, 0, 0))); + + ScaleMeshToView(); + } + + private void AddAFloor() + { + ImageBuffer testImage = new ImageBuffer(200, 200, 32, new BlenderBGRA()); + Graphics2D graphics = testImage.NewGraphics2D(); + Random rand = new Random(0); + for (int i = 0; i < 100; i++) + { + RGBA_Bytes color = new RGBA_Bytes(rand.NextDouble(), rand.NextDouble(), rand.NextDouble()); + graphics.Circle(new Vector2(rand.NextDouble() * testImage.Width, rand.NextDouble() * testImage.Height), rand.NextDouble() * 40 + 10, color); + } + scene.shapes.Add(new PlaneShape(new Vector3(0, 0, 1), 0, new TextureMaterial(testImage, 0, 0, .2, 1))); + //scene.shapes.Add(new PlaneShape(new Vector3(0, 0, 1), 0, new ChessboardMaterial(new RGBA_Floats(1, 1, 1), new RGBA_Floats(0, 0, 0), 0, 0, 1, 0.7))); + } + + private void AddTestMesh(List meshGroups) + { + loadedMeshGroup = meshGroups[0]; + AxisAlignedBoundingBox meshBounds = loadedMeshGroup.GetAxisAlignedBoundingBox(); + Vector3 meshCenter = meshBounds.Center; + loadedMeshGroup.Translate(-meshCenter); + + ScaleMeshToView(); + + RGBA_Bytes partColor = new RGBA_Bytes(0, 130, 153); + partColor = RGBA_Bytes.White; + IPrimitive bvhCollection = MeshToBVH.Convert(loadedMeshGroup, new SolidMaterial(partColor.GetAsRGBA_Floats(), .01, 0.0, 2.0)); + + renderCollection.Add(bvhCollection); + } + + private void CreateScene(List meshGroups) + { + scene = new Scene(); + scene.camera = new TrackBallCamera(trackballTumbleWidget); + //scene.background = new Background(new RGBA_Floats(0.5, .5, .5), 0.4); + scene.background = new Background(new RGBA_Floats(0, 0, 0, 0), 0.4); + + AddTestMesh(meshGroups); + + allObjects = BoundingVolumeHierarchy.CreateNewHierachy(renderCollection); + allObjectsHolder = new Transform(allObjects); + //allObjects = root; + scene.shapes.Add(allObjectsHolder); + + //AddAFloor(); + + //add two lights for better lighting effects + //scene.lights.Add(new Light(new Vector3(5000, 5000, 5000), new RGBA_Floats(0.8, 0.8, 0.8))); + scene.lights.Add(new PointLight(new Vector3(-5000, -5000, 3000), new RGBA_Floats(0.5, 0.5, 0.5))); + } + + private RectangleDouble GetScreenBounds(AxisAlignedBoundingBox meshBounds) + { + RectangleDouble screenBounds = RectangleDouble.ZeroIntersection; + + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.minXYZ.y, meshBounds.minXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.minXYZ.y, meshBounds.minXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.maxXYZ.y, meshBounds.minXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.maxXYZ.y, meshBounds.minXYZ.z))); + + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.minXYZ.y, meshBounds.maxXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.minXYZ.y, meshBounds.maxXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.maxXYZ.x, meshBounds.maxXYZ.y, meshBounds.maxXYZ.z))); + screenBounds.ExpandToInclude(trackballTumbleWidget.GetScreenPosition(new Vector3(meshBounds.minXYZ.x, meshBounds.maxXYZ.y, meshBounds.maxXYZ.z))); + return screenBounds; + } + + private bool NeedsToBeSmaller(RectangleDouble partScreenBounds, RectangleDouble goalBounds) + { + if (partScreenBounds.Bottom < goalBounds.Bottom + || partScreenBounds.Top > goalBounds.Top + || partScreenBounds.Left < goalBounds.Left + || partScreenBounds.Right > goalBounds.Right) + { + return true; + } + + return false; + } + + private void ScaleMeshToView() + { + if (loadedMeshGroup != null) + { + AxisAlignedBoundingBox meshBounds = loadedMeshGroup.GetAxisAlignedBoundingBox(); // get it now that we moved it. + + bool done = false; + double scallFraction = .1; + RectangleDouble goalBounds = new RectangleDouble(0, 0, size.x, size.y); + goalBounds.Inflate(-10); + while (!done) + { + RectangleDouble partScreenBounds = GetScreenBounds(meshBounds); + + if (!NeedsToBeSmaller(partScreenBounds, goalBounds)) + { + trackballTumbleWidget.TrackBallController.Scale *= (1 + scallFraction); + partScreenBounds = GetScreenBounds(meshBounds); + + // If it crossed over the goal reduct the amount we are adjusting by. + if (NeedsToBeSmaller(partScreenBounds, goalBounds)) + { + scallFraction /= 2; + } + } + else + { + trackballTumbleWidget.TrackBallController.Scale *= (1 - scallFraction); + partScreenBounds = GetScreenBounds(meshBounds); + + // If it crossed over the goal reduct the amount we are adjusting by. + if (!NeedsToBeSmaller(partScreenBounds, goalBounds)) + { + scallFraction /= 2; + if (scallFraction < .001) + { + done = true; + } + } + } + } + } + } + + private class TrackBallCamera : ICamera + { + private TrackballTumbleWidget trackballTumbleWidget; + + public TrackBallCamera(TrackballTumbleWidget trackballTumbleWidget) + { + this.trackballTumbleWidget = trackballTumbleWidget; + } + + public Ray GetRay(double screenX, double screenY) + { + return trackballTumbleWidget.GetRayFromScreen(new Vector2(screenX, screenY)); + } + } + } +} \ No newline at end of file diff --git a/MatterControl.csproj b/MatterControl.csproj index 78c3dc038..144ee9891 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -164,6 +164,7 @@ + @@ -394,6 +395,10 @@ + + {04667764-dc7b-4b95-aef6-b4e6c87a54e9} + DataConverters3D + {9B062971-A88E-4A3D-B3C9-12B78D15FA66} clipper_library diff --git a/MatterControl.sln b/MatterControl.sln index 76aebdd30..0707184b9 100644 --- a/MatterControl.sln +++ b/MatterControl.sln @@ -118,6 +118,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{32E5 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TextCreator", "TextCreator\TextCreator.csproj", "{F49EC1DD-D645-4709-8667-B57318AF67B0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataConverters3D", "..\agg-sharp\DataConverters3D\DataConverters3D.csproj", "{04667764-DC7B-4B95-AEF6-B4E6C87A54E9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1040,6 +1042,34 @@ Global {F49EC1DD-D645-4709-8667-B57318AF67B0}.Release64|x64.ActiveCfg = Release64|x64 {F49EC1DD-D645-4709-8667-B57318AF67B0}.Release64|x64.Build.0 = Release64|x64 {F49EC1DD-D645-4709-8667-B57318AF67B0}.Release64|x86.ActiveCfg = Release64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|x64.ActiveCfg = Debug|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|x64.Build.0 = Debug|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug|x86.ActiveCfg = Debug|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|Any CPU.ActiveCfg = Debug64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|Any CPU.Build.0 = Debug64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|Mixed Platforms.ActiveCfg = Debug64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|Mixed Platforms.Build.0 = Debug64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|x64.ActiveCfg = Debug64|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|x64.Build.0 = Debug64|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Debug64|x86.ActiveCfg = Debug64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|Any CPU.Build.0 = Release|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|x64.ActiveCfg = Release|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|x64.Build.0 = Release|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release|x86.ActiveCfg = Release|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|Any CPU.ActiveCfg = Release64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|Any CPU.Build.0 = Release64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|Mixed Platforms.ActiveCfg = Release64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|Mixed Platforms.Build.0 = Release64|Any CPU + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|x64.ActiveCfg = Release64|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|x64.Build.0 = Release64|x64 + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9}.Release64|x86.ActiveCfg = Release64|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1075,6 +1105,7 @@ Global {04B850F0-5A39-4157-A227-A574064110D2} = {8F938919-F383-4BAE-BB95-13AB2A94088E} {002B1D12-4DBB-4ECF-B481-5EBECBC1666E} = {8F938919-F383-4BAE-BB95-13AB2A94088E} {F49EC1DD-D645-4709-8667-B57318AF67B0} = {32E5B656-D6DF-415E-9E7E-D03F1D8C3A8A} + {04667764-DC7B-4B95-AEF6-B4E6C87A54E9} = {2AB9B589-5C98-4C05-BBEA-F97DAE168EAB} EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = MatterControl.csproj diff --git a/Submodules/agg-sharp b/Submodules/agg-sharp index 38ed9d0b8..9386b544a 160000 --- a/Submodules/agg-sharp +++ b/Submodules/agg-sharp @@ -1 +1 @@ -Subproject commit 38ed9d0b802f9b1ffec00f0b7b227f17043200b3 +Subproject commit 9386b544a1e09e88ab9cbef0c787f52d1a2a9a4c