Пример #1
0
    // Under 2ms on 512x512 textures, ~7ms with 1024x1024 textures (Deep Profiler mode), much faster in build (under 1ms)
    //void PaintTexture(RaycastHit hit)
    //{
    //    //UnityEngine.Debug.Log("PaintTexture");
    //    GlobalVariables.instance.paintInProgress = true;
    //    Renderer rend = hit.transform.GetComponent<Renderer>();
    //    Stopwatch startToEndStopwatch = new Stopwatch();
    //    startToEndStopwatch.Start();

    //    int bloodType = Random.Range(1, 4);

    //    if (rend != null)
    //    {
    //        Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap");

    //        if (originalTex != null && originalTex.isReadable)
    //        {
    //            Texture2D brush = blood1_64x64;

    //            if (bloodType == 1)
    //            {
    //                brush = blood1_64x64;
    //            }
    //            else if (bloodType == 2)
    //            {
    //                brush = blood2_64x64;
    //            }
    //            else if (bloodType == 3)
    //            {
    //                brush = blood3_64x64;
    //            }
    //            int orgTexWidth = originalTex.width;
    //            int orgTexHeight = originalTex.height;

    //            // Scaling
    //            /*
    //            if (orgWidth > 1024)
    //            {
    //                brush = lowResDecal64;
    //            }
    //            else if (orgWidth > 512)
    //            {
    //                brush = lowResDecal32;
    //            }
    //            else
    //            {
    //                brush = lowResDecal16;
    //            }
    //            */

    //            int brushWidth = brush.width;
    //            int brushHeight = brush.height;

    //            //Debug.Log("brush width: " + brushWidth);

    //            int uvx = (int)(hit.textureCoord.x * orgTexWidth);
    //            int uvy = (int)(hit.textureCoord.y * orgTexHeight);

    //            //UnityEngine.Debug.LogError("texCords: " + hit.textureCoord);
    //            //UnityEngine.Debug.LogError("x: " + uvx +  " y: " + uvy);
    //            //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord);
    //            //Debug.Log("x: " + uvx + " y: " + uvy);


    //            int paintStartX = uvx - (brushWidth / 2);
    //            int paintStartY = uvy - (brushHeight / 2);

    //            bool createNewTex = false;

    //            Texture2D modifiedTex;
    //            // If texture has not been edited/copied yet, create a new one
    //            if (originalTex.updateCount == 0)
    //            {
    //                createNewTex = true;
    //                modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture
    //                modifiedTex.filterMode = FilterMode.Point;
    //                modifiedTex.SetPixels32(originalTex.GetPixels32());
    //            }
    //            // If texture has been already edited/copied, edit existing texture rather than creating a new one
    //            else
    //            {
    //                modifiedTex = originalTex;

    //                //UnityEngine.Debug.Log("Edit existing texture");
    //                //UnityEngine.Debug.LogError("Edit existing texture");

    //                //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount);
    //                //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount);
    //            }



    //            for (int i = 0; i < brushWidth; i++)
    //            {
    //                for (int j = 0; j < brushHeight; j++)
    //                {
    //                    if (bloodType == 1)
    //                    {
    //                        Color32 c;
    //                        if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c))
    //                        {
    //                            modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                        }
    //                    }
    //                    else if (bloodType == 2)
    //                    {
    //                        Color32 c;
    //                        if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c))
    //                        {
    //                            modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                        }
    //                    }
    //                    else if (bloodType == 3)
    //                    {
    //                        Color32 c;
    //                        if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c))
    //                        {
    //                            modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                        }
    //                    }
    //                }
    //            }

    //            modifiedTex.Apply();
    //            if (createNewTex)
    //            {
    //                rend.material.SetTexture("_BaseMap", modifiedTex);
    //            }
    //            else
    //            {

    //            }

    //            if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75)
    //            {
    //                StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy), bloodType));
    //            }
    //        }
    //    }
    //    //UnityEngine.Debug.LogError("PaintTime: " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms");
    //    paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f);
    //    GlobalVariables.instance.paintInProgress = false;
    //}

    // Takes 6(new texture) or 5(editing existing texture) frames to complete to reduce load on single frame
    //IEnumerator PaintTextureAsync(RaycastHit hit)
    //{
    //    GlobalVariables.instance.paintInProgress = true;
    //    Stopwatch startToEndStopwatch = new Stopwatch();
    //    startToEndStopwatch.Start();

    //    Renderer rend = hit.transform.GetComponent<Renderer>();

    //    int bloodType = Random.Range(1, 4);

    //    if (rend != null)
    //    {
    //        Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap");

    //        if (originalTex != null && originalTex.isReadable)
    //        {
    //            Texture2D brush = blood1_64x64;

    //            if (bloodType == 1)
    //            {
    //                brush = blood1_64x64;
    //            }
    //            else if (bloodType == 2)
    //            {
    //                brush = blood2_64x64;
    //            }
    //            else if (bloodType == 3)
    //            {
    //                brush = blood3_64x64;
    //            }

    //            int orgTexWidth = originalTex.width;
    //            int orgTexHeight = originalTex.height;

    //            // Scaling
    //            /*
    //            if (orgWidth > 1024)
    //            {
    //                brush = lowResDecal64;
    //            }
    //            else if (orgWidth > 512)
    //            {
    //                brush = lowResDecal32;
    //            }
    //            else
    //            {
    //                brush = lowResDecal16;
    //            }
    //            */

    //            int brushWidth = brush.width;
    //            int brushHeight = brush.height;

    //            int uvx = (int)(hit.textureCoord.x * orgTexWidth);
    //            int uvy = (int)(hit.textureCoord.y * orgTexHeight);

    //            //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord);
    //            //Debug.Log("x: " + uvx + " y: " + uvy);


    //            int paintStartX = uvx - (brushWidth / 2);
    //            int paintStartY = uvy - (brushHeight / 2);

    //            Texture2D modifiedTex;
    //            bool createNewTex = false;

    //            // If texture has been already edited/copied, edit existing texture rather than creating a new one
    //            if (originalTex.updateCount == 0)
    //            {
    //                createNewTex = true;
    //                modifiedTex = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture
    //                modifiedTex.filterMode = FilterMode.Point;

    //                //UnityEngine.Debug.Log("Create new texture");
    //                //UnityEngine.Debug.LogError("Create new texture");

    //                modifiedTex.SetPixels32(originalTex.GetPixels32());
    //                //UnityEngine.Debug.Log("original texture update count : " + modifiedTex.updateCount);
    //                //UnityEngine.Debug.LogError("original texture update count : " + modifiedTex.updateCount);

    //                yield return null;
    //            }
    //            // If texture has not been edited/copied yet, create a new one
    //            else
    //            {
    //                modifiedTex = originalTex;
    //                //UnityEngine.Debug.Log("Edit existing texture");
    //                //UnityEngine.Debug.LogError("Edit existing texture");

    //                //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount);
    //                //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount);
    //            }

    //            bool loop1 = false;
    //            bool loop2 = false;
    //            bool loop3 = false;

    //            for (int i = 0; i < brushWidth; i++)
    //            {
    //                // Chop loop to 4 frames
    //                float complete = (float)i / (float)brushWidth;
    //                if (complete > 0.25f && !loop1)
    //                {
    //                    loop1 = true;
    //                    yield return null;
    //                }
    //                else if (complete > 0.50f && !loop2)
    //                {
    //                    loop2 = true;
    //                    yield return null;
    //                }
    //                else if (complete > 0.75f && !loop3)
    //                {
    //                    loop3 = true;
    //                    yield return null;
    //                }
    //                for (int j = 0; j < brushHeight; j++)
    //                {
    //                    //int pos = j * decalWidth + i;
    //                    //Color32 color = decalColorData[pos];
    //                    if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight)
    //                    {
    //                        if (bloodType == 1)
    //                        {
    //                            Color32 c;
    //                            if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c))
    //                            {
    //                                modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                            }
    //                        }
    //                        else if (bloodType == 2)
    //                        {
    //                            Color32 c;
    //                            if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c))
    //                            {
    //                                modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                            }
    //                        }
    //                        else if (bloodType == 3)
    //                        {
    //                            Color32 c;
    //                            if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c))
    //                            {
    //                                modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
    //                            }
    //                        }
    //                    }
    //                }
    //            }

    //            yield return null;


    //            modifiedTex.Apply();

    //            if (createNewTex)
    //            {
    //                rend.material.SetTexture("_BaseMap", modifiedTex);
    //            }
    //            else
    //            {
    //                //UnityEngine.Debug.Log("Existing texture update count after: " + modifiedTex.updateCount);
    //                //UnityEngine.Debug.LogError("Existing texture update count after: " + modifiedTex.updateCount);
    //            }

    //            if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75)
    //            {
    //                StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy), bloodType));
    //            }
    //        }
    //    }
    //    paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f);
    //    //UnityEngine.Debug.LogError("PaintTime(Async): " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms");
    //    //yield return null;
    //    GlobalVariables.instance.paintInProgress = false;
    //} // Causes problems with paintInProgress

    // Execution time of this function is limited to maxvalue per frame(some single functions inside this function can still take longer)
    IEnumerator PaintTextureAsyncTimed(RaycastHit hit) // paintInprogress causes problems
    {
        GlobalVariables.instance.paintInProgress = true;
        GlobalVariables.instance.globalPaintsInProgress++;
        localPaintsInProgress++;
        int       frames              = 0;
        float     maxTimePerFrame     = 4f;
        Stopwatch stopWatch           = new Stopwatch();
        Stopwatch startToEndStopwatch = new Stopwatch();

        //UnityEngine.Debug.Log("frq: " + Stopwatch.Frequency + "ishr: " + Stopwatch.IsHighResolution);
        startToEndStopwatch.Start();
        stopWatch.Start();
        Renderer rend = hit.transform.GetComponent <Renderer>();

        int bloodType = Random.Range(0, bloodSplatSprites.Length);

        if (rend != null)
        {
            Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap");
            //UnityEngine.Debug.Log("Original texture format: " + originalTex.format);

            if (originalTex != null && originalTex.isReadable)
            {
                float elapsedMs = 0;

                Texture2D brush = bloodSplatSprites[bloodType]; //blood1_64x64;

                //if (bloodType == 1)
                //{
                //    brush = blood1_64x64;
                //}
                //else if (bloodType == 2)
                //{
                //    brush = blood2_64x64;
                //}
                //else if (bloodType == 3)
                //{
                //    brush = blood3_64x64;
                //}

                int orgTexWidth  = originalTex.width;
                int orgTexHeight = originalTex.height;
                // Scaling

                /*
                 * if (orgWidth > 1024)
                 * {
                 *  brush = lowResDecal64;
                 * }
                 * else if (orgWidth > 512)
                 * {
                 *  brush = lowResDecal32;
                 * }
                 * else
                 * {
                 *  brush = lowResDecal16;
                 * }
                 */

                int brushWidth  = brush.width;
                int brushHeight = brush.height;

                //Debug.Log("brush width: " + brushWidth);

                int uvx = (int)(hit.textureCoord.x * orgTexWidth);
                int uvy = (int)(hit.textureCoord.y * orgTexHeight);
                //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord);
                //Debug.Log("x: " + uvx + " y: " + uvy);

                int paintStartX = uvx - (brushWidth / 2);
                int paintStartY = uvy - (brushHeight / 2);

                Texture2D modifiedTex;
                bool      createNewTex = false;
                // If texture has not been edited/copied yet, create a new one
                if (originalTex.updateCount == 0)
                {
                    createNewTex           = true;
                    modifiedTex            = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture
                    modifiedTex.filterMode = FilterMode.Point;
                    Color32[] newColors = originalTex.GetPixels32();

                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }

                    modifiedTex.SetPixels32(newColors);

                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }
                }
                // If texture has been already edited/copied, edit existing texture rather than creating a new one
                else
                {
                    modifiedTex = originalTex;

                    //UnityEngine.Debug.Log("Edit existing texture");
                    //UnityEngine.Debug.LogError("Edit existing texture");

                    //UnityEngine.Debug.Log("Existing texture update count : " + modifiedTex.updateCount);
                    //UnityEngine.Debug.LogError("Existing texture update count : " + modifiedTex.updateCount);
                }

                for (int i = 0; i < brushWidth; i++)
                {
                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }
                    for (int j = 0; j < brushHeight; j++)
                    {
                        //int pos = j * decalWidth + i;
                        //Color32 color = decalColorData[pos];
                        if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight)
                        {
                            Color32 c;
                            if (bloodSplatDictionaries[bloodType].TryGetValue(j * brushWidth + i, out c))
                            {
                                modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
                            }
                            //if (bloodType == 1)
                            //{
                            //    Color32 c;
                            //    if (nonTransparentBlood1Pixels.TryGetValue(j * brushWidth + i, out c))
                            //    {
                            //        modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
                            //    }
                            //}
                            //else if (bloodType == 2)
                            //{
                            //    Color32 c;
                            //    if (nonTransparentBlood2Pixels.TryGetValue(j * brushWidth + i, out c))
                            //    {
                            //        modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
                            //    }
                            //}
                            //else if (bloodType == 3)
                            //{
                            //    Color32 c;
                            //    if (nonTransparentBlood3Pixels.TryGetValue(j * brushWidth + i, out c))
                            //    {
                            //        modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
                            //    }
                            //}
                        }
                    }
                }

                // Apply() is approx 0.7ms for 512x512 texture so this last yield might not be needed

                //elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                //if (elapsedMs > maxTimePerFrame / 1.5) // For larger textures it might be benefitical to have smaller than max value here so that long loop portion doesnt get chained with Apply()
                //{
                //    frames++;
                //    stopWatch.Reset();
                //    yield return null;
                //    stopWatch.Start();
                //}

                modifiedTex.Apply();

                if (createNewTex)
                {
                    rend.material.SetTexture("_BaseMap", modifiedTex);

                    //UnityEngine.Debug.Log("new texture update count after: " + modifiedTex.updateCount);
                    //UnityEngine.Debug.LogError("new texture update count after: " + modifiedTex.updateCount);

                    //UnityEngine.Debug.Log("new: " + modifiedTex.updateCount);
                    //UnityEngine.Debug.Log("orgAfter: " + modifiedTex.updateCount);
                }
                else
                {
                    //UnityEngine.Debug.Log("Existing texture update count after: " + modifiedTex.updateCount);
                    //UnityEngine.Debug.LogError("Existing texture update count after: " + modifiedTex.updateCount);
                }
                //UnityEngine.Debug.Log(Mathf.Abs(rend.transform.rotation.eulerAngles.x));
                if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75)
                {
                    //StartCoroutine(WallDrip(modifiedTex, new Vector2(uvx, uvy)));
                    //StartCoroutine(decalHandler.WallDrip(modifiedTex, new Vector2(uvx, uvy))); // Problem
                    //StartWallDripCoroutine(modifiedTex, new Vector2(uvx, uvy));
                    DecalHandler.wallDripStruct wds = new DecalHandler.wallDripStruct();
                    wds.tex       = modifiedTex;
                    wds.uv        = new Vector2(uvx, uvy);
                    wds.bloodType = bloodType;

                    decalHandler.wallDripQueue.Enqueue(wds);
                }
            }
        }
        timeInInstance += (float)startToEndStopwatch.ElapsedTicks / (float)10000f;
        paintTimes.Add((float)startToEndStopwatch.ElapsedTicks / (float)10000f);
        //UnityEngine.Debug.LogError("PaintTime(TimedAsync): " + (float)startToEndStopwatch.ElapsedTicks / (float)10000f + "ms");

        if (timeInInstance > maxTimePerInstance)
        {
            yield return(null);
        }
        GlobalVariables.instance.paintInProgress = false; // Sometimes this object gets destroyed before the coroutne reaches this point
        GlobalVariables.instance.globalPaintsInProgress--;
        localPaintsInProgress--;
    }
Пример #2
0
    IEnumerator PaintTextureAsyncTimed(RaycastHit hit) // paintInprogress causes problems
    {
        GlobalVariables.instance.paintInProgress = true;
        GlobalVariables.instance.globalPaintsInProgress++;
        localPaintsInProgress++;

        int   frames          = 0;
        float maxTimePerFrame = 4f;

        Stopwatch stopWatch           = new Stopwatch();
        Stopwatch startToEndStopwatch = new Stopwatch();

        startToEndStopwatch.Start();
        stopWatch.Start();

        Renderer rend = hit.transform.GetComponent <Renderer>();

        int bloodType = Random.Range(0, bloodSplatSprites.Length);

        if (rend != null)
        {
            Texture2D originalTex = (Texture2D)rend.material.GetTexture("_BaseMap"); //HDRP/Lit version: GetTexture("_BaseColorMap");

            if (originalTex != null && originalTex.isReadable)
            {
                float elapsedMs = 0;

                Texture2D brush = bloodSplatSprites[bloodType];

                int orgTexWidth  = originalTex.width;
                int orgTexHeight = originalTex.height;

                int brushWidth  = brush.width;
                int brushHeight = brush.height;

                //Debug.Log("brush width: " + brushWidth);

                int uvx = (int)(hit.textureCoord.x * orgTexWidth);
                int uvy = (int)(hit.textureCoord.y * orgTexHeight);
                //UnityEngine.Debug.Log("tex cord: " + hit.textureCoord);
                //Debug.Log("x: " + uvx + " y: " + uvy);

                int paintStartX = uvx - (brushWidth / 2);
                int paintStartY = uvy - (brushHeight / 2);

                Texture2D modifiedTex;
                bool      createNewTex = false;

                // If texture has not been edited/copied yet, create a new one
                if (originalTex.updateCount == 0)
                {
                    createNewTex           = true;
                    modifiedTex            = new Texture2D(orgTexWidth, orgTexHeight, TextureFormat.RGBA32, false);// Create copy of the original texture
                    modifiedTex.filterMode = FilterMode.Point;
                    Color32[] newColors = originalTex.GetPixels32();

                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }

                    modifiedTex.SetPixels32(newColors);

                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }
                }
                // If texture has been already edited/copied, edit existing texture rather than creating a new one
                else
                {
                    modifiedTex = originalTex;
                }

                for (int i = 0; i < brushWidth; i++)
                {
                    elapsedMs = (float)stopWatch.ElapsedTicks / (float)10000f; // Tick is 100ns. 10K ticks = 1ms
                    if (elapsedMs > maxTimePerFrame)
                    {
                        frames++;
                        stopWatch.Reset();
                        startToEndStopwatch.Stop();
                        yield return(null);

                        startToEndStopwatch.Start();
                        stopWatch.Start();
                    }
                    for (int j = 0; j < brushHeight; j++)
                    {
                        //int pos = j * decalWidth + i;
                        //Color32 color = decalColorData[pos];
                        if (paintStartX + i >= 0 && paintStartX + i < orgTexWidth && paintStartY + j >= 0 && paintStartY + j < orgTexHeight)
                        {
                            Color32 c;
                            if (bloodSplatDictionaries[bloodType].TryGetValue(j * brushWidth + i, out c))
                            {
                                modifiedTex.SetPixel(paintStartX + i, paintStartY + j, c); //brush.GetPixel(i, j)); // Alternative: Store pixel colors to Dictionary instead of using GetPixel from Texture2D? (almost the same speed, causes calls to color contructor)
                            }
                        }
                    }
                }

                modifiedTex.Apply();

                if (createNewTex)
                {
                    rend.material.SetTexture("_BaseMap", modifiedTex);
                }
                else
                {
                }

                if (Mathf.Abs(rend.transform.rotation.eulerAngles.x) > 75)
                {
                    DecalHandler.wallDripStruct wds = new DecalHandler.wallDripStruct();
                    wds.tex       = modifiedTex;
                    wds.uv        = new Vector2(uvx, uvy);
                    wds.bloodType = bloodType;

                    decalHandler.wallDripQueue.Enqueue(wds);
                }
            }
        }
        timeInInstance += (float)startToEndStopwatch.ElapsedTicks / (float)10000f;

        if (timeInInstance > maxTimePerInstance)
        {
            yield return(null);
        }
        GlobalVariables.instance.paintInProgress = false; // Sometimes this object gets destroyed before the coroutine reaches this point
        GlobalVariables.instance.globalPaintsInProgress--;
        localPaintsInProgress--;
    }