public bool Inspect()
        {
            var changed = false;

            pegi.fullWindowDocumentationClickOpen(Documentation);

            "Bullets:".edit(50, ref shoots, 1, 50).nl(ref changed);
            "Spread:".edit(50, ref spread, 0f, 1f).nl(ref changed);

            if ("Fire!".Click().nl())
            {
                Paint();
            }

            brush.Targets_PEGI().nl(ref changed);
            brush.Mode_Type_PEGI().nl(ref changed);
            brush.ColorSliders().nl(ref changed);

            if (brush.targetIsTex2D)
            {
                "Script expects Render Texture terget".writeWarning();
                pegi.nl();

                if ("Switch to Render Texture".Click())
                {
                    brush.targetIsTex2D = false;
                }
            }
            else if (brush.GetBrushType(false).GetType() != typeof(BrushTypes.Sphere))
            {
                "This script works with Sphere Brush only".writeWarning();
                if ("Switch to Sphere Brush".Click())
                {
                    brush.SetBrushType(false, BrushTypes.Sphere.Inst);
                }
            }


            if (!brush.PaintingRGB)
            {
                "Enable RGB, disable A to use faster Brush Shader (if painting to RenderTexture).".writeHint();
            }

            return(changed);
        }
            public bool BrushConfigPEGI(ref bool overrideBlitMode, BrushConfig br)
            {
                var changed = false;

                var p = InspectedPainter;

                var volTex = p.GetVolumeTexture();

                if (volTex)
                {
                    var tex = volTex.texture;

                    if (tex)
                    {
                        "Volume is a {0} texture".F(tex.IsColorTexture() ? "Color" : "Non-Color Data").write();

#if UNITY_EDITOR
                        if (tex.IsColorTexture())
                        {
                            pegi.nl();
                            var imp = tex.GetTextureImporter();

                            if ((imp != null) && "FIX texture".Click() && (imp.WasWrongIsColor(false)))
                            {
                                imp.SaveAndReimport();
                            }
                        }
#endif


                        pegi.nl();
                    }
                    else
                    {
                        "Volume has no texture".writeWarning();
                    }

                    overrideBlitMode = true;

                    var id = p.TexMeta;

                    var cpuBlit = id.TargetIsTexture2D().nl();

                    br.showingSize = !_enableRayTracing || cpuBlit;

                    if (!cpuBlit)
                    {
                        if (BrushConfig.showAdvanced || _enableRayTracing)
                        {
                            "Ray-Tracing".toggleIcon(ref _enableRayTracing, true).changes(ref changed);

                            if (br.useAlphaBuffer)
                            {
                                icon.Warning.write(
                                    "Ray Tracing doesn't use Alpha buffer. Alpha buffer will be automatically disabled");
                            }
                        }

                        if ("Ray Trace Camera".conditional_enter(
                                _enableRayTracing && PainterCamera.depthProjectorCamera,
                                ref _exploreRayTaceCamera).nl_ifFoldedOut())
                        {
                            "Min".edit(40, ref minFov, 60, maxFov - 1).nl(ref changed);

                            "Max".edit(40, ref maxFov, minFov + 1, 170).nl(ref changed);

                            rayTraceCameraConfiguration.Nested_Inspect().nl(ref changed);
                        }

                        if (smoothing > 0 || BrushConfig.showAdvanced)
                        {
                            pegi.nl();
                            "Smoothing".edit(70, ref smoothing, 0, 1).changes(ref changed);
                            "Best used in the end".fullWindowDocumentationClickOpen();

                            pegi.nl();
                        }

                        if (!_exploreRayTaceCamera && _enableRayTracing)
                        {
                            var dp = PainterCamera.depthProjectorCamera;

                            if (!dp)
                            {
                                if ("Create Projector Camera".Click().nl())
                                {
                                    PainterCamera.GetProjectorCamera();
                                }
                            }
                            else if (dp.pauseAutoUpdates)
                            {
                                pegi.nl();
                                "Light Projectors paused".toggleIcon(ref dp.pauseAutoUpdates).nl(ref changed);
                            }

                            pegi.nl();
                        }
                    }

                    if (!cpuBlit)
                    {
                        pegi.nl();

                        if (!br.GetBrushType(false).IsAWorldSpaceBrush)
                        {
                            "Only World space brush can edit volumes".writeHint();
                            pegi.nl();
                            if ("Change to Sphere brush".Click())
                            {
                                br.SetBrushType(false, BrushTypes.Sphere.Inst);
                            }
                        }
                    }

                    pegi.nl();


                    if (!_exploreRayTaceCamera && PainterCamera.Data.showVolumeDetailsInPainter &&
                        (volTex.name + " " + VolumeEditingExtensions.VolumeSize(id.texture2D, volTex.hSlices))
                        .foldout(ref _exploreVolumeData).nl())
                    {
                        volTex.Nested_Inspect().changes(ref changed);

                        if (volTex.NeedsToManageMaterials)
                        {
                            var painterMaterial = InspectedPainter.Material;
                            if (painterMaterial)
                            {
                                if (!volTex.materials.Contains(painterMaterial))
                                {
                                    if ("Add This Material".Click().nl())
                                    {
                                        volTex.AddIfNew(p);
                                    }
                                }
                            }
                        }
                    }

                    if (!cpuBlit)
                    {
                        MsgPainter.Hardness.GetText()
                        .edit(MsgPainter.Hardness.GetDescription(), 70, ref br.hardness, 1f, 5f).nl(ref changed);
                    }

                    var tmpSpeed = br._dSpeed.Value;
                    if (MsgPainter.Speed.GetText().edit(40, ref tmpSpeed, 0.01f, 4.5f).nl(ref changed))
                    {
                        br._dSpeed.Value = tmpSpeed;
                    }

                    if (br.showingSize)
                    {
                        var maxScale = volTex.size * volTex.Width * 4;

                        "Scale:".edit(40, ref br.brush3DRadius, 0.001f * maxScale, maxScale * 0.5f)
                        .changes(ref changed);

                        if (cpuBlit && !_brushShaderFroRayTrace && br.brush3DRadius > BrushScaleMaxForCpu(volTex))
                        {
                            icon.Warning.write(
                                "Size will be reduced when panting due to low performance of the CPU brush for volumes");
                        }
                    }

                    pegi.nl();
                }

                return(changed);
            }
        private void Paint()
        {
            RaycastHit hit;

            for (var i = 0; i < (continious ? 1 : shoots); i++)
            {
                if (Physics.Raycast(new Ray(transform.position, transform.forward +
                                            (continious ? Vector3.zero :
                                             (transform.right * Random.Range(-spread, spread)
                                              + transform.up * Random.Range(-spread, spread)))
                                            )
                                    , out hit))
                {
                    var receivers = hit.transform.GetComponentsInParent <PaintingReceiver>();

                    if (receivers.Length == 0)
                    {
                        continue;
                    }

                    int subMesh;
                    var receiver = receivers[0];

                    #region Multiple Submeshes
                    if (hit.collider.GetType() == typeof(MeshCollider))
                    {
                        subMesh = ((MeshCollider)hit.collider).sharedMesh.GetSubMeshNumber(hit.triangleIndex);

                        if (receivers.Length > 1)
                        {
                            var mats = receiver.Renderer.materials;

                            var material = mats[subMesh % mats.Length];

                            receiver = receivers.FirstOrDefault(r => r.Material == material);
                        }
                    }
                    else
                    {
                        subMesh = receiver.materialIndex;
                    }

                    #endregion



                    if (!receiver)
                    {
                        continue;
                    }

                    var tex = receiver.GetTexture();

                    if (!tex)
                    {
                        continue;
                    }

                    var rendTex = (receiver.texture.GetType() == typeof(RenderTexture)) ? (RenderTexture)receiver.texture : null;

                    #region  WORLD SPACE BRUSH

                    if (continious)
                    {
                        if (previousTargetForContinious && (receiver != previousTargetForContinious))
                        {
                            continiousStroke.OnMouseUnPressed();
                        }

                        previousTargetForContinious = receiver;
                    }

                    if (rendTex)
                    {
                        var st = continious ? continiousStroke :
                                 new StrokeVector(hit, receiver.useTexcoord2);

                        st.unRepeatedUv = hit.collider.GetType() == typeof(MeshCollider)
                            ? (receiver.useTexcoord2 ? hit.textureCoord2 : hit.textureCoord).Floor()
                            : receiver.meshUvOffset;

                        if (continious)
                        {
                            st.OnMousePressed(hit, receiver.useTexcoord2);
                        }



                        if (receiver.type == PaintingReceiver.RendererType.Skinned && receiver.skinnedMeshRenderer)
                        {
                            BrushTypes.Sphere.Paint(rendTex, receiver.gameObject, receiver.skinnedMeshRenderer, brush, st, subMesh);
                        }
                        else if (receiver.type == PaintingReceiver.RendererType.Regular && receiver.meshFilter)
                        {
                            if (brush.GetBrushType(false) == BrushTypes.Sphere.Inst)
                            {
                                var mat = receiver.Material;
                                if (mat && mat.IsAtlased())
                                {
                                    BrushTypes.Sphere.PaintAtlased(rendTex, receiver.gameObject,
                                                                   receiver.originalMesh
                                            ? receiver.originalMesh
                                            : receiver.meshFilter.sharedMesh, brush, st, new List <int> {
                                        subMesh
                                    },
                                                                   (int)mat.GetFloat(PainterShaderVariables.ATLASED_TEXTURES));
                                }
                                else
                                {
                                    BrushTypes.Sphere.Paint(rendTex, receiver.gameObject,
                                                            receiver.originalMesh
                                            ? receiver.originalMesh
                                            : receiver.meshFilter.sharedMesh, brush, st,
                                                            new List <int> {
                                        subMesh
                                    });
                                }
                            }
                            else
                            {
                                BrushTypes.Normal.Paint(rendTex, brush, st);
                            }

                            break;
                        }
                    }
                    #endregion
                    #region TEXTURE SPACE BRUSH
                    else if (receiver.texture is Texture2D)
                    {
                        if (hit.collider.GetType() != typeof(MeshCollider))
                        {
                            Debug.Log("Can't get UV coordinates from a Non-Mesh Collider");
                        }

                        BlitFunctions.Paint(receiver.useTexcoord2 ? hit.textureCoord2 : hit.textureCoord, 1, (Texture2D)receiver.texture, Vector2.zero, Vector2.one, brush, null);
                        var id = receiver.texture.GetTextureMeta();
                        _texturesNeedUpdate.AddIfNew(id);
                    }
                    #endregion
                    else
                    {
                        Debug.Log(receiver.gameObject.name + " doesn't have any combination of paintable things setup on his PainterReciver.");
                    }
                }
            }
        }
            public void PaintPixelsInRam(StrokeVector stroke, float brushAlpha, TextureMeta image, BrushConfig bc,
                                         PlaytimePainter painter)
            {
                var volume = image.texture2D.GetVolumeTextureData();

                if (!volume)
                {
                    return;
                }

                bc.brush3DRadius = Mathf.Min(BrushScaleMaxForCpu(volume), bc.brush3DRadius);

                var volumeScale = volume.size;

                var pos = (stroke.posFrom - volume.transform.position) / volumeScale + 0.5f * Vector3.one;

                var height   = volume.Height;
                var texWidth = image.width;

                BlitFunctions.brAlpha = brushAlpha;
                bc.PrepareCpuBlit(image);
                BlitFunctions.half = bc.Size(true) / volumeScale;

                var pixels = image.Pixels;

                var iHalf  = (int)(BlitFunctions.half - 0.5f);
                var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst;

                if (smooth)
                {
                    iHalf += 1;
                }

                BlitFunctions.alphaMode = BlitFunctions.SphereAlpha;

                var sliceWidth = texWidth / volume.hSlices;

                var hw = sliceWidth / 2;

                var y = (int)pos.y;
                var z = (int)(pos.z + hw);
                var x = (int)(pos.x + hw);

                for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++)
                {
                    var h = y + BlitFunctions.y;

                    if (h >= height)
                    {
                        return;
                    }

                    if (h < 0)
                    {
                        continue;
                    }
                    var hy        = h / volume.hSlices;
                    var hx        = h % volume.hSlices;
                    var hTexIndex = (hy * texWidth + hx) * sliceWidth;

                    for (BlitFunctions.z = -iHalf; BlitFunctions.z < iHalf + 1; BlitFunctions.z++)
                    {
                        var trueZ = z + BlitFunctions.z;

                        if (trueZ < 0 || trueZ >= sliceWidth)
                        {
                            continue;
                        }
                        var yTexIndex = hTexIndex + trueZ * texWidth;

                        for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++)
                        {
                            if (!BlitFunctions.alphaMode())
                            {
                                continue;
                            }
                            var trueX = x + BlitFunctions.x;

                            if (trueX < 0 || trueX >= sliceWidth)
                            {
                                continue;
                            }
                            var texIndex = yTexIndex + trueX;
                            BlitFunctions.blitMode(ref pixels[texIndex]);
                        }
                    }
                }
            }
        public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, TextureMeta image, BrushConfig bc, PlaytimePainter painter)
        {
            if (!painter.IsAtlased())
            {
                return(false);
            }

            var uvCoords = stroke.uvFrom;

            var atlasedSection = GetAtlasedSection();

            sectorSize = image.width / atlasRows;
            atlasSector.From(atlasedSection * sectorSize);

            BlitFunctions.brAlpha = brushAlpha;

            BlitFunctions.half = (bc.Size(false)) / 2;
            var iHalf = Mathf.FloorToInt(BlitFunctions.half - 0.5f);

            var smooth = bc.GetBrushType(true) != BrushTypes.Pixel.Inst;

            if (smooth)
            {
                BlitFunctions.alphaMode = BlitFunctions.CircleAlpha;
            }
            else
            {
                BlitFunctions.alphaMode = BlitFunctions.NoAlpha;
            }

            BlitFunctions.blitMode = bc.GetBlitMode(true).BlitFunctionTex2D(image);

            if (smooth)
            {
                iHalf += 1;
            }

            BlitFunctions.alpha = 1;


            BlitFunctions.Set(bc.mask);

            BlitFunctions.cSrc = bc.Color;

            var tmp = image.UvToPixelNumber(uvCoords);

            var fromX = tmp.x - iHalf;

            tmp.y -= iHalf;

            var pixels = image.Pixels;

            for (BlitFunctions.y = -iHalf; BlitFunctions.y < iHalf + 1; BlitFunctions.y++)
            {
                tmp.x = fromX;

                for (BlitFunctions.x = -iHalf; BlitFunctions.x < iHalf + 1; BlitFunctions.x++)
                {
                    if (BlitFunctions.alphaMode())
                    {
                        var sx = tmp.x - atlasSector.x;
                        var sy = tmp.y - atlasSector.y;

                        sx %= sectorSize;
                        if (sx < 0)
                        {
                            sx += sectorSize;
                        }
                        sy %= sectorSize;
                        if (sy < 0)
                        {
                            sy += sectorSize;
                        }

                        BlitFunctions.blitMode(ref pixels[((atlasSector.y + sy)) * image.width + (atlasSector.x + sx)]);
                    }

                    tmp.x += 1;
                }

                tmp.y += 1;
            }
            return(true);
        }