Changeset - 787f2aabbded
[Not reviewed]
default
0 1 0
Jason Maltzen - 5 years ago 2019-11-02 02:24:55
jason@hiddenachievement.com
Update search for paint lab interface: check for 4 corners and left/right line of solid portion of the color area, fix papyrus texture check for new brighter papyrus texture.
1 file changed with 47 insertions and 3 deletions:
0 comments (0 inline, 0 general)
ReactionRecorder.cs
Show inline comments
...
 
@@ -22,32 +22,37 @@
 

	
 
using System;
 
using System.IO;
 

	
 
namespace DesertPaintLab
 
{
 
    // ReactionRecorder - business logic for recording paint reactions
 
    public class ReactionRecorder
 
    {
 
        public delegate void CaptureProgressHandler(int x, int y);
 
        public CaptureProgressHandler OnCaptureProgress;
 

	
 
        const int COLOR_TOLERANCE = 3;
 

	
 
        const InterfaceSize DEFAULT_INTERFACE_SIZE = InterfaceSize.Small;
 

	
 
        // Swatch is 301x20 solid color, 1px darker left/top, 1px black outer left/top, 1px light right/bottom, 1px bright right/bottom
 
        // top-right and bottom-left are bright instead of black
 

	
 
        // Color bars are 4x302 solid color, 2px border on all sides (darker left/top, lighter bottom/right
 

	
 
        public static readonly int[] SWATCH_HEIGHT = 
 
        {
 
            24, // tiny
 
            24, // small
 
            24, // medium
 
            24, // large
 
            24 // huge
 
        };
 
        public static readonly int[] SWATCH_WIDTH =
 
        {
 
            260, // tiny
 
            260, // small
 
            260, // medium
 
            274, // large
 
            304 // huge
 
        };
...
 
@@ -181,36 +186,40 @@ namespace DesertPaintLab
 
        public ReactionRecorder(int pixelMultiplier, InterfaceSize interfaceSize)
 
        {
 
            this.pixelMultiplier = pixelMultiplier;
 
            this.interfaceSize = interfaceSize;
 
            swatchHeight = SWATCH_HEIGHT[(int)interfaceSize] * pixelMultiplier;
 
            swatchWidth = SWATCH_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
            colorBarWidth = COLOR_BAR_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
            redBarSpacing = RED_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            greenBarSpacing = GREEN_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            blueBarSpacing = BLUE_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            swatchTestWidth = SWATCH_TEST_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
        }
 

	
 
        private static bool IsPapyTexture(byte r, byte g, byte b)
 
        {
 
            // red between 208 and 244
 
            // 240 and 255
 
            // green between 192 and 237
 
            // 223 and 248
 
            // blue between 145 and 205
 
            return ((r > 0xD0) && (g >= 0xC0) && (b >= 0x91)) &&
 
                   ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD));
 
            // 178 and 228
 
            //return ((r > 0xD0) && (g >= 0xC0) && (b >= 0x91)) &&
 
            //       ((r < 0xF4) && (g <= 0xED) && (b <= 0xCD));
 
            return ((r >= 0xF0) && (r <= 0xFF) && (g >= 0xDF) && (g <= 0xF8) && (b >= 0xB2) && (b <= 0xE4));
 
        }
 

	
 
        public void SetPixelMultiplier(int pixelMultiplier)
 
        {
 
            this.pixelMultiplier = pixelMultiplier;
 

	
 
            swatchHeight = SWATCH_HEIGHT[(int)interfaceSize] * pixelMultiplier;
 
            swatchWidth      = SWATCH_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
            colorBarWidth    = COLOR_BAR_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
            redBarSpacing    = RED_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            greenBarSpacing  = GREEN_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            blueBarSpacing   = BLUE_BAR_SPACING[(int)interfaceSize] * pixelMultiplier;
 
            swatchTestWidth  = SWATCH_TEST_WIDTH[(int)interfaceSize] * pixelMultiplier;
 
        }
 

	
 
        public void SetInterfaceSize(InterfaceSize interfaceSize)
...
 
@@ -290,43 +299,77 @@ namespace DesertPaintLab
 
                WriteLog("Swatch slice at {0}, {1} failed to match", x, y);
 
            }
 

	
 
            return result;
 
        }
 

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

	
 
            if (testPixelStart < stride)
 
            {
 
                return false;
 
            }
 

	
 
            bool result = true;
 

	
 
            int solidUpperLeft = testPixelStart + (2 * y * stride) + (2 * x * 3);
 
            int solidLowerLeft = testPixelStart + ((swatchHeight - 4) * stride);
 
            int solidUpperRight = testPixelStart + ((swatchWidth - 4) * 3);
 
            int solidLowerRight = solidLowerLeft + ((swatchWidth - 4) * 3);
 
            byte swatch_r = pixBytes[solidUpperLeft];
 
            byte swatch_g = pixBytes[solidUpperLeft + 1];
 
            byte swatch_b = pixBytes[solidUpperLeft + 2];
 

	
 
            // Check the other 3 corners of the swatch size for color match
 
            result &= IsColorMatch(swatch_r, swatch_r, swatch_r, pixBytes[solidUpperRight], pixBytes[solidUpperRight + 1], pixBytes[solidUpperRight + 2]);
 
            result &= IsColorMatch(swatch_r, swatch_r, swatch_r, pixBytes[solidLowerLeft], pixBytes[solidLowerLeft + 1], pixBytes[solidLowerLeft + 2]);
 
            result &= IsColorMatch(swatch_r, swatch_r, swatch_r, pixBytes[solidLowerRight], pixBytes[solidLowerRight + 1], pixBytes[solidLowerRight + 2]);
 

	
 
            if (!result)
 
            {
 
                return false;
 
            }
 

	
 
            // scan down the right and left sides
 
            for (int yOff = 1; yOff < (swatchHeight - 5); ++yOff)
 
            {
 
                int testPixel = solidUpperLeft + (yOff * stride);
 
                result &= IsColorMatch(swatch_r, swatch_r, swatch_r, pixBytes[testPixel], pixBytes[testPixel + 1], pixBytes[testPixel + 2]);
 
                testPixel += ((swatchWidth - 1) * (x + 3));
 
                result &= IsColorMatch(swatch_r, swatch_r, swatch_r, pixBytes[testPixel], pixBytes[testPixel + 1], pixBytes[testPixel + 2]);
 
            }
 

	
 
            if (!result)
 
            {
 
                WriteLog("Failed to find left edge for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatch_r, swatch_g, swatch_b);
 
                return false;
 
            }
 

	
 
            // test the left edge for dark pixels
 
            int i = 0;
 
            for (i = 0; result && (i < swatchHeight-pixelMultiplier); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (stride * i);
 
                result &= IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
            }
 
            if (!result)
 
            {
 
                // No dark border on the left side
 
                // WriteLog("Failed to find left border for swatch at {0}, {1}", x, y);
 
                WriteLog("Failed to find left border for potential swatch of color {2}, {3}, {4} at {0}, {1}", x, y, swatch_r, swatch_g, swatch_b);
 
                return false;
 
            }
 

	
 
            // test the dark top border and for papyrus above and below the swatch
 
            bool borderError = false;
 
            int papyErrorCount = 0;
 
            for (i = 0; result && (i < swatchWidth); ++i)
 
            {
 
                int otherPixelStart = testPixelStart + (3 * i);
 
                bool isBorder = IsDarkPixel(pixBytes[otherPixelStart], pixBytes[otherPixelStart+1], pixBytes[otherPixelStart+2]);
 
                result &= isBorder;
 
                if (!isBorder)
 
                {
 
                    borderError = true;
 
                }
 
                if (otherPixelStart >= stride)
...
 
@@ -355,32 +398,33 @@ namespace DesertPaintLab
 

	
 
            return result;
 
        }
 

	
 
        unsafe private bool TestPosition(int x, int y, 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;
 

	
 
            // Look for the color swatch.
 
            pixelStart = (y * stride) + (x * 3);
 
            pixel_r = pixBytes[pixelStart];
 
            pixel_g = pixBytes[pixelStart + 1];
 
            pixel_b = pixBytes[pixelStart + 2];
 

	
 
            // Check 4 corners of solid area and left/right solid bar areas
 
            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.
0 comments (0 inline, 0 general)