Exemplo n.º 1
0
        private static IEnumerator ComputeEdgeGradients()
        {
            float sqrt2 = Mathf.Sqrt(2f);

            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (int y = 1; y < height - 1; y++)
                {
                    for (int x = 1; x < width - 1; x++)
                    {
                        var p = pixels[x, y];
                        if (p.originalValue > 0f && p.originalValue < 1f)
                        {
                            float g =
                                -pixels[x - 1, y - 1].originalValue
                                - pixels[x - 1, y + 1].originalValue
                                + pixels[x + 1, y - 1].originalValue
                                + pixels[x + 1, y + 1].originalValue;
                            p.gradient.x = g + (pixels[x + 1, y].originalValue - pixels[x - 1, y].originalValue) *
                                           sqrt2;
                            p.gradient.y = g + (pixels[x, y + 1].originalValue - pixels[x, y - 1].originalValue) *
                                           sqrt2;
                            p.gradient.Normalize();
                        }
                    }
                }
            }, "Edge grad A"));


            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (int y = 0; y < height; y++)
                {
                    int skip = ((y == 0) || (y == (height - 1))) ? 1 : (width - 1);

                    for (int x = 0; x < width; x += skip)
                    {
                        var p = pixels[x, y];
                        if (p.originalValue > 0f && p.originalValue < 1f)
                        {
                            float g =
                                -Pixels(x - 1, y - 1).originalValue
                                - Pixels(x - 1, y + 1).originalValue
                                + Pixels(x + 1, y - 1).originalValue
                                + Pixels(x + 1, y + 1).originalValue;
                            p.gradient.x = g + (Pixels(x + 1, y).originalValue - Pixels(x - 1, y).originalValue) *
                                           sqrt2;
                            p.gradient.y = g + (Pixels(x, y + 1).originalValue - Pixels(x, y - 1).originalValue) *
                                           sqrt2;
                            p.gradient.Normalize();
                        }
                    }
                }
            }, "Edge grad B"));
        }
Exemplo n.º 2
0
        private static IEnumerator PostProcess(float maxDistance)
        {
            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        var p = pixels[x, y];
                        if ((p.dX == 0 && p.dY == 0) || p.distance >= maxDistance)
                        {
                            continue;
                        }

                        float
                        dX = p.dX,
                        dY = p.dY;
                        var closest = Pixels(x - p.dX, y - p.dY);
                        var g = closest.gradient;

                        if (g.x == 0f && g.y == 0f)
                        {
                            continue;
                        }

                        float df = ApproximateEdgeDelta(g.x, g.y, closest.originalValue);
                        float t = dY * g.x - dX * g.y;
                        float u = -df * g.x + t * g.y;
                        float v = -df * g.y - t * g.x;

                        if (Mathf.Abs(u) <= 0.5f && Mathf.Abs(v) <= 0.5f)
                        {
                            p.distance = Mathf.Sqrt((dX + u) * (dX + u) + (dY + v) * (dY + v));
                        }
                    }
                }
            }, "Postprocess"));
        }
Exemplo n.º 3
0
        public static IEnumerator Generate(
            TextureMeta image,
            float maxInside,
            float maxOutside,
            float postProcessDistance)
        {
            width  = image.width;
            height = image.height;

            destination = image;

            if (image.Pixels == null)
            {
                Debug.LogError("Pixels are null");
                yield break;
            }

            pixels = new Pixel[width, height];
            int   x, y;
            float scale;

            yield return(QcAsync.CallAgain("Creating pixels"));

            yield return(QcAsync.CallAfter_Thread(() => InitializePixels(), "Creating pixels coroutine"));

            yield return(QcAsync.CallAgain("Filling max Inside"));

            //INSIDE
            if (maxInside > 0f)
            {
                for (var e = ComputeEdgeGradients(); e.MoveNext();)
                {
                    yield return(e.Current);
                }

                for (var e = GenerateDistanceTransform(); e.MoveNext();)
                {
                    yield return(e.Current);
                }

                if (postProcessDistance > 0f)
                {
                    for (var e = PostProcess(postProcessDistance); e.MoveNext();)
                    {
                        yield return(e.Current);
                    }
                }


                yield return(QcAsync.CallAgain("Setting Inside Pixels"));

                scale = 1f / maxInside;
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        SetDestination(x, y, Mathf.Clamp01(pixels[x, y].distance * scale));
                    }

                    yield return(QcAsync.CallAgain("Inside Pixels {0}".F(y)));
                }
            }

            yield return(QcAsync.CallAgain("Filling max Outside"));


            //OUTSIDE
            if (maxOutside > 0f)
            {
                yield return(QcAsync.CallAfter_Thread(() => {
                    for (y = 0; y < height; y++)
                    {
                        for (x = 0; x < width; x++)
                        {
                            pixels[x, y].FlipOriginal();
                        }
                    }
                }, "Flipping pixels"));


                for (var e = ComputeEdgeGradients(); e.MoveNext();)
                {
                    yield return(e.Current);
                }

                for (var e = GenerateDistanceTransform(); e.MoveNext();)
                {
                    yield return(e.Current);
                }

                if (postProcessDistance > 0f)
                {
                    for (var e = PostProcess(postProcessDistance); e.MoveNext();)
                    {
                        yield return(e.Current);
                    }
                }

                scale = 1f / maxOutside;
                if (maxInside > 0f)
                {
                    for (y = 0; y < height; y++)
                    {
                        for (x = 0; x < width; x++)
                        {
                            float value = 0.5f + (destination.PixelUnSafe(x, y).r -
                                                  Mathf.Clamp01(pixels[x, y].distance * scale)) * 0.5f;
                            SetDestination(x, y, value);
                        }
                    }

                    yield return(QcAsync.CallAgain("Setting Outside Pixels {0}/{1}".F(y, height)));
                }
                else
                {
                    for (y = 0; y < height; y++)
                    {
                        for (x = 0; x < width; x++)
                        {
                            var value = Mathf.Clamp01(1f - pixels[x, y].distance * scale);
                            SetDestination(x, y, value);
                        }

                        yield return(QcAsync.CallAgain("Setting Outside Pixels {0}/{1}".F(y, height)));
                    }
                }
            }


            pixels = null;
        }
Exemplo n.º 4
0
        private static IEnumerator GenerateDistanceTransform()
        {
            int   x = 0, y = 0;
            Pixel p;

            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (y = 0; y < height; y++)
                {
                    for (x = 0; x < width; x++)
                    {
                        pixels[x, y].ResetTransform();
                    }
                }
            }, "Reseting Dist Tf"));

            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (y = 0; y < height; y++)
                {
                    var dy = (y + height) % height;

                    for (x = 0; x < width; x++)
                    {
                        UpdateDistanceSafe(x, dy);
                    }

                    for (x = width - 1; x >= 0; x--)
                    {
                        p = pixels[x, dy];
                        if (p.distance > 0f)
                        {
                            UpdateDistanceSafe(p, x, dy, 1, 0);
                        }
                    }
                }
            }, "Dist down"));

            yield return(QcAsync.CallAfter_Thread(() =>
            {
                for (y = height - 1; y >= -8; y--)
                {
                    var dy = (y + height) % height;

                    for (x = width - 1; x >= 0; x--)
                    {
                        UpdateDistanceSafe(x, dy, 1);
                    }

                    for (x = 0; x < width; x++)
                    {
                        p = pixels[x, dy];
                        if (p.distance > 0f)
                        {
                            UpdateDistanceSafe(p, x, dy, -1, 0);
                        }
                    }
                }
            }, "Dist up"));

            yield return(QcAsync.CallAfter_Thread(() => {
                for (y = -2; y < 7; y++)
                {
                    var dy = (y + height) % height;

                    for (x = 0; x < width; x++)
                    {
                        UpdateDistanceSafe(x, dy);
                    }
                }

                for (y = 6; y > -3; y--)
                {
                    var dy = (y + height) % height;

                    for (x = width - 1; x >= 0; x--)
                    {
                        UpdateDistanceSafe(x, dy, 1);
                    }
                }
            }, "Dist edge"));
        }
Exemplo n.º 5
0
        public override bool Inspect()
        {
            if (ProcessEnumerator != null)
            {
                "Running Coroutine".nl();
                _processEnumerator.Inspect_AsInList();
                return(false);
            }

            var changed = false;

            if ("CPU blit options".conditional_enter(this.TargetIsTexture2D(), ref inspectedItems, 0).nl())
            {
                "Disable Continious Lines".toggleIcon("If you see unwanted lines appearing on the texture as you paint, enable this.", ref disableContiniousLine).nl(ref changed);

                "CPU blit repaint delay".edit("Delay for video memory update when painting to Texture2D", 140, ref _repaintDelay, 0.01f, 0.5f).nl(ref changed);

                "Don't update mipMaps".toggleIcon("May increase performance, but your changes may not disaplay if you are far from texture.",
                                                  ref dontRedoMipMaps).changes(ref changed);
            }

            if ("GPU blit options".enter(ref inspectedItems, 1).nl())
            {
                "Update Texture2D after every stroke".toggleIcon(ref updateTex2DafterStroke).nl();
            }

            #region Processors

            var newWidth  = Cfg.SelectedWidthForNewTexture(); //PainterDataAndConfig.SizeIndexToSize(PainterCamera.Data.selectedWidthIndex);
            var newHeight = Cfg.SelectedHeightForNewTexture();

            if ("Texture Processors".enter(ref inspectedItems, 6).nl())
            {
                if (errorWhileReading)
                {
                    "There was en error reading texture pixels, can't process it".writeWarning();
                }
                else
                {
                    if ("Resize ({0}*{1}) => ({2}*{3})".F(width, height, newWidth, newHeight).enter(ref _inspectedProcess, 0).nl_ifFoldedOut())
                    {
                        "New Width ".select(60, ref PainterCamera.Data.selectedWidthIndex, PainterDataAndConfig.NewTextureSizeOptions).nl(ref changed);

                        "New Height ".select(60, ref PainterCamera.Data.selectedHeightIndex, PainterDataAndConfig.NewTextureSizeOptions).nl(ref changed);

                        if (newWidth != width || newHeight != height)
                        {
                            bool rescale;

                            if (newWidth <= width && newHeight <= height)
                            {
                                rescale = "Downscale".Click();
                            }
                            else if (newWidth >= width && newHeight >= height)
                            {
                                rescale = "Upscale".Click();
                            }
                            else
                            {
                                rescale = "Rescale".Click();
                            }

                            if (rescale)
                            {
                                Resize(newWidth, newHeight);
                            }
                        }
                        pegi.nl();
                    }

                    if (_inspectedProcess == -1)
                    {
                        if ((newWidth != width || newHeight != height) && icon.Size.Click("Resize").nl(ref changed))
                        {
                            Resize(newWidth, newHeight);
                        }

                        pegi.nl();
                    }

                    if ("Clear ".enter(ref _inspectedProcess, 1, false))
                    {
                        "Clear Color".edit(80, ref clearColor).nl();

                        if ("Clear Texture".Click().nl())
                        {
                            Colorize(clearColor);
                            SetApplyUpdateRenderTexture();
                        }
                    }

                    if (_inspectedProcess == -1 && icon.Refresh.Click("Apply color {0}".F(clearColor)).nl())
                    {
                        Colorize(clearColor);
                        SetApplyUpdateRenderTexture();
                    }

                    if ("Color to Alpha".enter(ref _inspectedProcess, 2).nl())
                    {
                        "Background Color".edit(80, ref clearColor).nl();
                        if (Pixels != null)
                        {
                            if ("Color to Alpha".Click("Will Convert Background Color with transparency").nl())
                            {
                                bool wasRt = WasRenderTexture();

                                for (int i = 0; i < _pixels.Length; i++)
                                {
                                    _pixels[i] = BlitFunctions.ColorToAlpha(_pixels[i], clearColor);
                                }

                                SetAndApply();

                                if (wasRt)
                                {
                                    ReturnToRenderTexture();
                                }
                            }

                            if ("Color from Alpha".Click("Will subtract background color from transparency").nl())
                            {
                                bool wasRt = WasRenderTexture();

                                for (int i = 0; i < _pixels.Length; i++)
                                {
                                    var col = _pixels[i];

                                    col.a = BlitFunctions.ColorToAlpha(_pixels[i], clearColor).a;

                                    _pixels[i] = col;
                                }

                                SetAndApply();

                                if (wasRt)
                                {
                                    ReturnToRenderTexture();
                                }
                            }
                        }
                    }

                    if ("Signed Distance Filelds generator".enter(ref _inspectedProcess, 4).nl())
                    {
                        if (texture2D.IsColorTexture())
                        {
                            "Texture is a color texture, best to switch to non-color for SDF. Save any changes first, as the texture will reimport.".writeWarning();

#if UNITY_EDITOR
                            var ai = texture2D.GetTextureImporter();

                            if (ai != null && "Convert to non-Color".ClickConfirm("SDFnc", "This will undo any unsaved changes. Proceed?") && ai.WasWrongIsColor(false))
                            {
                                ai.SaveAndReimport();
                            }
#endif
                        }

                        "Will convert black and white color to black and white signed field".nl();

                        "SDF Max Inside".edit(ref sdfMaxInside).nl();
                        "SDF Max Outside".edit(ref sdfMaxOutside).nl();
                        "SDF Post Process".edit(ref sdfPostProcessDistance).nl();

                        if ("Generate Assync".Click("Will take a bit longer but you'll be able to use Unity"))
                        {
                            bool wasRt = WasRenderTexture();

                            var p = PlaytimePainter.inspected;
                            if (p)
                            {
                                p.UpdateOrSetTexTarget(TexTarget.Texture2D);
                            }

                            _processEnumerator = QcAsync.StartManagedCoroutine(
                                DistanceFieldProcessor.Generate(this, sdfMaxInside, sdfMaxOutside,
                                                                sdfPostProcessDistance), () => {
                                SetAndApply();
                                if (wasRt)
                                {
                                    ReturnToRenderTexture();
                                }
                            });
                        }

                        pegi.nl();
                    }

                    if ("Curves".enter(ref _inspectedProcess, 5).nl())
                    {
                        var crv = TexMGMT.InspectAnimationCurve("Channel");

                        if (Pixels != null)
                        {
                            if ("Remap Alpha".Click())
                            {
                                for (int i = 0; i < _pixels.Length; i++)
                                {
                                    var col = _pixels[i];
                                    col.a      = crv.Evaluate(col.a);
                                    _pixels[i] = col;
                                }
                                SetApplyUpdateRenderTexture();
                            }

                            if ("Remap Color".Click())
                            {
                                for (int i = 0; i < _pixels.Length; i++)
                                {
                                    var col = _pixels[i];
                                    col.r      = crv.Evaluate(col.r);
                                    col.g      = crv.Evaluate(col.g);
                                    col.b      = crv.Evaluate(col.b);
                                    _pixels[i] = col;
                                }
                                SetApplyUpdateRenderTexture();
                            }
                        }
                    }

                    if ("Save Textures In Game ".enter(ref _inspectedProcess, 7).nl())
                    {
                        "This is intended to test playtime saving. The functions to do so are quite simple. You can find them inside ImageData.cs class."
                        .writeHint();

                        pegi.nl();

                        "Save Name".edit(70, ref saveName);

                        if (icon.Folder.Click("Open Folder with textures").nl())
                        {
                            QcFile.Explorer.OpenPersistentFolder(SavedImagesFolder);
                        }

                        if ("Save Playtime".Click("Will save to {0}/{1}".F(Application.persistentDataPath, saveName)).nl())
                        {
                            SaveInPlayer();
                        }

                        if (Cfg && Cfg.playtimeSavedTextures.Count > 0)
                        {
                            "Playtime Saved Textures".write_List(Cfg.playtimeSavedTextures, LoadTexturePegi);
                        }
                    }

                    if ("Fade edges".enter(ref _inspectedProcess, 8).nl())
                    {
                        ("This will cahange pixels on the edges of the texture. Useful when wrap mode " +
                         "is set to clamp.").writeHint();

                        if (texture2D)
                        {
#if UNITY_EDITOR
                            var ti = texture2D.GetTextureImporter();
                            if (ti)
                            {
                                if (ti.wrapMode != TextureWrapMode.Clamp && "Change wrap mode from {0} to Clamp"
                                    .F(ti.wrapMode).Click().nl(ref changed))
                                {
                                    ti.wrapMode = TextureWrapMode.Clamp;
                                    ti.SaveAndReimport();
                                }
                            }
#endif

                            if ("Set edges to transparent".Click().nl(ref changed))
                            {
                                SetEdges(Color.clear, ColorMask.A);
                                SetAndApply();
                            }

                            if ("Set edges to Clear Black".Click().nl(ref changed))
                            {
                                SetEdges(Color.clear);
                                SetAndApply();
                            }
                        }
                    }

                    if ("Add Background".enter(ref _inspectedProcess, 9).nl())
                    {
                        "Background Color".edit(80, ref clearColor).nl();

                        if ("Add Background".Click("Will Add Beckground color and make everything non transparent").nl())
                        {
                            bool wasRt = WasRenderTexture();

                            for (int i = 0; i < _pixels.Length; i++)
                            {
                                _pixels[i] = BlitFunctions.AddBackground(_pixels[i], clearColor);
                            }

                            SetAndApply();

                            if (wasRt)
                            {
                                ReturnToRenderTexture();
                            }
                        }
                    }

                    if ("Offset".enter(ref _inspectedProcess, 10).nl())
                    {
                        "X:".edit(ref _offsetByX);

                        if ((_offsetByX != width / 2) && "{0}/{1}".F(width / 2, width).Click())
                        {
                            _offsetByX = width / 2;
                        }

                        pegi.nl();

                        "Y:".edit(ref _offsetByY);

                        if ((_offsetByY != height / 2) && "{0}/{1}".F(height / 2, height).Click())
                        {
                            _offsetByY = height / 2;
                        }

                        pegi.nl();

                        if (((_offsetByX % width != 0) || (_offsetByY % height != 0)) && "Apply Offset".Click())
                        {
                            OffsetPixels();
                            SetAndApply();
                        }
                    }
                }
            }

            #endregion

            if ("Enable Undo for '{0}'".F(NameForPEGI).toggle_enter(ref enableUndoRedo, ref inspectedItems, 2, ref changed).nl())
            {
                "UNDOs: Tex2D".edit(80, ref _numberOfTexture2DBackups).changes(ref changed);
                "RendTex".edit(60, ref _numberOfRenderTextureBackups).nl(ref changed);

                "Backup manually".toggleIcon(ref backupManually).nl();

                if (_numberOfTexture2DBackups > 50 || _numberOfRenderTextureBackups > 50)
                {
                    "Too big of a number will eat up lot of memory".writeWarning();
                }

                "Creating more backups will eat more memory".writeOneTimeHint("backupIsMem");
                "This are not connected to Unity's Undo/Redo because when you run out of backups you will by accident start undoing other operations.".writeOneTimeHint("noNativeUndo");
                "Use Z/X to undo/redo".writeOneTimeHint("ZxUndoRedo");
            }

            if (inspectedItems == -1)
            {
                if (isAVolumeTexture)
                {
                    "Is A volume texture".toggleIcon(ref isAVolumeTexture).nl(ref changed);
                }
            }

            return(changed);
        }
Exemplo n.º 6
0
        public void CombinedUpdate()
        {
            if (!this || !Data)
            {
                return;
            }

            lastManagedUpdate = QcUnity.TimeSinceStartup();

            if (PlaytimePainter.IsCurrentTool && FocusedPainter)
            {
                FocusedPainter.ManagedUpdateOnFocused();
            }

            QcAsync.UpdateManagedCoroutines();

            MeshManager.CombinedUpdate();

            if (!Application.isPlaying && depthProjectorCamera)
            {
                depthProjectorCamera.ManagedUpdate();
            }

#if UNITY_EDITOR
            if (refocusOnThis)
            {
                _scipFrames--;
                if (_scipFrames == 0)
                {
                    QcUnity.FocusOn(refocusOnThis);
                    refocusOnThis = null;
                    _scipFrames   = 3;
                }
            }
#endif

            var p = PlaytimePainter.currentlyPaintedObjectPainter;

            if (p && !Application.isPlaying && ((QcUnity.TimeSinceStartup() - lastPainterCall) > 0.016f))
            {
                if (p.TexMeta == null)
                {
                    PlaytimePainter.currentlyPaintedObjectPainter = null;
                }
                else
                {
                    p.ProcessStrokeState();
                }
            }

            var needRefresh = false;
            if (CameraModuleBase.modules != null)
            {
                foreach (var pl in CameraModuleBase.modules)
                {
                    if (pl != null)
                    {
                        pl.Update();
                    }
                    else
                    {
                        needRefresh = true;
                    }
                }
            }

            if (needRefresh)
            {
                Debug.Log("Refreshing modules");
                CameraModuleBase.RefreshModules();
            }

            lastPainterCall = QcUnity.TimeSinceStartup();
        }
Exemplo n.º 7
0
        public void CombinedUpdate()
        {
            if (!this || !Data)
            {
                return;
            }

            lastManagedUpdate = Time.time;

            if (PlaytimePainter.IsCurrentTool && focusedPainter)
            {
                focusedPainter.ManagedUpdateOnFocused();
            }

            if (GlobalBrush.previewDirty)
            {
                SHADER_BRUSH_UPDATE();
            }

            QcAsync.UpdateManagedCoroutines();

            MeshManager.CombinedUpdate();

            if (!Application.isPlaying && depthProjectorCamera)
            {
                depthProjectorCamera.ManagedUpdate();
            }

#if UNITY_EDITOR
            if (refocusOnThis)
            {
                _scipFrames--;
                if (_scipFrames == 0)
                {
                    QcUnity.FocusOn(refocusOnThis);
                    refocusOnThis = null;
                    _scipFrames   = 3;
                }
            }
#endif

            var p = PlaytimePainter.currentlyPaintedObjectPainter;

            if (p && !Application.isPlaying && ((Time.time - lastPainterCall) > 0.016f))
            {
                if (p.TexMeta == null)
                {
                    PlaytimePainter.currentlyPaintedObjectPainter = null;
                }
                else
                {
                    p.ProcessStrokeState();
                    //TexMgmtData.brushConfig.Paint(p.stroke, p);
                    //p.ManagedUpdateOnFocused();
                }
            }

            var needRefresh = false;
            if (CameraModuleBase.modules != null)
            {
                foreach (var pl in CameraModuleBase.modules)
                {
                    if (pl != null)
                    {
                        pl.Update();
                    }
                    else
                    {
                        needRefresh = true;
                    }
                }
            }

            if (needRefresh)
            {
                Debug.Log("Refreshing modules");
                CameraModuleBase.RefreshPlugins();
            }

            lastPainterCall = Time.time;
        }