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
...
 
@@ -57,30 +57,35 @@
 
    <Compile Include="NewProfileDialog.cs" />
 
    <Compile Include="PaintSwatch.cs" />
 
    <Compile Include="Palette.cs" />
 
    <Compile Include="PaintColor.cs" />
 
    <Compile Include="Reaction.cs" />
 
    <Compile Include="ReagentManager.cs" />
 
    <Compile Include="Reagent.cs" />
 
    <Compile Include="gtk-gui\MainWindow.cs" />
 
    <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" />
 
        </Policies>
 
        <GtkDesignInfo generateGettext="False" />
 
      </Properties>
 
    </MonoDevelop>
 
  </ProjectExtensions>
 
</Project>
...
 
\ No newline at end of file
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
...
 
@@ -42,70 +42,71 @@ public partial class MainWindow : Gtk.Wi
 
	bool shouldShutDown = false;
 
	string appDataPath;
 
	List<string> profileList = new List<string>();
 
	PlayerProfile profile = null;
 
	PaintColor expectedColor = new PaintColor();
 
	PaintColor reactedColor = new PaintColor();
 
	
 
	int screenWidth = 0;
 
	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),
 
		    "DesertPaintLab");
 
		
 
		if (!System.IO.Directory.Exists(appDataPath))
 
		{
 
			System.IO.Directory.CreateDirectory(appDataPath);	
 
		}
 
		
 
		DirectoryInfo di = new DirectoryInfo(appDataPath);
 
		DirectoryInfo[] dirs = di.GetDirectories();
 
		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)
 
		{
 
			reactionSwatch.Clear();
 
		}
 

	
 
		// get the root window
 
		rootWindow = Gdk.Global.DefaultRootWindow;
 

	
 
		// get its width and height
...
 
@@ -372,342 +373,204 @@ public partial class MainWindow : Gtk.Wi
 
		expectedColor.Red = red;
 
		expectedColor.Green = green;
 
		expectedColor.Blue = blue;
 
		unmodifiedSwatch.Color = expectedColor;
 
	}
 
	
 
	protected void SetExpectedColor(PaintColor color)
 
	{
 
		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();	
 
				}
 
			}
 
		}
 
	}
 
	
 
	protected void OnDeleteEvent(object sender, DeleteEventArgs a)
 
	{
 
		if (ConfirmedExit())
 
		{
 
			a.RetVal = true;
 
			Application.Quit();
 
		}
 
		else
 
		{
 
			a.RetVal = false;
 
		}
 
	}
 
	
 
	bool IsPapyTexture(byte r, byte g, byte b)
 
	{
 
		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
 
        {
 
            ++i;
 
            filename = System.IO.Path.Combine(screenshotDir, String.Format("DesertPaintLab_{0}.png", i));
 
        } while (System.IO.File.Exists(filename));
 
        screenBuffer.Save(filename, "png");
 
    }
 

	
 
	protected virtual void OnCaptureButton(object sender, System.EventArgs e)
...
 
@@ -761,73 +624,36 @@ public partial class MainWindow : Gtk.Wi
 
		else
 
		{
 
			MessageDialog md = new MessageDialog(this, 
 
	            DialogFlags.DestroyWithParent,
 
	            MessageType.Error, ButtonsType.Ok, 
 
	            "Pigment Lab dialog box NOT FOUND.  Please ensure " +
 
	            "that there is an unobstructed view of the dialog " +
 
	            "when you press the Capture button.");
 
	   
 
			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)
 
	{
 
		UpdateIngredients();
 
	}
 
	
 
	protected virtual void OnChangedIngredient3(object sender, System.EventArgs e)
 
	{
 
		UpdateIngredients();
 

	
...
 
@@ -871,32 +697,38 @@ public partial class MainWindow : Gtk.Wi
 
			profileSelected = true;
 
		}
 
		else if (resp == ResponseType.Accept) // New profile.
 
		{
 
			profileSelected = NewProfile();
 
		}
 
		if (profileSelected)
 
		{
 
			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())
 
		{
 
			Application.Quit();
 
		}
 
	}
 
	
 
	protected virtual void OnExport(object sender, System.EventArgs e)
 
	{
 
		FileChooserDialog fileDialog =
 
			new FileChooserDialog("Select destination file.",
...
 
@@ -906,21 +738,28 @@ public partial class MainWindow : Gtk.Wi
 
		ResponseType resp = (ResponseType)fileDialog.Run();
 
		if (resp == ResponseType.Accept)
 
		{
 
			string fileName = fileDialog.Filename;
 
			string directory = fileDialog.CurrentFolder;
 
			profile.Export(System.IO.Path.Combine(directory, fileName));
 
		}
 
		fileDialog.Destroy();
 
	}
 
	
 
	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
...
 
@@ -35,36 +35,38 @@ namespace DesertPaintLab
 
		SortedDictionary<string, SortedDictionary<string, Reaction>> reactions =
 
			new SortedDictionary<string, SortedDictionary<string, Reaction>>();
 
		
 
		public PlayerProfile(string name, string directory)
 
		{
 
			this.name = name;
 
			this.directory = directory;
 
			this.reactFile = System.IO.Path.Combine(directory, "dp_reactions.txt");
 
		}
 
		
 
		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);					
 
			}
 
		}
 
		
 
		public void ConvertFromPP(string ppFile, string dpFile)
 
		{
 
			string line;
 
			using (StreamReader reader = new StreamReader(ppFile))
 
			{
 
				using (StreamWriter writer = new StreamWriter(dpFile))
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;	
 
			}
 
		}
 
		
 
		public PaintColor Color
 
		{
 
			get
 
			{
 
				return color;	
 
			}
 
		}
 
		
 
		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]";
 
			}
 
			else
 
			{
 
				return "[" + name + ", " + color.ToString() + "]";
 
			}
 
		}
 
		
 
		
 
	}
ReagentManager.cs
Show inline comments
 
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)
 
		{	
 
			Match match;
 
			string line;
 
			reagents.Clear();
 
			using (StreamReader reader = new StreamReader(file))
 
			{
 
				while ((line = reader.ReadLine()) != null) 
 
                {
 
					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)
 
		{
 
			foreach (KeyValuePair<string, Reagent> pair1 in reagents)
 
			{
 
				SortedDictionary<string, Reaction> dict = new SortedDictionary<string, Reaction>();
 
				foreach (KeyValuePair<string, Reagent> pair2 in reagents)
 
				{
 
					if (pair1.Key != pair2.Key)
 
					{
 
						dict.Add(pair2.Key, null);
...
 
@@ -75,35 +88,35 @@ namespace DesertPaintLab
 
				}
 
				reactions.Add(pair1.Key, dict);
 
			}
 
		}
 
		
 
		public static void PopulateReagents(ref Gtk.ComboBox comboBox)
 
		{
 
			comboBox.Clear();
 
			
 
			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();
 
			
 
			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)
SimulatorWindow.cs
Show inline comments
...
 
@@ -16,32 +16,33 @@
 
 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.
 
*/
 

 
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();
 
			reagentColumn.PackStart(reagentColumnCell, true);		
 
			reagentColumn.Title = "Ingredient";
 
			
 
			reagentListView.AppendColumn(reagentColumn);
 
			reagentColumn.AddAttribute(reagentColumnCell, "text", 0);
 
			
 
			reagentListView.Model = ReagentManager.NameListModel;
 
			
...
 
@@ -106,104 +107,62 @@ namespace DesertPaintLab
 
            	recipeData.SetValue(iter, 1, oldValue);
 
			}
 
        }	
 
	
 
		protected void OnRecipeChanged(object sender, GLib.SignalArgs args)
 
	    {
 
			UpdateRecipeColor();
 
	    }	
 

 
		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))
 
			{
 
				int oldValue = (int)recipeData.GetValue(iter, 1);
 
				recipeData.SetValue(iter, 1, oldValue + 1);
 
			}
 
			
 
		}
 
		
 
		protected virtual void OnDecrementReagent (object sender, System.EventArgs e)
 
		{
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
...
 
@@ -14,32 +14,36 @@ public partial class MainWindow
 
	private global::Gtk.Action NewProfileAction;
 
	
 
	private global::Gtk.Action OpenProfileAction;
 
	
 
	private global::Gtk.Action ExitAction;
 
	
 
	private global::Gtk.Action ExportForPracticalPaintAction;
 
	
 
	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;
 
	
 
	private global::Gtk.Alignment GtkAlignment;
 
	
 
	private global::Gtk.VBox vbox3;
 
	
 
	private global::Gtk.HBox hbox6;
 
	
 
	private global::Gtk.Label label4;
 
	
...
 
@@ -111,42 +115,48 @@ public partial class MainWindow
 
		w1.Add (this.ExitAction, "<Alt>x");
 
		this.ExportForPracticalPaintAction = new global::Gtk.Action ("ExportForPracticalPaintAction", "Export for _PracticalPaint...", null, null);
 
		this.ExportForPracticalPaintAction.ShortLabel = "Export for _PracticalPaint...";
 
		w1.Add (this.ExportForPracticalPaintAction, null);
 
		this.WindowAction = new global::Gtk.Action ("WindowAction", "_Window", null, null);
 
		this.WindowAction.ShortLabel = "_Window";
 
		w1.Add (this.WindowAction, null);
 
		this.RunSimulatorAction = new global::Gtk.Action ("RunSimulatorAction", "_Run Simulator", null, null);
 
		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
 
		this.hbox1 = new global::Gtk.HBox ();
 
		this.hbox1.Name = "hbox1";
 
		this.hbox1.Spacing = 6;
 
		this.hbox1.BorderWidth = ((uint)(4));
 
		// Container child hbox1.Gtk.Box+BoxChild
 
		this.frame2 = new global::Gtk.Frame ();
 
		this.frame2.Name = "frame2";
 
		this.frame2.BorderWidth = ((uint)(4));
...
 
@@ -351,23 +361,25 @@ public partial class MainWindow
 
		w26.Fill = false;
 
		this.Add (this.vbox1);
 
		if ((this.Child != null)) {
 
			this.Child.ShowAll ();
 
		}
 
		this.DefaultWidth = 629;
 
		this.DefaultHeight = 265;
 
		this.Show ();
 
		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
...
 
@@ -65,56 +65,70 @@
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">_Run Simulator</property>
 
        <property name="ShortLabel" translatable="yes">_Run Simulator</property>
 
        <signal name="Activated" handler="RunSimulator" />
 
      </action>
 
      <action id="DebugAction">
 
        <property name="Type">Action</property>
 
        <property name="Label" translatable="yes">Debug</property>
 
        <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" />
 
        <child>
 
          <widget class="Gtk.MenuBar" id="menubar1">
 
            <property name="MemberName" />
 
            <node name="menubar1" type="Menubar">
 
              <node type="Menu" action="FileAction">
 
                <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>
 
            <property name="AutoSize">True</property>
 
            <property name="Expand">False</property>
 
            <property name="Fill">False</property>
 
          </packing>
 
        </child>
 
        <child>
 
          <widget class="Gtk.HBox" id="hbox1">
 
            <property name="MemberName" />
...
 
@@ -1073,17 +1087,50 @@ You can either import an existing Practi
 
            <property name="CanDefault">True</property>
 
            <property name="CanFocus">True</property>
 
            <property name="UseStock">True</property>
 
            <property name="Type">StockItem</property>
 
            <property name="StockId">gtk-ok</property>
 
            <property name="ResponseId">-5</property>
 
            <property name="label">gtk-ok</property>
 
          </widget>
 
          <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)