public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr)
        {
            var volume = image.texture2D.GetVolumeTextureData();

            if (volume != null)
            {
                if (volume.VolumeJobIsRunning)
                {
                    return(false);
                }

                float volumeScale = volume.size;

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

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

                Blit_Functions.brAlpha = brushAlpha;
                bc.PrepareCPUBlit();
                Blit_Functions.half = bc.Size(true) / volumeScale;

                var pixels = image.Pixels;

                int  ihalf  = (int)(Blit_Functions.half - 0.5f);
                bool smooth = bc.Type(true) != BrushTypePixel.Inst;
                if (smooth)
                {
                    ihalf += 1;
                }

                Blit_Functions._alphaMode = Blit_Functions.SphereAlpha;

                int sliceWidth = texWidth / volume.h_slices;

                int hw = sliceWidth / 2;

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

                for (Blit_Functions.y = -ihalf; Blit_Functions.y < ihalf + 1; Blit_Functions.y++)
                {
                    int h = y + Blit_Functions.y;

                    if (h >= height)
                    {
                        return(true);
                    }

                    if (h >= 0)
                    {
                        int hy         = h / volume.h_slices;
                        int hx         = h % volume.h_slices;
                        int hTex_index = (hy * texWidth + hx) * sliceWidth;

                        for (Blit_Functions.z = -ihalf; Blit_Functions.z < ihalf + 1; Blit_Functions.z++)
                        {
                            int trueZ = z + Blit_Functions.z;

                            if (trueZ >= 0 && trueZ < sliceWidth)
                            {
                                int yTex_index = hTex_index + trueZ * texWidth;

                                for (Blit_Functions.x = -ihalf; Blit_Functions.x < ihalf + 1; Blit_Functions.x++)
                                {
                                    if (Blit_Functions._alphaMode())
                                    {
                                        int trueX = x + Blit_Functions.x;

                                        if (trueX >= 0 && trueX < sliceWidth)
                                        {
                                            int texIndex = yTex_index + trueX;
                                            Blit_Functions._blitMode(ref pixels[texIndex]);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return(true);
            }
            return(false);
        }
        public bool PaintTexture2D(StrokeVector stroke, float brushAlpha, ImageData image, BrushConfig bc, PlaytimePainter pntr)
        {
            if (pntr.IsAtlased())
            {
                Vector2 uvCoords = stroke.uvFrom;

                Vector2 AtlasedSection = GetAtlasedSection();

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

                Blit_Functions.brAlpha = brushAlpha;

                Blit_Functions.half = (bc.Size(false)) / 2;
                int ihalf = Mathf.FloorToInt(Blit_Functions.half - 0.5f);

                bool smooth = bc.Type(true) != BrushTypePixel.Inst;

                if (smooth)
                {
                    Blit_Functions._alphaMode = Blit_Functions.circleAlpha;
                }
                else
                {
                    Blit_Functions._alphaMode = Blit_Functions.noAlpha;
                }

                Blit_Functions._blitMode = bc.BlitMode.BlitFunctionTex2D;

                if (smooth)
                {
                    ihalf += 1;
                }

                Blit_Functions.alpha = 1;

                Blit_Functions.r = bc.mask.GetFlag(BrushMask.R);
                Blit_Functions.g = bc.mask.GetFlag(BrushMask.G);
                Blit_Functions.b = bc.mask.GetFlag(BrushMask.B);
                Blit_Functions.a = bc.mask.GetFlag(BrushMask.A);

                Blit_Functions.csrc = bc.colorLinear.ToGamma();

                MyIntVec2 tmp = image.UvToPixelNumber(uvCoords);//new myIntVec2 (pixIndex);

                int fromx = tmp.x - ihalf;

                tmp.y -= ihalf;


                var pixels = image.Pixels;

                for (Blit_Functions.y = -ihalf; Blit_Functions.y < ihalf + 1; Blit_Functions.y++)
                {
                    tmp.x = fromx;

                    for (Blit_Functions.x = -ihalf; Blit_Functions.x < ihalf + 1; Blit_Functions.x++)
                    {
                        if (Blit_Functions._alphaMode())
                        {
                            int sx = tmp.x - atlasSector.x;
                            int sy = tmp.y - atlasSector.y;

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

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

                        tmp.x += 1;
                    }

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

            return(false);
        }
        void Paint()
        {
            RaycastHit hit;

            // bool anyHits = false;
            //bool anyRecivers = false;
            var texturesNeedUpdate = new List <ImageData>();

            for (int i = 0; i < shoots; i++)
            {
                if (Physics.Raycast(new Ray(transform.position, transform.forward + transform.right * Random.Range(-spread, spread) + transform.up * Random.Range(-spread, spread)), out hit))
                {
                    var recivers             = hit.transform.GetComponentsInParent <PaintingReciever>();
                    PaintingReciever reciver = null;
                    //  Debug.Log("Hit");
                    if (recivers.Length > 0)
                    {
                        var submesh = 0;
                        reciver = recivers[0];

                        // IF FEW SUBMESHES
                        if (hit.collider.GetType() == typeof(MeshCollider))
                        {
                            submesh = ((MeshCollider)hit.collider).sharedMesh.GetSubmeshNumber(hit.triangleIndex);

                            if (recivers.Length > 1)
                            {
                                var mats = reciver.Rendy.materials;

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

                                reciver = null;

                                foreach (var r in recivers)
                                {
                                    if (r.Material == material)
                                    {
                                        reciver = r;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            submesh = reciver.materialIndex;
                        }

                        // ACTUAL PAINTING

                        if (reciver != null)
                        {
                            var tex = reciver.GetTexture();
                            if (tex != null)
                            {
                                var rendTex = (reciver.texture.GetType() == typeof(RenderTexture)) ? (RenderTexture)reciver.texture : null;

                                // WORLD SPACE BRUSH

                                if (rendTex != null)
                                {
                                    var st = new StrokeVector(hit.point)
                                    {
                                        unRepeatedUV = hit.collider.GetType() == typeof(MeshCollider) ?
                                                       (reciver.useTexcoord2 ? hit.textureCoord2 : hit.textureCoord).Floor() : reciver.meshUVoffset,

                                        useTexcoord2 = reciver.useTexcoord2
                                    };

                                    if (reciver.type == PaintingReciever.RendererType.Skinned && reciver.skinnedMeshRenderer != null)
                                    {
                                        BrushTypeSphere.Paint(rendTex, reciver.gameObject, reciver.skinnedMeshRenderer, brush, st, submesh);
                                    }
                                    else if (reciver.type == PaintingReciever.RendererType.regular && reciver.meshFilter != null)
                                    {
                                        var mat = reciver.Material;
                                        if (mat != null && mat.IsAtlased())
                                        {
                                            BrushTypeSphere.PaintAtlased(rendTex, reciver.gameObject,
                                                                         reciver.originalMesh ? reciver.originalMesh : reciver.meshFilter.sharedMesh, brush, st, new List <int> {
                                                submesh
                                            }, (int)mat.GetFloat(PainterDataAndConfig.atlasedTexturesInARow));
                                        }
                                        else
                                        {
                                            BrushTypeSphere.Paint(rendTex, reciver.gameObject,
                                                                  reciver.originalMesh ? reciver.originalMesh : reciver.meshFilter.sharedMesh, brush, st, new List <int> {
                                                submesh
                                            });
                                        }
                                    }
                                }
                                // TEXTURE SPACE BRUSH
                                else if (reciver.texture.GetType() == typeof(Texture2D))
                                {
                                    if (hit.collider.GetType() != typeof(MeshCollider))
                                    {
                                        Debug.Log("Can't get UV coordinates from a Non-Mesh Collider");
                                    }

                                    Blit_Functions.Paint(reciver.useTexcoord2 ? hit.textureCoord2 : hit.textureCoord, 1, (Texture2D)reciver.texture, Vector2.zero, Vector2.one, brush, null);
                                    var id = reciver.texture.GetImgData();

                                    if (!texturesNeedUpdate.Contains(id))
                                    {
                                        texturesNeedUpdate.Add(id);
                                    }
                                }
                                else
                                {
                                    Debug.Log(reciver.gameObject.name + " doesn't have any combination of paintable things setup on his PainterReciver.");
                                }
                            }
                        }
                    }
                }
            }

            foreach (var t in texturesNeedUpdate)
            {
                t.SetAndApply(true);                                   // True for Mipmaps. Best to disable mipmaps on textures and set to false
            }
            //Not to waste performance, don't SetAndApply after each edit, but at the end of the frame (LateUpdate maybe) and only if texture was changed.
            //Mip maps will slow things down, so best is to disable them.


            //   if (!anyHits) Debug.Log("No hits");
            // else if (!anyRecivers) Debug.Log("Attach PaintingReciever script to objects you want to Paint on.");
        }