Changeset - eee2a6a0c86b
[Not reviewed]
default
0 3 0
Jason Maltzen (jmaltzen) - 9 years ago 2016-03-04 06:23:05
jason.maltzen@unsanctioned.net
Loosen checks on testing for papyrus texture some more. Allow for a bit of error there, as long as everything else checks out.
3 files changed with 20 insertions and 17 deletions:
0 comments (0 inline, 0 general)
MainWindow.cs
Show inline comments
 
/*
 
 * Copyright (c) 2010, Tess Snider
 

	
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 
 of this software and associated documentation files (the "Software"), to deal
 
 in the Software without restriction, including without limitation the rights
 
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
 copies of the Software, and to permit persons to whom the Software is
 
 furnished to do so, subject to the following conditions:
 

	
 
 The above copyright notice and this permission notice shall be included in
 
 all copies or substantial portions of the Software.
 

	
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 THE SOFTWARE.
 
*/
 

	
 
using System;
 
using System.IO;
 
using System.Collections.Generic;
 
using System.Text.RegularExpressions;
 
using Gtk;
 
using DesertPaintLab;
 

	
 
public partial class MainWindow : Gtk.Window
 
{
 
    const string APP_VERSION = "1.7.13";
 
    const string APP_VERSION = "1.7.14";
 

	
 
	bool unsavedData = false;
 
	bool shouldShutDown = false;
 
	List<string> profileList = new List<string>();
 
	PlayerProfile profile = null;
 
	
 
	Gdk.Window rootWindow = null;
 
	Gdk.Pixbuf screenBuffer = null;
 

	
 
    // views
 
    RecipeGeneratorView generatorView;
 
    SimulatorView simulatorView;
 
    CaptureView captureView;
 

	
 
	public bool ShouldShutDown
 
	{
 
		get
 
		{
 
			return shouldShutDown;
 
		}
 
	}
 
	
 
	public MainWindow () : base(Gtk.WindowType.Toplevel)
 
	{
 
        string appDataPath = FileUtils.AppDataPath;
 
		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);
 
			}
 
		}
 

	
 
        string colorsPath = FileUtils.FindApplicationResourceFile("colors.txt");
 
        if (colorsPath == null)
 
        {
 
            // failed to find colors.txt file
 
            MessageDialog md = new MessageDialog(this, 
 
                DialogFlags.DestroyWithParent,
 
                MessageType.Error, ButtonsType.Close, 
 
                "Failed to find colors.txt file. Please check your installation.");
ReactionRecorder.cs
Show inline comments
...
 
@@ -51,188 +51,191 @@ namespace DesertPaintLab
 
        {
 
            // red between 208 and 244
 
            // green between 192 and 237
 
            // blue between 145 and 205
 
            return ((r > 0xD0) && (g >= 0xC0) && (b >= 0x91)) &&
 
                   ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD));
 
        }
 

	
 
        public static void SetPixelMultiplier(int pixelMultiplier)
 
        {
 
            swatchHeight    = DEFAULT_SWATCH_HEIGHT * pixelMultiplier;
 
            swatchWidth     = DEFAULT_SWATCH_WIDTH * pixelMultiplier;
 
            colorBarWidth   = DEFAULT_COLOR_BAR_WIDTH * pixelMultiplier;
 
            redBarSpacing   = DEFAULT_RED_BAR_SPACING * pixelMultiplier;
 
            greenBarSpacing = DEFAULT_GREEN_BAR_SPACING * pixelMultiplier;
 
            blueBarSpacing  = DEFAULT_BLUE_BAR_SPACING * pixelMultiplier;
 
            swatchTestWidth = DEFAULT_SWATCH_TEST_WIDTH * pixelMultiplier;
 
            ReactionRecorder.pixelMultiplier = pixelMultiplier;
 
        }
 

	
 
        unsafe private static void ColorAt(byte *pixBytes, int x, int y, int stride, out byte r, out byte g, out byte b)
 
        {
 
            int pixelStart = (y * stride) + (x * 3);
 
                    r = pixBytes[pixelStart];
 
                    g = pixBytes[pixelStart + 1];
 
                    b = pixBytes[pixelStart + 2];
 
        }
 

	
 
        private static bool IsDarkPixel(int r, int g, int b)
 
        {
 
            return ((r < 0x46) && (g < 0x46) && (b < 0x47));
 
        }
 

	
 
        private static bool IsColorMatch(byte test_r, byte test_g, byte test_b, byte target_r, byte target_g, byte target_b)
 
        {
 
            return ((Math.Abs(test_r - target_r) <= COLOR_TOLERANCE) &&
 
                (Math.Abs(test_g - target_g) <= COLOR_TOLERANCE) &&
 
                (Math.Abs(test_b - target_b) <= COLOR_TOLERANCE));
 
        }
 

	
 
        unsafe private static bool IsPossibleSwatchSlice(byte* pixBytes, int x, int y, int stride)
 
        {
 
            int testPixelStart = (y * stride) + (x * 3);
 
            byte r = pixBytes[testPixelStart];
 
            byte g = pixBytes[testPixelStart+1];
 
            byte b = pixBytes[testPixelStart+2];
 

	
 
            bool isDarkPixel = false;
 
            bool isPapyAbove = false;
 
            bool isPapyBelow = false;
 
            //bool isPapyAbove = false;
 
            //bool isPapyBelow = false;
 

	
 
            // 1.) Check if the top pixel is a dark pixel.
 
            isDarkPixel = IsDarkPixel(r, g, b); // ((r < 0x46) && (g < 0x46) && (b < 0x46));
 
            
 
            // 2.) Check the pixel above it to see if it's from the papy texture.
 
            int otherPixelStart = testPixelStart - stride;
 
            isPapyAbove = ((otherPixelStart >= 0) &&
 
                IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart]));
 
            //// 2.) Check the pixel above it to see if it's from the papy texture.
 
            //int otherPixelStart = testPixelStart - stride;
 
            //isPapyAbove = ((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 = testPixelStart + (stride * swatchHeight);
 
            isPapyBelow = (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 = testPixelStart + (stride * swatchHeight);
 
            //isPapyBelow = (IsPapyTexture(pixBytes[otherPixelStart++], pixBytes[otherPixelStart++], pixBytes[otherPixelStart]));
 

	
 
            bool result = isDarkPixel && isPapyAbove && isPapyBelow;
 
            //bool result = isDarkPixel && isPapyAbove && isPapyBelow;
 
            bool result = isDarkPixel;
 

	
 
            // grab the swatch color
 
            int swatchColorStart = testPixelStart + (2 * pixelMultiplier * stride); // 2 rows below the test pixel, skipping the faded color
 
            r = pixBytes[swatchColorStart];
 
            g = pixBytes[swatchColorStart+1];
 
            b = pixBytes[swatchColorStart+2];
 

	
 
            // scan the column from 2 below the top to 2 above the bottom to ensure the color matches
 
            for (int i = (2*pixelMultiplier); result && (i < swatchHeight-(2*pixelMultiplier)); ++i)
 
            {
 
                otherPixelStart = testPixelStart + (stride * i);
 
                int otherPixelStart = testPixelStart + (stride * i);
 
                result &= IsColorMatch(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2], r, g, b);
 
            }
 

	
 
            return result;
 
        }
 

	
 
        unsafe private static bool IsPossibleSwatchUpperLeft(byte* pixBytes, int x, int y, int stride)
 
        {
 
            int testPixelStart = (y * stride) + (x * 3);
 

	
 
            bool result = true;
 
            // test the left edge for dark pixels
 
            for (int i = 0; result && (i < swatchHeight-pixelMultiplier); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (stride * i);
 
                result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
            }
 

	
 
            // test the dark top border and for papyrus below the swatch
 
            // test the dark top border and for papyrus above and below the swatch
 
            int papyErrorCount = 0;
 
            for (int i = 0; result && (i < swatchWidth); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (3 * i);
 
                result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
                otherPixelStart = otherPixelStart - stride;
 
                result &= IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 1 : 0);
 
                otherPixelStart = testPixelStart + (stride * swatchHeight) + (3 * i);
 
                result &= IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
                papyErrorCount += (IsPapyTexture(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]) ? 1 : 0);
 
                result &= (papyErrorCount < (swatchWidth / 20)); // allow up to 5% error rate checking for papy texture, because this seems to be inconsistent
 
            }
 

	
 
            return result;
 
        }
 

	
 
        unsafe public static bool CaptureReaction(byte* pixBytes, int screenshotWidth, int screenshotHeight, int stride, ref PaintColor reactedColor, ref int redPixelStart)
 
        {
 
            byte pixel_r, pixel_g, pixel_b;
 
            int pixelStart, otherPixelStart;
 
            bool colorMatch = true;
 
            for (int x = 0; x < screenshotWidth - colorBarWidth; ++x)
 
            {
 
                for (int y = 0; y < (screenshotHeight - (blueBarSpacing + 1)  /*53*/); ++y)
 
                {
 
                    // Look for the color swatch.
 
                    pixelStart = (y * stride) + (x * 3);
 
                    pixel_r = pixBytes[pixelStart];
 
                    pixel_g = pixBytes[pixelStart + 1];
 
                    pixel_b = pixBytes[pixelStart + 2];
 
                    
 
                    bool foundSwatch = IsPossibleSwatchUpperLeft(pixBytes, x, y, stride); // ((pixel_r < 0x46) && (pixel_g < 0x46) && (pixel_b < 0x46));
 
                    if (foundSwatch)
 
                    {
 
                        int borderXOffset = 0;
 
                        for (borderXOffset = (2 * pixelMultiplier); foundSwatch && (borderXOffset < swatchTestWidth); ++borderXOffset)
 
                        {
 
                            foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + borderXOffset, y, stride);
 
                            foundSwatch &= IsPossibleSwatchSlice(pixBytes, x + swatchWidth - borderXOffset, y, stride);
 
                        }
 
                    }
 

	
 
                    if (foundSwatch)
 
                    {
 
                        // found a swatch with an appropriate dark top border with papyrus texture above it and papyrus a jump below it
 
                        // 4.) Scan the left border of the potential swatch
 
                        // location.
 
                        colorMatch = true;
 
                        for (int i = 1; i < swatchHeight - 2; ++i)
 
                        for (int i = 2; i < swatchHeight - (2 * pixelMultiplier); ++i)
 
                        {
 
                            otherPixelStart = pixelStart + (stride * i);
 
                            if (!IsColorMatch(pixel_r, pixel_g, pixel_b, pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]))
 
                            {
 
                                colorMatch = false;
 
                                break;
 
                            }
 
                        }
 
                        
 
                        if (colorMatch)
 
                        {
 
                            // WE FOUND THE SWATCH!
 
                            // Now we know where the color bars are.
 
                            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))
gtk-gui/MainWindow.cs
Show inline comments
...
 
@@ -47,97 +47,97 @@ public partial class MainWindow
 
	
 
	private global::Gtk.VBox vbox1;
 
	
 
	private global::Gtk.MenuBar menu;
 
	
 
	private global::Gtk.Alignment contentContainer;
 
	
 
	private global::Gtk.Statusbar statusBar;
 

	
 
	protected virtual void Build ()
 
	{
 
		global::Stetic.Gui.Initialize (this);
 
		// Widget MainWindow
 
		this.UIManager = new global::Gtk.UIManager ();
 
		global::Gtk.ActionGroup w1 = new global::Gtk.ActionGroup ("Default");
 
		this.FileAction = new global::Gtk.Action ("FileAction", "_File", null, null);
 
		this.FileAction.ShortLabel = "_File";
 
		w1.Add (this.FileAction, "<Alt>f");
 
		this.HelpAction = new global::Gtk.Action ("HelpAction", "_Help", null, null);
 
		this.HelpAction.ShortLabel = "_Help";
 
		w1.Add (this.HelpAction, "<Alt>a");
 
		this.AboutAction = new global::Gtk.Action ("AboutAction", "_About...", null, null);
 
		this.AboutAction.ShortLabel = "_About...";
 
		w1.Add (this.AboutAction, "<Alt>a");
 
		this.ExitAction = new global::Gtk.Action ("ExitAction", "E_xit", null, null);
 
		this.ExitAction.ShortLabel = "E_xit";
 
		w1.Add (this.ExitAction, "<Alt>x");
 
		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.ReactionStatusAction = new global::Gtk.Action ("ReactionStatusAction", "Reaction Status", null, null);
 
		this.ReactionStatusAction.ShortLabel = "Reaction Status";
 
		w1.Add (this.ReactionStatusAction, null);
 
		this.ViewAction = new global::Gtk.Action ("ViewAction", "View", null, null);
 
		this.ViewAction.ShortLabel = "View";
 
		w1.Add (this.ViewAction, null);
 
		this.CaptureAction = new global::Gtk.RadioAction ("CaptureAction", "Capture", null, null, 0);
 
		this.CaptureAction.Group = new global::GLib.SList (global::System.IntPtr.Zero);
 
		this.CaptureAction.ShortLabel = "Capture";
 
		w1.Add (this.CaptureAction, null);
 
		this.SimulatorAction = new global::Gtk.RadioAction ("SimulatorAction", "Simulator", null, null, 0);
 
		this.SimulatorAction.Group = this.CaptureAction.Group;
 
		this.SimulatorAction.ShortLabel = "Simulator";
 
		w1.Add (this.SimulatorAction, null);
 
		this.RecipeGeneratorAction = new global::Gtk.RadioAction ("RecipeGeneratorAction", "Recipe Generator", null, null, 0);
 
		this.RecipeGeneratorAction.Group = this.SimulatorAction.Group;
 
		this.RecipeGeneratorAction.Group = this.CaptureAction.Group;
 
		this.RecipeGeneratorAction.ShortLabel = "Recipe Generator";
 
		w1.Add (this.RecipeGeneratorAction, null);
 
		this.RecipesAction = new global::Gtk.Action ("RecipesAction", "Recipes...", null, null);
 
		this.RecipesAction.ShortLabel = "Recipes...";
 
		w1.Add (this.RecipesAction, null);
 
		this.ExportRecipesAction = new global::Gtk.Action ("ExportRecipesAction", "Export Recipes", null, null);
 
		this.ExportRecipesAction.ShortLabel = "Export Recipes";
 
		w1.Add (this.ExportRecipesAction, null);
 
		this.CopyRecipesToClipboardAction = new global::Gtk.Action ("CopyRecipesToClipboardAction", "Copy to Clipboard", null, null);
 
		this.CopyRecipesToClipboardAction.ShortLabel = "Copy to Clipboard";
 
		w1.Add (this.CopyRecipesToClipboardAction, null);
 
		this.ProfileAction = new global::Gtk.Action ("ProfileAction", "Profile...", null, null);
 
		this.ProfileAction.ShortLabel = "Profile...";
 
		w1.Add (this.ProfileAction, null);
 
		this.NewProfileAction = new global::Gtk.Action ("NewProfileAction", "New Profile", null, null);
 
		this.NewProfileAction.ShortLabel = "New Profile";
 
		w1.Add (this.NewProfileAction, null);
 
		this.OpenProfileAction = new global::Gtk.Action ("OpenProfileAction", "Open Profile", null, null);
 
		this.OpenProfileAction.ShortLabel = "Open Profile";
 
		w1.Add (this.OpenProfileAction, null);
 
		this.ImportProfileAction = new global::Gtk.Action ("ImportProfileAction", "Import Profile", null, null);
 
		this.ImportProfileAction.ShortLabel = "Import Profile";
 
		w1.Add (this.ImportProfileAction, null);
 
		this.ExportProfileAction = new global::Gtk.Action ("ExportProfileAction", "Export Profile", null, null);
 
		this.ExportProfileAction.ShortLabel = "Export Profile";
 
		w1.Add (this.ExportProfileAction, null);
 
		this.ExportForPracticalPaintAction = new global::Gtk.Action ("ExportForPracticalPaintAction", "Export for PracticalPaint", null, null);
 
		this.ExportForPracticalPaintAction.ShortLabel = "Export for PracticalPaint";
 
		w1.Add (this.ExportForPracticalPaintAction, 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='menu'><menu name='FileAction' action='FileAction'><menu name='ProfileAction' action='ProfileAction'><menuitem name='NewProfileAction' action='NewProfileAction'/><menuitem name='OpenProfileAction' action='OpenProfileAction'/><menuitem name='ImportProfileAction' action='ImportProfileAction'/><menuitem name='ExportProfileAction' action='ExportProfileAction'/><menuitem name='ExportForPracticalPaintAction' action='ExportForPracticalPaintAction'/></menu><menu name='RecipesAction' action='RecipesAction'><menuitem name='ExportRecipesAction' action='ExportRecipesAction'/><menuitem name='CopyRecipesToClipboardAction' action='CopyRecipesToClipboardAction'/></menu><separator/><menuitem name='ExitAction' action='ExitAction'/></menu><menu name='ViewAction' action='ViewAction'><menuitem name='CaptureAction' action='CaptureAction'/><menuitem name='SimulatorAction' action='SimulatorAction'/><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.menu = ((global::Gtk.MenuBar)(this.UIManager.GetWidget ("/menu")));
 
		this.menu.Name = "menu";
 
		this.vbox1.Add (this.menu);
 
		global::Gtk.Box.BoxChild w2 = ((global::Gtk.Box.BoxChild)(this.vbox1 [this.menu]));
 
		w2.Position = 0;
 
		w2.Expand = false;
 
		w2.Fill = false;
 
		// Container child vbox1.Gtk.Box+BoxChild
 
		this.contentContainer = new global::Gtk.Alignment (0.5F, 0.5F, 1F, 1F);
0 comments (0 inline, 0 general)