Changeset - f28757bb21cb
[Not reviewed]
default
0 9 8
Jason Maltzen (jmaltzen) - 9 years ago 2015-12-19 05:46:18
jason.maltzen@unsanctioned.net
Refactor recipe / reaction computation into a common class. Add some file utilities for supporting Mac bundles. Add some scripts for building Mac app bundles. Add a help window that shows the missing reactions.
17 files changed with 727 insertions and 291 deletions:
0 comments (0 inline, 0 general)
.hgignore
Show inline comments
 
syntax: glob
 
obj/
 
*.userprefs
 
*.orig
 
*.swp
 
*.zip
 
.DS_Store
 
mac/build/DesertPaintLab.app
DesertPaintLab.csproj
Show inline comments
...
 
@@ -65,16 +65,21 @@
 
    <Compile Include="gtk-gui\DesertPaintLab.FirstRunDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.SelectProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.NewProfileDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.PaintSwatch.cs" />
 
    <Compile Include="SimulatorWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.SimulatorWindow.cs" />
 
    <Compile Include="ScreenCheckDialog.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ScreenCheckDialog.cs" />
 
    <Compile Include="FileUtils.cs" />
 
    <Compile Include="PaintRecipe.cs" />
 
    <Compile Include="ReactionRecorder.cs" />
 
    <Compile Include="ReactionStatusWindow.cs" />
 
    <Compile Include="gtk-gui\DesertPaintLab.ReactionStatusWindow.cs" />
 
  </ItemGroup>
 
  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
 
  <ProjectExtensions>
 
    <MonoDevelop>
 
      <Properties>
 
        <Policies>
 
          <TextStylePolicy inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
 
          <CSharpFormattingPolicy IndentSwitchBody="True" IndentBlocksInsideExpressions="True" AnonymousMethodBraceStyle="NextLine" PropertyBraceStyle="NextLine" PropertyGetBraceStyle="NextLine" PropertySetBraceStyle="NextLine" EventBraceStyle="NextLine" EventAddBraceStyle="NextLine" EventRemoveBraceStyle="NextLine" StatementBraceStyle="NextLine" ElseNewLinePlacement="NewLine" CatchNewLinePlacement="NewLine" FinallyNewLinePlacement="NewLine" WhileNewLinePlacement="DoNotCare" ArrayInitializerWrapping="DoNotChange" ArrayInitializerBraceStyle="NextLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
FileUtils.cs
Show inline comments
 
new file 100644
 
using System;
 

	
 
namespace DesertPaintLab
 
{
 
    public class FileUtils
 
    {
 
        public FileUtils()
 
        {
 
        }
 

	
 
        public static string FindApplicationResourceDirectory(string dirname)
 
        {
 
            string dirPath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            // try "Resources" in case this is a Mac app bundle
 
            dirPath = System.IO.Path.Combine(
 
                Environment.GetFolderPath(Environment.SpecialFolder.Resources), dirname);
 
            if (System.IO.Directory.Exists(dirPath))
 
            {
 
                return dirPath;
 
            }
 
            dirPath = System.IO.Path.Combine(
 
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                "Resources", 
 
                dirname);
 
            if (!System.IO.Directory.Exists(dirPath))
 
            {
 
                // not found
 
                dirPath = null;
 
            }
 
            return dirPath;
 
        }
 

	
 
        public static string FindApplicationResourceFile(string filename)
 
        {
 
            string filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    filename);
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                // try "Resources" in case this is a Mac app bundle
 
                filePath = System.IO.Path.Combine(
 
                    Environment.GetFolderPath(Environment.SpecialFolder.Resources), filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                filePath = System.IO.Path.Combine(
 
                    System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
                    "Resources", 
 
                    filename);
 
            }
 
            if (!System.IO.File.Exists(filePath))
 
            {
 
                // not found
 
                filePath = null;
 
            }
 
            return filePath;
 
        }
 
    }
 
}
 

	
MainWindow.cs
Show inline comments
...
 
@@ -50,26 +50,24 @@ public partial class MainWindow : Gtk.Wi
 
	int screenHeight = 0;
 
	int pixelMultiplier = 1;
 

	
 
    bool enableDebugMenu = false;
 

	
 
	Gdk.Window rootWindow = null;
 
	Gdk.Pixbuf screenBuffer = null;
 

	
 
	Reagent reagent1 = null;
 
	Reagent reagent2 = null;
 
	Reagent reagent3 = null;
 
    Reagent[] reagents = new Reagent[3];
 
    PaintRecipe recipe = new PaintRecipe();
 

	
 
	
 
	public bool ShouldShutDown
 
	{
 
		get
 
		{
 
			return shouldShutDown;	
 
			return shouldShutDown;
 
		}
 
	}
 
	
 
	
 
	public MainWindow () : base(Gtk.WindowType.Toplevel)
 
	{
 
		appDataPath = System.IO.Path.Combine(
 
			Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
...
 
@@ -85,19 +83,22 @@ public partial class MainWindow : Gtk.Wi
 
		foreach (DirectoryInfo dir in dirs)
 
		{
 
			if (dir.Name != "template")
 
			{
 
				profileList.Add(dir.Name);
 
			}
 
		}
 

	
 
		Palette.Load(System.IO.Path.Combine(
 
				System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
		    	"colors.txt"));
 
        reagents[0] = null;
 
        reagents[1] = null;
 
        reagents[2] = null;
 

	
 
        string colorsPath = FileUtils.FindApplicationResourceFile("colors.txt");
 
		Palette.Load(colorsPath);
 
		
 
		Build();
 
		
 
		if (unmodifiedSwatch != null)
 
		{
 
			unmodifiedSwatch.Clear();
 
		}
 
		if (reactionSwatch != null)
...
 
@@ -380,173 +381,130 @@ public partial class MainWindow : Gtk.Wi
 
		SetExpectedColor(color.Red, color.Green, color.Blue);
 
	}
 
	
 
	protected void UpdateIngredients()
 
	{
 
		Reaction reaction1, reaction2;
 
		TreeIter selectIter;
 
		string reagentName;
 
		reagent1 = null;
 
		reagent2 = null;
 
		reagent3 = null;
 
		
 
		int expRedSum = 0;
 
		int expGreenSum = 0;
 
		int expBlueSum = 0;
 
		
 
		int reactRedSum = 0;
 
		int reactGreenSum = 0;
 
		int reactBlueSum = 0;
 
        reagents[0] = null;
 
        reagents[1] = null;
 
        reagents[2] = null;
 
		
 
		bool reactionKnown = true;
 
		
 
		int pigmentCount = 0;
 
		
 
		saveButton.Sensitive = false;
 

	
 
        recipe.Clear();
 
		
 
		if (ingredient1ComboBox.GetActiveIter(out selectIter))
 
		{
 
			reagentName = (string)ingredient1ComboBox.Model.GetValue(selectIter, 0);
 
			if ((reagentName == null) || (reagentName.Length == 0))
 
			{
 
                // Nothing selected as reagent 1
 
				ingredient2ComboBox.Sensitive = false;
 
				ingredient3ComboBox.Sensitive = false;
 
				unmodifiedSwatch.Clear();
 
				captureButton.Sensitive = false;
 
			}
 
			else
 
			{
 
				reagent1 = ReagentManager.GetReagent(reagentName);
 
                recipe.AddReagent(reagentName);
 
                reagents[0] = ReagentManager.GetReagent(reagentName);
 
				ingredient2ComboBox.Sensitive = true;
 
				if (!reagent1.IsCatalyst)
 
				{
 
					expRedSum = reagent1.Color.Red;
 
					expGreenSum = reagent1.Color.Green;
 
					expBlueSum = reagent1.Color.Blue;
 
					pigmentCount = 1;
 
				}
 
				if (ingredient2ComboBox.GetActiveIter(out selectIter))
 
				{
 
					reagentName = (string)ingredient2ComboBox.Model.GetValue(selectIter, 0);
 
					if ((reagentName == null) || (reagentName.Length == 0))
 
					{
 
						ingredient3ComboBox.Sensitive = false;
 
						saveButton.Sensitive = false;
 
						reactionKnown = false;
 
					}
 
					else
 
					{
 
						reagent2 = ReagentManager.GetReagent(reagentName);
 
                        recipe.AddReagent(reagentName);
 
						reagents[1] = ReagentManager.GetReagent(reagentName);
 
						ingredient3ComboBox.Sensitive = true;
 
						captureButton.Sensitive = true;
 
						if (!reagent2.IsCatalyst)
 
						{
 
							expRedSum += reagent2.Color.Red;
 
							expGreenSum += reagent2.Color.Green;
 
							expBlueSum += reagent2.Color.Blue;
 
							pigmentCount++;
 
						}
 
						
 
						reaction1 = profile.FindReaction(reagent1, reagent2);
 
                        reaction1 = profile.FindReaction(reagents[0], reagents[1]);
 
						
 
						if (reaction1 != null)
 
                        if ((reaction1 != null) || (reagents[0] == reagents[1]))
 
						{
 
							ingredient3ComboBox.Sensitive = true;
 
							reactRedSum = reaction1.Red;
 
							reactGreenSum = reaction1.Green;
 
							reactBlueSum = reaction1.Blue;;	
 
						}
 
						else
 
						{
 
							reactionKnown = false;
 
							ingredient3ComboBox.Sensitive = false;
 
						}
 
						
 
						if (ingredient3ComboBox.GetActiveIter(out selectIter))
 
						{
 
							reagentName = (string)ingredient3ComboBox.Model.GetValue(selectIter, 0);
 
							if ((reagentName != null) && (reagentName.Length != 0))
 
							{
 
								reagent3 = ReagentManager.GetReagent(reagentName);
 
                                recipe.AddReagent(reagentName);
 
                                reagents[2] = ReagentManager.GetReagent(reagentName);
 
						
 
								if (!reactionKnown)
 
								{
 
									MessageDialog md = new MessageDialog(this, 
 
	            						DialogFlags.DestroyWithParent,
 
	            						MessageType.Error, ButtonsType.Ok, 
 
	            						"To do a three-ingredient reaction test, " +
 
									    "you must first recored the reaction of " +
 
									    "the first two ingredients.");
 
	   
 
									md.Run();
 
									md.Destroy();
 
									captureButton.Sensitive = false;
 
								}
 
								
 
								if (!reagent3.IsCatalyst)
 
								{
 
									expRedSum += reagent3.Color.Red;
 
									expGreenSum += reagent3.Color.Green;
 
									expBlueSum += reagent3.Color.Blue;
 
									pigmentCount++;
 
								}
 
								
 
								reaction1 = profile.FindReaction(reagent1, reagent3);
 
								reaction2 = profile.FindReaction(reagent2, reagent3);
 
                                reaction1 = profile.FindReaction(reagents[0], reagents[2]);
 
                                reaction2 = profile.FindReaction(reagents[1], reagents[2]);
 
								
 
								if (reactionKnown && (reaction1 == null) && (reaction2 == null))
 
								{
 
									MessageDialog md = new MessageDialog(this, 
 
	            						DialogFlags.DestroyWithParent,
 
	            						MessageType.Error, ButtonsType.Ok, 
 
	            						"To do a three-ingredient reaction test, " +
 
									    "you must first record the reaction of " +
 
									    "either the first or second ingredient " +
 
									    "with the third ingredient.");
 
	   
 
									md.Run();
 
									md.Destroy();	
 
									captureButton.Sensitive = false;
 
								}
 
								
 
								if (reaction1 != null)
 
								{
 
									reactRedSum += reaction1.Red;
 
									reactGreenSum += reaction1.Green;
 
									reactBlueSum += reaction1.Blue;
 
								}
 
								else
 
                                if ((reaction1 == null) && (reagents[0] != reagents[2]))
 
								{
 
									reactionKnown = false;	
 
								}
 

	
 
								if (reaction2 != null)
 
								{
 
									reactRedSum += reaction2.Red;
 
									reactGreenSum += reaction2.Green;
 
									reactBlueSum += reaction2.Blue;
 
								}
 
								else
 
                                if ((reaction2 == null) && (reagents[1] != reagents[2]))
 
								{
 
									reactionKnown = false;	
 
								}
 
							}
 
						}
 
					}
 
				}
 
				SetExpectedColor((byte)Math.Round((float)expRedSum / (float)pigmentCount),
 
					(byte)Math.Round((float)expGreenSum / (float)pigmentCount),
 
					(byte)Math.Round((float)expBlueSum / (float)pigmentCount));
 
                recipe.ComputeBaseColor(ref expectedColor);
 
                unmodifiedSwatch.Color = expectedColor;
 
                //SetExpectedColor(recipeColor.Red, recipeColor.Green, recipeColor.Blue);
 
				
 
				if (reactionKnown)
 
				{
 
					reactedColor.Red = (byte)Math.Min(255, Math.Max(0, expectedColor.Red + reactRedSum));
 
					reactedColor.Green = (byte)Math.Min(255, Math.Max(0, expectedColor.Green + reactGreenSum));
 
					reactedColor.Blue = (byte)Math.Min(255, Math.Max(0, expectedColor.Blue + reactBlueSum));
 
                    recipe.ComputeReactedColor(profile, ref reactedColor);
 
					reactionSwatch.Color = reactedColor;
 
				}
 
				else
 
				{
 
					reactionSwatch.Clear();	
 
				}
 
			}
 
		}
...
 
@@ -569,137 +527,42 @@ public partial class MainWindow : Gtk.Wi
 
	{
 
		return ((r > 0xD0) && (g > 0xC8) && (b > 0xA0)) &&
 
				((r < 0xF4) && (g < 0xE0) && (b < 0xC4));
 
	}
 
	
 
	unsafe bool CaptureReactionColor()
 
	{
 
		// Take a screenshot.
 
		byte r, g, b;
 
		int pixelStart, otherPixelStart;
 
		bool colorMatch;
 
		Gdk.Image rootImage = rootWindow.GetImage(0, 0, screenWidth, screenHeight);
 
		screenBuffer.GetFromImage(rootImage, rootImage.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
		//screenBuffer.GetFromDrawable(rootWindow,
 
		//	rootWindow.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
		int stride = screenBuffer.Rowstride;
 
		byte* pixBytes = (byte*)screenBuffer.Pixels;
 
	
 
		for (int x = 0; x < screenWidth - colorBarWidth; ++x)
 
		{
 
			for (int y = 0; y < (screenHeight - 53); ++y)
 
			{
 
				// Look for the color swatch.
 
				pixelStart = (y * stride) + (x * 3);
 
				r = pixBytes[pixelStart];
 
				g = pixBytes[pixelStart + 1];
 
				b = pixBytes[pixelStart + 2];
 
				
 
				// 1.) Check if this is a dark pixel.
 
				if ((r < 0x46) && (g < 0x46) && (b < 0x46))
 
				{
 
					// 2.) Check the pixel above it,
 
					// to see if it's from the papy texture.
 
					otherPixelStart = pixelStart - stride;
 
					if ((otherPixelStart >= 0) &&
 
					    IsPapyTexture(pixBytes[otherPixelStart++],
 
					                   pixBytes[otherPixelStart++],
 
					                   pixBytes[otherPixelStart]))
 
					{
 
						// 3.) Check the pixel below where the swatch should be,
 
						// to see if it's also from the papy texture.
 
						otherPixelStart = pixelStart + (stride * swatchHeight);
 
						if (IsPapyTexture(pixBytes[otherPixelStart++],
 
					                   pixBytes[otherPixelStart++],
 
					                   pixBytes[otherPixelStart]))
 
						{
 
							// pixBytes[pixelStart] = 0xFF;
 
							// pixBytes[pixelStart + 1] = 0x00;
 
							// pixBytes[pixelStart + 2] = 0xFF;
 
							
 
							// 4.) Scan the left border of the potential swatch
 
							// location.
 
							colorMatch = true;
 
							for (int i = 1; i < swatchHeight - 2; ++i)
 
							{
 
								otherPixelStart = pixelStart + (stride * i);
 
								if ((Math.Abs(r - pixBytes[otherPixelStart++]) > colorTolerance) ||
 
								    (Math.Abs(g - pixBytes[otherPixelStart++]) > colorTolerance) ||
 
								    (Math.Abs(b - pixBytes[otherPixelStart]) > colorTolerance))
 
								{
 
									colorMatch = false;
 
									break;
 
								}
 
							}
 
							
 
							if (colorMatch)
 
							{
 
								// WE FOUND THE SWATCH!
 
								// Now we know where the color bars are.
 
								otherPixelStart = pixelStart + (redBarSpacing * stride);
 
								int pixelCount = 0;
 
								while ((pixBytes[otherPixelStart] > 0x9F) &&
 
								       (pixBytes[otherPixelStart + 1] < 0x62) &&
 
								       (pixBytes[otherPixelStart + 2]  < 0x62))
 
								{
 
									pixelCount++;
 
									// pixBytes[otherPixelStart] = 0x00;
 
									// pixBytes[otherPixelStart + 1] = 0xFF;
 
									// pixBytes[otherPixelStart + 2] = 0xFF;
 
									otherPixelStart += 3;
 
								}
 
									
 
								reactedColor.Red = (byte)Math.Round((float)pixelCount * 255f / (float)colorBarWidth);
 
								otherPixelStart = pixelStart + (greenBarSpacing * stride);
 
								
 
								pixelCount = 0;
 
								while ((pixBytes[otherPixelStart] < 0x62) &&
 
								       (pixBytes[otherPixelStart + 1] > 0x9F) &&
 
								       (pixBytes[otherPixelStart + 2] < 0x62))
 
								{
 
									pixelCount++;
 
									// pixBytes[otherPixelStart] = 0x00;
 
									// pixBytes[otherPixelStart + 1] = 0xFF;
 
									// pixBytes[otherPixelStart + 2] = 0xFF;
 
									otherPixelStart += 3;
 
								}
 

	
 
								reactedColor.Green = (byte)Math.Round((float)pixelCount * 255f / (float)colorBarWidth);
 
								otherPixelStart = pixelStart + (blueBarSpacing * stride);
 
								
 
								pixelCount = 0;
 
								while ((pixBytes[otherPixelStart] < 0x62) &&
 
									(pixBytes[otherPixelStart + 1] < 0x62) &&
 
									(pixBytes[otherPixelStart + 2] > 0x9F))
 
								{
 
									pixelCount++;
 
									// pixBytes[otherPixelStart] = 0x00;
 
									// pixBytes[otherPixelStart + 1] = 0xFF;
 
									// pixBytes[otherPixelStart + 2] = 0xFF;
 
									otherPixelStart += 3;
 
								}
 

	
 
								reactedColor.Blue = (byte)Math.Round((float)pixelCount * 255f / (float)colorBarWidth);
 
								
 
								// write out the screenshot
 
								//screenBuffer.Save("screenshot.png", "png");
 
								return true;
 
							}
 
						}
 
					}
 
				}
 
			}
 
		}
 
        bool wasCaptured = ReactionRecorder.CaptureReaction(pixBytes, screenWidth, screenHeight, stride, ref reactedColor);
 
        if (!wasCaptured && enableDebugMenu)
 
        {
 
            // write out the screenshot
 
            string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
 
            string filename;
 
            int i = 0;
 
            do
 
            {
 
                ++i;
 
                filename = System.IO.Path.Combine(screenshotDir, String.Format("DesertPaintLab_Colormatch{0}.png", i));
 
            } while (System.IO.File.Exists(filename));
 
            screenBuffer.Save(filename, "png");
 
        }
 
        //screenBuffer.Save("screenshot.png", "png");
 
		
 
		return false;
 
		
 
		return !wasCaptured;
 
	}
 
	
 

	
 
    protected virtual void OnDebugScreenshot(object sender, System.EventArgs e)
 
    {
 
        Gdk.Image rootImage = rootWindow.GetImage(0, 0, screenWidth, screenHeight);
 
        screenBuffer.GetFromImage(rootImage, rootImage.Colormap, 0, 0, 0, 0, screenWidth, screenHeight);
 
        string screenshotDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
 
        string filename;
 
        int i = 0;
 
        do
...
 
@@ -769,57 +632,20 @@ public partial class MainWindow : Gtk.Wi
 
	   
 
			md.Run();
 
			md.Destroy();	
 
		}
 
	}
 
	
 
	protected virtual void OnSaveButton(object sender, System.EventArgs e)
 
	{
 
		int r, g, b;
 
		if (reagent3 != null)
 
		{
 
			// A 3-reagent reaction.
 
			Reaction reaction1 = profile.FindReaction(reagent1, reagent2);
 
			Reaction reaction2 = profile.FindReaction(reagent1, reagent3);
 
			Reaction reaction3 = profile.FindReaction(reagent2, reagent3);
 
			
 
			r = reactedColor.Red - expectedColor.Red;
 
			g = reactedColor.Green - expectedColor.Green;
 
			b = reactedColor.Blue - expectedColor.Blue;
 
			
 
			if (reaction2 == null)
 
			{
 
				r = r - reaction1.Red - reaction3.Red;
 
				g = g - reaction1.Green - reaction3.Green;
 
				b = b - reaction1.Blue - reaction3.Blue;
 
				profile.SetReaction(reagent1, reagent3, new Reaction(r, g, b));
 
				profile.Save();
 
				saveButton.Sensitive = false;
 
			}
 
			else if (reaction3 == null)
 
			{
 
				r = r - reaction1.Red - reaction2.Red;
 
				g = g - reaction1.Green - reaction2.Green;
 
				b = b - reaction1.Blue - reaction2.Blue;
 
				profile.SetReaction(reagent2, reagent3, new Reaction(r, g, b));
 
				profile.Save();
 
				saveButton.Sensitive = false;
 
			}	
 
		}
 
		else if ((reagent1 != null) && (reagent2 != null))
 
		{
 
			// A 2-reagent reaction.
 
			r = reactedColor.Red - expectedColor.Red;
 
			g = reactedColor.Green - expectedColor.Green;
 
			b = reactedColor.Blue - expectedColor.Blue;
 
			profile.SetReaction(reagent1, reagent2, new Reaction(r, g, b));
 
			profile.Save();
 
			saveButton.Sensitive = false;
 
		}
 
        if (ReactionRecorder.RecordReaction(profile, expectedColor, reactedColor, reagents))
 
        {
 
            saveButton.Sensitive = false;
 
        }
 
	}
 
	
 
	protected virtual void OnChangedIngredient1(object sender, System.EventArgs e)
 
	{
 
		UpdateIngredients();
 
	}
 
	
 
	protected virtual void OnChangedIngredient2(object sender, System.EventArgs e)
...
 
@@ -879,16 +705,22 @@ public partial class MainWindow : Gtk.Wi
 
			profile.Load();
 
			PopulateDropDowns();
 
		}
 
	}
 
	
 
	protected virtual void OnAbout(object sender, System.EventArgs e)
 
	{
 
		AboutDialog aboutDialog = new AboutDialog();
 

	
 
        aboutDialog.ProgramName = "Desert Paint Lab";
 
        aboutDialog.Version = "0.0.1";
 
        aboutDialog.Comments = "Desert Paint Lab paint reaction recorder for A Tale in the Desert";
 
        aboutDialog.Authors = new string [] {"Tess Snider", "Jason Maltzen"};
 
        //aboutDialog.Website = "http://www.google.com/";
 
		aboutDialog.Run();
 
		aboutDialog.Destroy();
 
	}
 
	
 
	protected virtual void OnMenuExit (object sender, System.EventArgs e)
 
	{
 
		if (ConfirmedExit())
 
		{
...
 
@@ -914,13 +746,20 @@ public partial class MainWindow : Gtk.Wi
 
	}
 
	
 
	protected virtual void RunSimulator(object sender, System.EventArgs e)
 
	{
 
		SimulatorWindow win = new SimulatorWindow(profile);
 
		win.Show();
 
	}
 
	
 
	
 
	
 
	
 
    protected void OnOpenRecipeGenerator(object sender, EventArgs e)
 
    {
 
        throw new NotImplementedException();
 
    }
 

	
 
    protected void OnShowReactionStatus(object sender, EventArgs e)
 
    {
 
        ReactionStatusWindow win = new ReactionStatusWindow(profile);
 
        win.Show();
 
    }
 
}
 

	
PaintRecipe.cs
Show inline comments
 
new file 100644
 
using System;
 
using System.Collections.Generic;
 

	
 
namespace DesertPaintLab
 
{
 
    public class PaintRecipe
 
    {
 
        public struct RGB
 
        {
 
            public int r;
 
            public int g;
 
            public int b;
 
        };
 

	
 
        private List<string> reagents = new List<string>();
 

	
 
        public PaintRecipe()
 
        {
 
        }
 

	
 
        public void AddReagent(String reagentName)
 
        {
 
            reagents.Add(reagentName);
 
        }
 

	
 
        public void Clear()
 
        {
 
            reagents.Clear();
 
        }
 

	
 
        byte CalculateColor(int baseSum, int pigmentCount, int reactSum)
 
        {
 
            return (byte)Math.Max(Math.Min(Math.Round((((float)baseSum / (float)pigmentCount) + (float)reactSum)), 255), 0);
 
        }
 

	
 
        // Compute the color including reactions based on the player's profile
 
        public void ComputeReactedColor(PlayerProfile profile, ref PaintColor paintColor)
 
        {
 
            RGB baseColor;
 
            baseColor.r = 0;
 
            baseColor.g = 0;
 
            baseColor.b = 0;
 
            RGB reactionColor;
 
            reactionColor.r = 0;
 
            reactionColor.g = 0;
 
            reactionColor.b = 0;
 

	
 
            int pigmentCount = 0;
 
            string prevReagent = null;
 

	
 
            // track visited reagents so the reaction is only applied once
 
            SortedDictionary<string,bool> reagentSet = new SortedDictionary<string,bool>();
 
            List<Reagent> prevReagents = new List<Reagent>();
 

	
 
            foreach (string reagentName in reagents)
 
            {
 
                if (reagentName == null)
 
                {
 
                    continue;   
 
                }
 
                
 
                Reagent reagent = ReagentManager.GetReagent(reagentName);
 
                if (!reagent.IsCatalyst)
 
                {
 
                    baseColor.r += reagent.Color.Red;
 
                    baseColor.g += reagent.Color.Green;
 
                    baseColor.b += reagent.Color.Blue;
 
                    pigmentCount += 1;
 
                }
 
                if (prevReagent == null || !prevReagent.Equals(reagentName))
 
                {
 
                    if (!reagentSet.ContainsKey(reagentName) && reagentSet.Count <= 4)
 
                    {
 
                        reagentSet[reagentName] = true;
 
                        // Run reactions.
 
                        foreach (Reagent otherReagent in prevReagents)
 
                        {
 
                            Reaction reaction = profile.FindReaction(otherReagent, reagent);
 
                            if (reaction != null)
 
                            {
 
                                reactionColor.r += reaction.Red;
 
                                reactionColor.g += reaction.Green;
 
                                reactionColor.b += reaction.Blue;
 
                            }
 
                        }
 
                        prevReagents.Add(reagent);
 
                    }
 
                }
 
                prevReagent = reagentName;
 
            }
 
            paintColor.Red = CalculateColor(baseColor.r, pigmentCount, reactionColor.r);
 
            paintColor.Green = CalculateColor(baseColor.g, pigmentCount, reactionColor.g);
 
            paintColor.Blue = CalculateColor(baseColor.b, pigmentCount, reactionColor.b);
 
        }
 

	
 
        // Compute the base color without any reactions
 
        public void ComputeBaseColor(ref PaintColor color)
 
        {
 
            RGB baseColor;
 
            baseColor.r = 0;
 
            baseColor.g = 0;
 
            baseColor.b = 0;
 
            int pigmentCount = 0;
 
            foreach (string reagentName in reagents)
 
            {
 
                if (reagentName == null)
 
                {
 
                    continue;   
 
                }
 
                
 
                Reagent reagent = ReagentManager.GetReagent(reagentName);
 
                if (!reagent.IsCatalyst)
 
                {
 
                    baseColor.r += reagent.Color.Red;
 
                    baseColor.g += reagent.Color.Green;
 
                    baseColor.b += reagent.Color.Blue;
 
                    pigmentCount += 1;
 
                }
 
            }
 
            color.Red = CalculateColor(baseColor.r, pigmentCount, 0);
 
            color.Green = CalculateColor(baseColor.g, pigmentCount, 0);
 
            color.Blue = CalculateColor(baseColor.b, pigmentCount, 0);
 
        }
 
    }
 
}
 

	
PlayerProfile.cs
Show inline comments
...
 
@@ -43,20 +43,22 @@ namespace DesertPaintLab
 
		}
 
		
 
		public void Initialize()
 
		{
 
			// Create new directory.
 
			System.IO.Directory.CreateDirectory(directory);
 
				
 
			// Copy template files into new directory.
 
			string templatePath = System.IO.Path.Combine(
 
				System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location),
 
		    	"template");
 
			string templatePath = FileUtils.FindApplicationResourceDirectory("template");
 
			
 
            if (!System.IO.Directory.Exists(templatePath))
 
            {
 
            }
 

 
			DirectoryInfo di = new DirectoryInfo(templatePath);
 
			FileInfo[] templateFiles = di.GetFiles();
 

 
			foreach (FileInfo file in templateFiles)
 
			{
 
				System.IO.File.Copy(file.FullName,
 
					System.IO.Path.Combine(directory, file.Name), true);					
 
			}
ReactionRecorder.cs
Show inline comments
 
new file 100644
 
using System;
 

	
 
namespace DesertPaintLab
 
{
 
    // ReactionRecorder - business logic for recording paint reactions
 
    public class ReactionRecorder
 
    {
 
        const int colorTolerance = 2;
 

	
 
        const int swatchHeight = 24;
 
        const int colorBarWidth = 306;
 
        const int redBarSpacing = 32;
 
        const int greenBarSpacing = 42;
 
        const int blueBarSpacing = 52;
 

	
 
        private static bool IsPapyTexture(byte r, byte g, byte b)
 
        {
 
            return ((r > 0xD0) && (g > 0xC8) && (b > 0xA0)) &&
 
                    ((r < 0xF4) && (g < 0xE0) && (b < 0xC4));
 
        }
 

	
 
        unsafe public static bool CaptureReaction(byte* pixBytes, int screenshotWidth, int screenshotHeight, int stride, ref PaintColor reactedColor)
 
        {
 
            byte r, g, b;
 
            int pixelStart, otherPixelStart;
 
            bool colorMatch;
 
            for (int x = 0; x < screenshotWidth - colorBarWidth; ++x)
 
            {
 
                for (int y = 0; y < (screenshotHeight - 53); ++y)
 
                {
 
                    // Look for the color swatch.
 
                    pixelStart = (y * stride) + (x * 3);
 
                    r = pixBytes[pixelStart];
 
                    g = pixBytes[pixelStart + 1];
 
                    b = pixBytes[pixelStart + 2];
 
                    
 
                    // 1.) Check if this is a dark pixel.
 
                    if ((r < 0x46) && (g < 0x46) && (b < 0x46))
 
                    {
 
                        // 2.) Check the pixel above it,
 
                        // to see if it's from the papy texture.
 
                        otherPixelStart = pixelStart - stride;
 
                        if ((otherPixelStart >= 0) &&
 
                            IsPapyTexture(pixBytes[otherPixelStart++],
 
                                           pixBytes[otherPixelStart++],
 
                                           pixBytes[otherPixelStart]))
 
                        {
 
                            // 3.) Check the pixel below where the swatch should be,
 
                            // to see if it's also from the papy texture.
 
                            otherPixelStart = pixelStart + (stride * swatchHeight);
 
                            if (IsPapyTexture(pixBytes[otherPixelStart++],
 
                                           pixBytes[otherPixelStart++],
 
                                           pixBytes[otherPixelStart]))
 
                            {
 
                                // pixBytes[pixelStart] = 0xFF;
 
                                // pixBytes[pixelStart + 1] = 0x00;
 
                                // pixBytes[pixelStart + 2] = 0xFF;
 
                                
 
                                // 4.) Scan the left border of the potential swatch
 
                                // location.
 
                                colorMatch = true;
 
                                for (int i = 1; i < swatchHeight - 2; ++i)
 
                                {
 
                                    otherPixelStart = pixelStart + (stride * i);
 
                                    if ((Math.Abs(r - pixBytes[otherPixelStart++]) > colorTolerance) ||
 
                                        (Math.Abs(g - pixBytes[otherPixelStart++]) > colorTolerance) ||
 
                                        (Math.Abs(b - pixBytes[otherPixelStart]) > colorTolerance))
 
                                    {
 
                                        colorMatch = false;
 
                                        break;
 
                                    }
 
                                }
 
                                
 
                                if (colorMatch)
 
                                {
 
                                    // WE FOUND THE SWATCH!
 
                                    // Now we know where the color bars are.
 
                                    int redPixelStart = pixelStart + (redBarSpacing * stride);
 
                                    int redPixelCount = 0;
 
                                    while ((pixBytes[redPixelStart] > 0x9F) &&
 
                                           (pixBytes[redPixelStart + 1] < 0x62) &&
 
                                           (pixBytes[redPixelStart + 2]  < 0x62))
 
                                    {
 
                                        redPixelCount++;
 
                                        // pixBytes[redPixelStart] = 0x00;
 
                                        // pixBytes[redPixelStart + 1] = 0xFF;
 
                                        // pixBytes[redPixelStart + 2] = 0xFF;
 
                                        redPixelStart += 3;
 
                                    }
 
                                        
 
                                    reactedColor.Red = (byte)Math.Round((float)redPixelCount * 255f / (float)colorBarWidth);
 
                                    int greenPixelStart = pixelStart + (greenBarSpacing * stride);
 
                                    
 
                                    int greenPixelCount = 0;
 
                                    while ((pixBytes[greenPixelStart] < 0x62) &&
 
                                           (pixBytes[greenPixelStart + 1] > 0x9F) &&
 
                                           (pixBytes[greenPixelStart + 2] < 0x62))
 
                                    {
 
                                        greenPixelCount++;
 
                                        // pixBytes[greenPixelStart] = 0x00;
 
                                        // pixBytes[greenPixelStart + 1] = 0xFF;
 
                                        // pixBytes[greenPixelStart + 2] = 0xFF;
 
                                        greenPixelStart += 3;
 
                                    }
 
    
 
                                    reactedColor.Green = (byte)Math.Round((float)greenPixelCount * 255f / (float)colorBarWidth);
 
                                    int bluePixelStart = pixelStart + (blueBarSpacing * stride);
 
                                    
 
                                    int bluePixelCount = 0;
 
                                    while ((pixBytes[bluePixelStart] < 0x62) &&
 
                                        (pixBytes[bluePixelStart + 1] < 0x62) &&
 
                                        (pixBytes[bluePixelStart + 2] > 0x9F))
 
                                    {
 
                                        bluePixelCount++;
 
                                        // pixBytes[bluePixelStart] = 0x00;
 
                                        // pixBytes[bluePixelStart + 1] = 0xFF;
 
                                        // pixBytes[bluePixelStart + 2] = 0xFF;
 
                                        bluePixelStart += 3;
 
                                    }
 
    
 
                                    reactedColor.Blue = (byte)Math.Round((float)bluePixelCount * 255f / (float)colorBarWidth);
 
                                    return true;
 
                                }
 
                            }
 
                        }
 
                    }
 
                }
 
            }
 
            return false;
 
        }
 

	
 
        public static bool RecordReaction(PlayerProfile profile, PaintColor expectedColor, PaintColor reactedColor, Reagent[] reagents)
 
        {
 
            bool saved = false;
 
            int r, g, b;
 
            if (reagents[2] != null)
 
            {
 
                // A 3-reagent reaction.
 
                Reaction reaction1 = profile.FindReaction(reagents[0], reagents[1]);
 
                Reaction reaction2 = profile.FindReaction(reagents[0], reagents[2]);
 
                Reaction reaction3 = profile.FindReaction(reagents[1], reagents[2]);
 
                
 
                r = reactedColor.Red - expectedColor.Red;
 
                g = reactedColor.Green - expectedColor.Green;
 
                b = reactedColor.Blue - expectedColor.Blue;
 
                
 
                if (reaction2 == null)
 
                {
 
                    r = r - reaction1.Red - reaction3.Red;
 
                    g = g - reaction1.Green - reaction3.Green;
 
                    b = b - reaction1.Blue - reaction3.Blue;
 
                    profile.SetReaction(reagents[0], reagents[2], new Reaction(r, g, b));
 
                    profile.Save();
 
                    saved = true;
 
                }
 
                else if (reaction3 == null)
 
                {
 
                    r = r - reaction1.Red - reaction2.Red;
 
                    g = g - reaction1.Green - reaction2.Green;
 
                    b = b - reaction1.Blue - reaction2.Blue;
 
                    profile.SetReaction(reagents[1], reagents[2], new Reaction(r, g, b));
 
                    profile.Save();
 
                    saved = true;
 
                }   
 
            }
 
            else if ((reagents[0] != null) && (reagents[1] != null))
 
            {
 
                // A 2-reagent reaction.
 
                r = reactedColor.Red - expectedColor.Red;
 
                g = reactedColor.Green - expectedColor.Green;
 
                b = reactedColor.Blue - expectedColor.Blue;
 
                profile.SetReaction(reagents[0], reagents[1], new Reaction(r, g, b));
 
                profile.Save();
 
                saved = true;
 
            }
 
            return saved;
 
        }
 
    }
 
}
 

	
ReactionStatusWindow.cs
Show inline comments
 
new file 100644
 
using System;
 

	
 
namespace DesertPaintLab
 
{
 
    public partial class ReactionStatusWindow : Gtk.Window
 
    {
 
        //PlayerProfile profile;
 

	
 
        public ReactionStatusWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
 
        {
 
            //this.profile = profile;
 
            this.Build();
 

	
 
            //Gtk.CellRendererText reagentColumnCell = new Gtk.CellRendererText();
 

	
 
            int count = 0;
 
            foreach (string name1 in ReagentManager.Names)
 
            {
 
                Reagent reagent1 = ReagentManager.GetReagent(name1);
 
                foreach (string name2 in ReagentManager.Names)
 
                {
 
                    if (name1.Equals(name2))
 
                    {
 
                        continue;
 
                    }
 
                    Reagent reagent2 = ReagentManager.GetReagent(name2);
 
                    Reaction reaction = profile.FindReaction(reagent1, reagent2);
 
                    if (reaction == null)
 
                    {
 
                        if (count == 0)
 
                        {
 
                            Gtk.Label header = new Gtk.Label("Missing Reactions:");
 
                            resultbox.PackStart(header, false, false, 0);
 
                            Gtk.HSeparator sep = new Gtk.HSeparator();
 
                            resultbox.PackStart(sep, false, false, 0);
 
                        }
 
                        Gtk.Label label = new Gtk.Label(name1 + " + " + name2);
 
                        resultbox.PackStart(label, false, false, 0);
 

	
 
                        ++count;
 
                    }
 
                }
 
            }
 

	
 
            if (count == 0)
 
            {
 
                Gtk.Label header = new Gtk.Label("All reactions recorded!");
 
                resultbox.PackStart(header, false, false, 0);
 
            }
 
            ShowAll();
 
        }
 
    }
 
}
 

	
Reagent.cs
Show inline comments
 
using System;
 

 
namespace DesertPaintLab
 
{
 
	public class Reagent
 
	{ 
 
		string name;
 
		bool isCatalyst = false;
 
        int cost = 0;
 
		PaintColor color;
 
		
 
		public bool IsCatalyst
 
		{
 
			get
 
			{
 
				return isCatalyst;	
 
			}
...
 
@@ -27,26 +28,28 @@ namespace DesertPaintLab
 
		public string Name
 
		{
 
			get
 
			{
 
				return name;	
 
			}
 
		}
 
		
 
		public Reagent(string name)
 
        public Reagent(string name, int cost)
 
		{
 
			this.name = name;
 
            this.cost = cost;
 
			isCatalyst = true;
 
		}
 
		
 
		public Reagent(string name, byte red, byte green, byte blue)
 
        public Reagent(string name, byte red, byte green, byte blue, int cost)
 
		{
 
			color = new PaintColor(red, green, blue);
 
			this.name = name;
 
            this.cost = cost;
 
		}
 
		
 
		public override string ToString()
 
		{
 
			if (isCatalyst)
 
			{
 
				return "[" + name + ", catalyst]";
 
			}
ReagentManager.cs
Show inline comments
...
 
@@ -2,30 +2,39 @@ using System;
 
using System.IO;
 
using System.Collections.Generic;
 
using System.Text.RegularExpressions;
 

 
namespace DesertPaintLab
 
{
 
	public class ReagentManager
 
	{
 
		static Regex reagentRegex = new Regex(@"(?<name>\w+)\s*\|\s*(?<red>\d+),\s*(?<green>\d+),\s*(?<blue>\d+).*");
 
		static Regex catalystRegex = new Regex(@"(?<name>\w+)\s*\|\s*catalyst");
 
		static Regex reagentRegex = new Regex(@"(?<name>\w+)\s*\|\s*(?<red>\d+),\s*(?<green>\d+),\s*(?<blue>\d+)\s*\|\s*(?<cost>\d+)\s*\|.*");
 
		static Regex catalystRegex = new Regex(@"(?<name>\w+)\s*\|\s*catalyst\s*\|\s*(?<cost>\d+)\s*\|.*");
 
		
 
		static SortedDictionary<string,Reagent> reagents = new SortedDictionary<string, Reagent>();
 
        static List<string> names = new List<string>();
 
		
 
		static Gtk.ListStore nameStore = new Gtk.ListStore(typeof(string));
 

 
		static public Gtk.ListStore NameListModel
 
		{
 
			get
 
			{
 
				return nameStore;	
 
			}
 
		}
 

 
        static public List<string> Names
 
        {
 
            get
 
            {
 
                return names;
 
            }
 
        }
 
		
 
		public ReagentManager ()
 
		{
 
			
 
		}
 
		
 
		public static void Load(string file)
 
		{	
...
 
@@ -39,27 +48,31 @@ namespace DesertPaintLab
 
					match = reagentRegex.Match(line); 
 
					if (match.Success)
 
					{
 
						string name = match.Groups["name"].Value;
 
						reagents.Add(name,
 
							new Reagent(name,
 
						        byte.Parse(match.Groups["red"].Value),
 
						    	byte.Parse(match.Groups["green"].Value),
 
						        byte.Parse(match.Groups["blue"].Value)));
 
						        byte.Parse(match.Groups["blue"].Value),
 
                                int.Parse(match.Groups["cost"].Value)));
 
						nameStore.AppendValues(name);
 
                        names.Add(name);
 
					}
 
					else
 
					{
 
						match = catalystRegex.Match(line);
 
						if (match.Success)
 
						{
 
							string name = match.Groups["name"].Value;
 
							reagents.Add(name, new Reagent(name));
 
                            int cost = int.Parse(match.Groups["cost"].Value);
 
							reagents.Add(name, new Reagent(name, cost));
 
							nameStore.AppendValues(name);
 
                            names.Add(name);
 
						}
 
					}
 
                }
 
			}
 
		}
 
		
 
		public static void InitializeReactions(ref SortedDictionary<string, SortedDictionary<string, Reaction>> reactions)
 
		{
...
 
@@ -83,19 +96,19 @@ namespace DesertPaintLab
 
			
 
			Gtk.CellRendererText cell = new Gtk.CellRendererText();
 
	        comboBox.PackStart(cell, false);
 
	        comboBox.AddAttribute(cell, "text", 0);
 
	        Gtk.ListStore store = new Gtk.ListStore(typeof(string));
 
	        comboBox.Model = store;
 
			
 
			store.AppendValues("");
 
			foreach (KeyValuePair<string, Reagent> pair in reagents)
 
            foreach (string name in names)
 
			{
 
				store.AppendValues(pair.Key);
 
				store.AppendValues(name);
 
			}
 
		}
 
		
 
		/*
 
		public static void PopulatePigments(ref Gtk.ComboBox comboBox)
 
		{
 
			comboBox.Clear();
 
			
SimulatorWindow.cs
Show inline comments
...
 
@@ -24,16 +24,17 @@ using System;
 
using System.Collections.Generic;
 

 
namespace DesertPaintLab
 
{
 
	public partial class SimulatorWindow : Gtk.Window
 
	{
 
		PlayerProfile profile;
 
		Gtk.ListStore recipeData = new Gtk.ListStore(typeof(string), typeof(int));
 
        PaintRecipe paintRecipe = new PaintRecipe();
 

 
		public SimulatorWindow(PlayerProfile profile) : base(Gtk.WindowType.Toplevel)
 
		{
 
			this.profile = profile;
 
			this.Build ();
 
			
 
			Gtk.TreeViewColumn reagentColumn = new Gtk.TreeViewColumn();
 
			Gtk.CellRendererText reagentColumnCell = new Gtk.CellRendererText();
...
 
@@ -114,88 +115,46 @@ namespace DesertPaintLab
 

 
		void UpdateRecipeColor()
 
		{
 
			if (recipeView.Children.Length == 0)
 
			{
 
				paintSwatch.Clear();
 
			}
 
			
 
			Reaction reaction;
 
            paintRecipe.Clear();
 

 
			Gtk.TreeIter iter;
 
			string reagentName;
 
			int qty;
 
			PaintColor color = null;
 
			Reagent reagent = null;
 
			
 
			int baseRedSum = 0;
 
			int baseGreenSum = 0;
 
			int baseBlueSum = 0;
 
			
 
			int reactRedSum = 0;
 
			int reactGreenSum = 0;
 
			int reactBlueSum = 0;
 
			
 
			int pigmentCount = 0;
 
			
 
			SortedDictionary<string,bool> reagentSet = new SortedDictionary<string,bool>();
 
			List<Reagent> reagents = new List<Reagent>();
 
			
 
			recipeData.GetIterFirst(out iter);
 
			
 
			do
 
			{
 
   				reagentName = (string) recipeData.GetValue(iter, 0);
 
				
 
				if (reagentName == null)
 
				{
 
					continue;	
 
				}
 
				
 
				qty = (int)recipeData.GetValue(iter, 1);
 
				reagent = ReagentManager.GetReagent(reagentName);
 
				if (!reagent.IsCatalyst)
 
				{
 
					color = reagent.Color;
 
					baseRedSum += qty * color.Red;
 
					baseGreenSum += qty * color.Green;
 
					baseBlueSum += qty * color.Blue;
 
					pigmentCount += qty;
 
				}
 
				if (!reagentSet.ContainsKey(reagentName) && reagentSet.Count <= 4)
 
				{
 
					reagentSet[reagentName] = true;
 
					// Run reactions.
 
					foreach (Reagent otherReagent in reagents)
 
					{
 
						reaction = profile.FindReaction(otherReagent, reagent);
 
						if (reaction != null)
 
						{
 
							reactRedSum += reaction.Red;
 
							reactGreenSum += reaction.Green;
 
							reactBlueSum += reaction.Blue;
 
						}
 
					}
 
					reagents.Add(reagent);
 
				}
 
				
 
                for (int i = 0; i < qty; ++i)
 
                {
 
                    paintRecipe.AddReagent(reagentName);
 
                }
 
			}
 
			while (recipeData.IterNext(ref iter));
 
			
 
			paintSwatch.Color = new PaintColor(
 
				CalculateColor(baseRedSum, pigmentCount, reactRedSum),
 
			    CalculateColor(baseGreenSum, pigmentCount, reactGreenSum),
 
				CalculateColor(baseBlueSum,  pigmentCount, reactBlueSum));	
 
            PaintColor resultColor = new PaintColor();
 
            paintRecipe.ComputeReactedColor(profile, ref resultColor);
 
			paintSwatch.Color = resultColor;	
 
		}
 
		
 
		byte CalculateColor(int baseSum, int pigmentCount, int reactSum)
 
		{
 
			return (byte)Math.Max(Math.Min(Math.Round((((float)baseSum / (float)pigmentCount) + (float)reactSum)), 255), 0);
 
		}
 

 
		protected virtual void OnIncrementReagent (object sender, System.EventArgs e)
 
		{
 
			Gtk.TreeModel model;
 
			Gtk.TreeIter iter;
 

 
			Gtk.TreeSelection selection = recipeView.Selection;
 
			if ((selection != null) && selection.GetSelected(out model, out iter))
 
			{
gtk-gui/DesertPaintLab.ReactionStatusWindow.cs
Show inline comments
 
new file 100644
 

	
 
// This file has been generated by the GUI designer. Do not modify.
 
namespace DesertPaintLab
 
{
 
	public partial class ReactionStatusWindow
 
	{
 
		private global::Gtk.ScrolledWindow scroller;
 
		
 
		private global::Gtk.VBox resultbox;
 

	
 
		protected virtual void Build ()
 
		{
 
			global::Stetic.Gui.Initialize (this);
 
			// Widget DesertPaintLab.ReactionStatusWindow
 
			this.Name = "DesertPaintLab.ReactionStatusWindow";
 
			this.Title = "Reaction Status";
 
			this.WindowPosition = ((global::Gtk.WindowPosition)(4));
 
			// Container child DesertPaintLab.ReactionStatusWindow.Gtk.Container+ContainerChild
 
			this.scroller = new global::Gtk.ScrolledWindow ();
 
			this.scroller.CanFocus = true;
 
			this.scroller.Name = "scroller";
 
			this.scroller.ShadowType = ((global::Gtk.ShadowType)(1));
 
			// Container child scroller.Gtk.Container+ContainerChild
 
			global::Gtk.Viewport w1 = new global::Gtk.Viewport ();
 
			w1.ShadowType = ((global::Gtk.ShadowType)(0));
 
			// Container child GtkViewport.Gtk.Container+ContainerChild
 
			this.resultbox = new global::Gtk.VBox ();
 
			this.resultbox.Name = "resultbox";
 
			this.resultbox.Spacing = 6;
 
			w1.Add (this.resultbox);
 
			this.scroller.Add (w1);
 
			this.Add (this.scroller);
 
			if ((this.Child != null)) {
 
				this.Child.ShowAll ();
 
			}
 
			this.DefaultWidth = 400;
 
			this.DefaultHeight = 300;
 
			this.Show ();
 
		}
 
	}
 
}
gtk-gui/MainWindow.cs
Show inline comments
...
 
@@ -22,16 +22,20 @@ public partial class MainWindow
 
	private global::Gtk.Action WindowAction;
 
	
 
	private global::Gtk.Action RunSimulatorAction;
 
	
 
	private global::Gtk.Action DebugAction;
 
	
 
	private global::Gtk.Action ScreenshotAction;
 
	
 
	private global::Gtk.Action RecipeGeneratorAction;
 
	
 
	private global::Gtk.Action ReactionStatusAction;
 
	
 
	private global::Gtk.VBox vbox1;
 
	
 
	private global::Gtk.MenuBar menubar1;
 
	
 
	private global::Gtk.HBox hbox1;
 
	
 
	private global::Gtk.Frame frame2;
 
	
...
 
@@ -119,26 +123,32 @@ public partial class MainWindow
 
		this.RunSimulatorAction.ShortLabel = "_Run Simulator";
 
		w1.Add (this.RunSimulatorAction, null);
 
		this.DebugAction = new global::Gtk.Action ("DebugAction", "Debug", null, null);
 
		this.DebugAction.ShortLabel = "Debug";
 
		w1.Add (this.DebugAction, null);
 
		this.ScreenshotAction = new global::Gtk.Action ("ScreenshotAction", "Screenshot", null, null);
 
		this.ScreenshotAction.ShortLabel = "Screenshot";
 
		w1.Add (this.ScreenshotAction, null);
 
		this.RecipeGeneratorAction = new global::Gtk.Action ("RecipeGeneratorAction", "Recipe Generator", null, null);
 
		this.RecipeGeneratorAction.ShortLabel = "Recipe Generator";
 
		w1.Add (this.RecipeGeneratorAction, null);
 
		this.ReactionStatusAction = new global::Gtk.Action ("ReactionStatusAction", "Reaction Status", null, null);
 
		this.ReactionStatusAction.ShortLabel = "Reaction Status";
 
		w1.Add (this.ReactionStatusAction, null);
 
		this.UIManager.InsertActionGroup (w1, 0);
 
		this.AddAccelGroup (this.UIManager.AccelGroup);
 
		this.Name = "MainWindow";
 
		this.Title = "Desert Paint Lab";
 
		this.WindowPosition = ((global::Gtk.WindowPosition)(4));
 
		// Container child MainWindow.Gtk.Container+ContainerChild
 
		this.vbox1 = new global::Gtk.VBox ();
 
		this.vbox1.Name = "vbox1";
 
		// Container child vbox1.Gtk.Box+BoxChild
 
		this.UIManager.AddUiFromString ("<ui><menubar name='menubar1'><menu name='FileAction' action='FileAction'><menuitem name='NewProfileAction' action='NewProfileAction'/><menuitem name='OpenProfileAction' action='OpenProfileAction'/><menuitem name='ExportForPracticalPaintAction' action='ExportForPracticalPaintAction'/><separator/><menuitem name='ExitAction' action='ExitAction'/></menu><menu name='WindowAction' action='WindowAction'><menuitem name='RunSimulatorAction' action='RunSimulatorAction'/></menu><menu name='HelpAction' action='HelpAction'><menuitem name='AboutAction' action='AboutAction'/></menu><menu name='DebugAction' action='DebugAction'><menuitem name='ScreenshotAction' action='ScreenshotAction'/></menu></menubar></ui>");
 
		this.UIManager.AddUiFromString ("<ui><menubar name='menubar1'><menu name='FileAction' action='FileAction'><menuitem name='NewProfileAction' action='NewProfileAction'/><menuitem name='OpenProfileAction' action='OpenProfileAction'/><menuitem name='ExportForPracticalPaintAction' action='ExportForPracticalPaintAction'/><separator/><menuitem name='ExitAction' action='ExitAction'/></menu><menu name='WindowAction' action='WindowAction'><menuitem name='RunSimulatorAction' action='RunSimulatorAction'/><menuitem name='RecipeGeneratorAction' action='RecipeGeneratorAction'/></menu><menu name='HelpAction' action='HelpAction'><menuitem name='AboutAction' action='AboutAction'/><menuitem name='ReactionStatusAction' action='ReactionStatusAction'/></menu><menu name='DebugAction' action='DebugAction'><menuitem name='ScreenshotAction' action='ScreenshotAction'/></menu></menubar></ui>");
 
		this.menubar1 = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menubar1")));
 
		this.menubar1.Name = "menubar1";
 
		this.vbox1.Add (this.menubar1);
 
		global::Gtk.Box.BoxChild w2 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.menubar1]));
 
		w2.Position = 0;
 
		w2.Expand = false;
 
		w2.Fill = false;
 
		// Container child vbox1.Gtk.Box+BoxChild
...
 
@@ -359,15 +369,17 @@ public partial class MainWindow
 
		this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent);
 
		this.AboutAction.Activated += new global::System.EventHandler (this.OnAbout);
 
		this.NewProfileAction.Activated += new global::System.EventHandler (this.OnNewProfile);
 
		this.OpenProfileAction.Activated += new global::System.EventHandler (this.OnOpenProfile);
 
		this.ExitAction.Activated += new global::System.EventHandler (this.OnMenuExit);
 
		this.ExportForPracticalPaintAction.Activated += new global::System.EventHandler (this.OnExport);
 
		this.RunSimulatorAction.Activated += new global::System.EventHandler (this.RunSimulator);
 
		this.ScreenshotAction.Activated += new global::System.EventHandler (this.OnDebugScreenshot);
 
		this.RecipeGeneratorAction.Activated += new global::System.EventHandler (this.OnOpenRecipeGenerator);
 
		this.ReactionStatusAction.Activated += new global::System.EventHandler (this.OnShowReactionStatus);
 
		this.ingredient1ComboBox.Changed += new global::System.EventHandler (this.OnChangedIngredient1);
 
		this.ingredient2ComboBox.Changed += new global::System.EventHandler (this.OnChangedIngredient2);
 
		this.ingredient3ComboBox.Changed += new global::System.EventHandler (this.OnChangedIngredient3);
 
		this.captureButton.Clicked += new global::System.EventHandler (this.OnCaptureButton);
 
		this.saveButton.Clicked += new global::System.EventHandler (this.OnSaveButton);
 
	}
 
}
gtk-gui/gui.stetic
Show inline comments
...
 
@@ -73,16 +73,28 @@
 
        <property name="ShortLabel" translatable="yes">Debug</property>
 
      </action>
 
      <action id="ScreenshotAction">
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">Screenshot</property>
 
        <property name="ShortLabel" translatable="yes">Screenshot</property>
 
        <signal name="Activated" handler="OnDebugScreenshot" />
 
      </action>
 
      <action id="RecipeGeneratorAction">
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">Recipe Generator</property>
 
        <property name="ShortLabel" translatable="yes">Recipe Generator</property>
 
        <signal name="Activated" handler="OnOpenRecipeGenerator" />
 
      </action>
 
      <action id="ReactionStatusAction">
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">Reaction Status</property>
 
        <property name="ShortLabel" translatable="yes">Reaction Status</property>
 
        <signal name="Activated" handler="OnShowReactionStatus" />
 
      </action>
 
    </action-group>
 
    <property name="MemberName" />
 
    <property name="Title" translatable="yes">Desert Paint Lab</property>
 
    <property name="WindowPosition">CenterOnParent</property>
 
    <signal name="DeleteEvent" handler="OnDeleteEvent" />
 
    <child>
 
      <widget class="Gtk.VBox" id="vbox1">
 
        <property name="MemberName" />
...
 
@@ -94,19 +106,21 @@
 
                <node type="Menuitem" action="NewProfileAction" />
 
                <node type="Menuitem" action="OpenProfileAction" />
 
                <node type="Menuitem" action="ExportForPracticalPaintAction" />
 
                <node type="Separator" />
 
                <node type="Menuitem" action="ExitAction" />
 
              </node>
 
              <node type="Menu" action="WindowAction">
 
                <node type="Menuitem" action="RunSimulatorAction" />
 
                <node type="Menuitem" action="RecipeGeneratorAction" />
 
              </node>
 
              <node type="Menu" action="HelpAction">
 
                <node type="Menuitem" action="AboutAction" />
 
                <node type="Menuitem" action="ReactionStatusAction" />
 
              </node>
 
              <node type="Menu" action="DebugAction">
 
                <node type="Menuitem" action="ScreenshotAction" />
 
              </node>
 
            </node>
 
          </widget>
 
          <packing>
 
            <property name="Position">0</property>
...
 
@@ -1081,9 +1095,42 @@ You can either import an existing Practi
 
          <packing>
 
            <property name="Expand">False</property>
 
            <property name="Fill">False</property>
 
          </packing>
 
        </child>
 
      </widget>
 
    </child>
 
  </widget>
 
  <widget class="Gtk.Window" id="DesertPaintLab.ReactionStatusWindow" design-size="400 300">
 
    <property name="MemberName" />
 
    <property name="Title" translatable="yes">Reaction Status</property>
 
    <property name="WindowPosition">CenterOnParent</property>
 
    <child>
 
      <widget class="Gtk.ScrolledWindow" id="scroller">
 
        <property name="MemberName" />
 
        <property name="CanFocus">True</property>
 
        <property name="ShadowType">In</property>
 
        <child>
 
          <widget class="Gtk.Viewport" id="GtkViewport">
 
            <property name="MemberName" />
 
            <property name="ShadowType">None</property>
 
            <child>
 
              <widget class="Gtk.VBox" id="resultbox">
 
                <property name="MemberName" />
 
                <property name="Spacing">6</property>
 
                <child>
 
                  <placeholder />
 
                </child>
 
                <child>
 
                  <placeholder />
 
                </child>
 
                <child>
 
                  <placeholder />
 
                </child>
 
              </widget>
 
            </child>
 
          </widget>
 
        </child>
 
      </widget>
 
    </child>
 
  </widget>
 
</stetic-interface>
...
 
\ No newline at end of file
mac/Info.plist
Show inline comments
 
new file 100644
 
<?xml version="1.0" encoding="UTF-8"?>
 
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 
<plist version="1.0">
 
<dict>
 
	<key>CFBundleDevelopmentRegion</key>
 
	<string>English</string>
 
	<key>CFBundleExecutable</key>
 
	<string>launcher.sh</string>
 
	<key>CFBundleIconFile</key>
 
	<string>DesertPaintLab.icns</string>
 
	<key>CFBundleIdentifier</key>
 
	<string>org.malkyne.desert-paint-lab</string>
 
	<key>CFBundleInfoDictionaryVersion</key>
 
	<string>6.0</string>
 
	<key>CFBundleName</key>
 
	<string>Desert Paint Lab</string>
 
	<key>CFBundlePackageType</key>
 
	<string>APPL</string>
 
	<key>CFBundleShortVersionString</key>
 
	<string>1.7.4</string>
 
	<key>CFBundleSignature</key>
 
	<string>xmmd</string>
 
	<key>CFBundleVersion</key>
 
	<string>1.7.4</string>
 
	<key>NSAppleScriptEnabled</key>
 
	<string>NO</string>
 
</dict>
 
</plist>
mac/build_mac_bundle.sh
Show inline comments
 
new file 100644
 
#!/bin/sh
 

	
 
/bin/mv DesertPaintLab.app DesertPaintLab.app.`/bin/date +"%Y%m%d%H%M%S"`
 
/bin/mkdir -p DesertPaintLab.app
 
/bin/cp Info.plist DesertPaintLab.app/Info.plist
 
/bin/mkdir -p DesertPaintLab.app/Contents/MacOS
 
/bin/cp launcher.sh DesertPaintLab.app/Contents/MacOS
 
/bin/chmod 755 DesertPaintLab.app/Contents/MacOS/launcher.sh
 
/bin/cp ../bin/Release/DesertPaintLab.exe DesertPaintLab.app/Contents/MacOS/
 
/bin/mkdir -p DesertPaintLab.app/Contents/Resources
 
/bin/cp ../bin/Release/colors.txt DesertPaintLab.app/Contents/Resources/
 
/bin/cp -r ../bin/Release/template DesertPaintLab.app/Contents/Resources/template
mac/launcher.sh
Show inline comments
 
new file 100755
 
#!/bin/sh
 

	
 
APPNAME="DesertPaintLab"
 

	
 
DIR=$(cd "$(dirname "$0")"; pwd)
 

	
 
EXE_PATH="$DIR\DesertPaintLab.exe"
 
PROCESS_NAME=desertpaintlab
 

	
 
MONO_FRAMEWORK_PATH=/Library/Frameworks/Mono.framework/Versions/Current
 
export DYLD_FALLBACK_LIBRARY_PATH="$DIR:$MONO_FRAMEWORK_PATH/lib:/lib:/usr/lib"
 
export PATH="$MONO_FRAMEWORK_PATH/bin:$PATH"
 
 
 
#mono version check
 
 
 
REQUIRED_MAJOR=4
 
REQUIRED_MINOR=0
 
 
 
VERSION_TITLE="Cannot launch $APPNAME"
 
VERSION_MSG="$APPNAME requires the Mono Framework version $REQUIRED_MAJOR.$REQUIRED_MINOR or later."
 
DOWNLOAD_URL="http://www.go-mono.com/mono-downloads/download.html"
 
 
 
MONO_VERSION="$(mono --version | grep 'Mono JIT compiler version ' |  cut -f5 -d\ )"
 
MONO_VERSION_MAJOR="$(echo $MONO_VERSION | cut -f1 -d.)"
 
MONO_VERSION_MINOR="$(echo $MONO_VERSION | cut -f2 -d.)"
 
if [ -z "$MONO_VERSION" ] \
 
	|| [ $MONO_VERSION_MAJOR -lt $REQUIRED_MAJOR ] \
 
	|| [ $MONO_VERSION_MAJOR -eq $REQUIRED_MAJOR -a $MONO_VERSION_MINOR -lt $REQUIRED_MINOR ] 
 
then
 
	/usr/bin/osascript \
 
		-e "set question to display dialog \"$VERSION_MSG\" with title \"$VERSION_TITLE\" buttons {\"Cancel\", \"Download...\"} default button 2" \
 
		-e "if button returned of question is equal to \"Download...\" then open location \"$DOWNLOAD_URL\""
 
	echo "$VERSION_TITLE"
 
	echo "$VERSION_MSG"
 
	exit 1
 
fi
 

	
 
OSX_VERSION=$(uname -r | cut -f1 -d.)
 
if [ $OSX_VERSION -lt 9 ]; then  # If OSX version is 10.4
 
	MONO_EXEC="exec mono"
 
else
 
	MONO_EXEC="exec -a \"$PROCESS_NAME\" mono"
 
fi
 

	
 
LOG_FILE="$HOME/Library/Logs/$APPNAME/$APPNAME.log"
 
/bin/mkdir -p "`dirname \"$LOG_FILE\"`"
 
$MONO_EXEC $MONO_OPTIONS "$EXE_PATH" $* 2>&1 1> "$LOG_FILE"
 

	
0 comments (0 inline, 0 general)