Browse Source

Shader object

flabbet 1 year ago
parent
commit
c83b3a7b2e

+ 1 - 1
src/PixiEditor.AvaloniaUI/Views/Visuals/SurfaceControl.cs

@@ -72,7 +72,7 @@ internal class SurfaceControl : Control
         {
         {
             result = Stretch.CalculateSize(availableSize, new Size(source.Size.X, source.Size.Y));
             result = Stretch.CalculateSize(availableSize, new Size(source.Size.X, source.Size.Y));
         }
         }
-        else
+        else if(Width > 0 && Height > 0)
         {
         {
             result = Stretch.CalculateSize(availableSize, new Size(Width, Height));
             result = Stretch.CalculateSize(availableSize, new Size(Width, Height));
         }
         }

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs

@@ -18,5 +18,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IImgDataImplementation ImgDataImplementation { get; }
         public IImgDataImplementation ImgDataImplementation { get; }
         public IBitmapImplementation BitmapImplementation { get; }
         public IBitmapImplementation BitmapImplementation { get; }
         public IColorFilterImplementation ColorFilterImplementation { get; set; }
         public IColorFilterImplementation ColorFilterImplementation { get; set; }
+        public IShaderImplementation ShaderImplementation { get; set; }
     }
     }
 }
 }

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPaintImplementation.cs

@@ -28,5 +28,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl
 
 
         public void SetColorFilter(Paint paint, ColorFilter value);
         public void SetColorFilter(Paint paint, ColorFilter value);
         public object GetNativePaint(IntPtr objectPointer);
         public object GetNativePaint(IntPtr objectPointer);
+        public Shader GetShader(Paint paint);
+        public void SetShader(Paint paint, Shader shader);
     }
     }
 }
 }

+ 15 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IShaderImplementation.cs

@@ -0,0 +1,15 @@
+using System;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IShaderImplementation
+{
+    public IntPtr CreateShader();
+    public void Dispose(IntPtr shaderObjPointer);
+    public Shader? CreateFromSksl(string sksl, bool isOpaque, out string errors);
+    public Shader CreateLinearGradient(VecI p1, VecI p2, Color[] colors);
+    public object GetNativeShader(IntPtr objectPointer);
+}

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasImplementation.cs

@@ -38,5 +38,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public void DrawBitmap(IntPtr objPtr, Bitmap bitmap, int x, int y);
         public void DrawBitmap(IntPtr objPtr, Bitmap bitmap, int x, int y);
         public void Dispose(IntPtr objectPointer);
         public void Dispose(IntPtr objectPointer);
         public object GetNativeCanvas(IntPtr objectPointer);
         public object GetNativeCanvas(IntPtr objectPointer);
+        public void DrawPaint(IntPtr objectPointer, Paint paint);
     }
     }
 }
 }

+ 19 - 11
src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs

@@ -10,9 +10,9 @@ using PixiEditor.Numerics;
 namespace PixiEditor.DrawingApi.Core.Surface
 namespace PixiEditor.DrawingApi.Core.Surface
 {
 {
     public delegate void SurfaceChangedEventHandler(RectD? changedRect);
     public delegate void SurfaceChangedEventHandler(RectD? changedRect);
+
     public class Canvas : NativeObject
     public class Canvas : NativeObject
     {
     {
-
         public override object Native => DrawingBackendApi.Current.CanvasImplementation.GetNativeCanvas(ObjectPointer);
         public override object Native => DrawingBackendApi.Current.CanvasImplementation.GetNativeCanvas(ObjectPointer);
         public event SurfaceChangedEventHandler? Changed;
         public event SurfaceChangedEventHandler? Changed;
 
 
@@ -21,6 +21,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
         }
         }
 
 
         public void DrawPixel(VecI position, Paint drawingPaint) => DrawPixel(position.X, position.Y, drawingPaint);
         public void DrawPixel(VecI position, Paint drawingPaint) => DrawPixel(position.X, position.Y, drawingPaint);
+
         public void DrawPixel(int posX, int posY, Paint drawingPaint)
         public void DrawPixel(int posX, int posY, Paint drawingPaint)
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.DrawPixel(ObjectPointer, posX, posY, drawingPaint);
             DrawingBackendApi.Current.CanvasImplementation.DrawPixel(ObjectPointer, posX, posY, drawingPaint);
@@ -34,15 +35,16 @@ namespace PixiEditor.DrawingApi.Core.Surface
         }
         }
 
 
         public void DrawSurface(DrawingSurface original, int x, int y) => DrawSurface(original, x, y, null);
         public void DrawSurface(DrawingSurface original, int x, int y) => DrawSurface(original, x, y, null);
-        
+
         public void DrawSurface(DrawingSurface surfaceToDraw, VecI size, Paint paint)
         public void DrawSurface(DrawingSurface surfaceToDraw, VecI size, Paint paint)
         {
         {
             DrawSurface(surfaceToDraw, size.X, size.Y, paint);
             DrawSurface(surfaceToDraw, size.X, size.Y, paint);
         }
         }
 
 
-        public void DrawImage(Image image, int x, int y) => DrawingBackendApi.Current.CanvasImplementation.DrawImage(ObjectPointer, image, x, y);
-        
-        public void DrawImage(Image image, RectD rect, Paint paint) => 
+        public void DrawImage(Image image, int x, int y) =>
+            DrawingBackendApi.Current.CanvasImplementation.DrawImage(ObjectPointer, image, x, y);
+
+        public void DrawImage(Image image, RectD rect, Paint paint) =>
             DrawingBackendApi.Current.CanvasImplementation.DrawImage(ObjectPointer, image, rect, paint);
             DrawingBackendApi.Current.CanvasImplementation.DrawImage(ObjectPointer, image, rect, paint);
 
 
         public int Save()
         public int Save()
@@ -54,7 +56,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.Restore(ObjectPointer);
             DrawingBackendApi.Current.CanvasImplementation.Restore(ObjectPointer);
         }
         }
-        
+
         public void Scale(float s) => Scale(s, s);
         public void Scale(float s) => Scale(s, s);
 
 
         /// <param name="size">The amount to scale.</param>
         /// <param name="size">The amount to scale.</param>
@@ -93,7 +95,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
             DrawingBackendApi.Current.CanvasImplementation.DrawPath(ObjectPointer, path, paint);
             DrawingBackendApi.Current.CanvasImplementation.DrawPath(ObjectPointer, path, paint);
             Changed?.Invoke(path.Bounds);
             Changed?.Invoke(path.Bounds);
         }
         }
-        
+
         public void DrawPoint(VecI pos, Paint paint)
         public void DrawPoint(VecI pos, Paint paint)
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.DrawPoint(ObjectPointer, pos, paint);
             DrawingBackendApi.Current.CanvasImplementation.DrawPoint(ObjectPointer, pos, paint);
@@ -111,20 +113,20 @@ namespace PixiEditor.DrawingApi.Core.Surface
             DrawingBackendApi.Current.CanvasImplementation.DrawRect(ObjectPointer, x, y, width, height, paint);
             DrawingBackendApi.Current.CanvasImplementation.DrawRect(ObjectPointer, x, y, width, height, paint);
             Changed?.Invoke(new RectD(x, y, width, height));
             Changed?.Invoke(new RectD(x, y, width, height));
         }
         }
-        
+
         public void DrawCircle(int x, int y, int radius, Paint paint)
         public void DrawCircle(int x, int y, int radius, Paint paint)
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.DrawCircle(ObjectPointer, x, y, radius, paint);
             DrawingBackendApi.Current.CanvasImplementation.DrawCircle(ObjectPointer, x, y, radius, paint);
             Changed?.Invoke(new RectD(x - radius, y - radius, radius * 2, radius * 2));
             Changed?.Invoke(new RectD(x - radius, y - radius, radius * 2, radius * 2));
         }
         }
-        
+
         public void DrawRect(RectI rect, Paint paint) => DrawRect(rect.X, rect.Y, rect.Width, rect.Height, paint);
         public void DrawRect(RectI rect, Paint paint) => DrawRect(rect.X, rect.Y, rect.Width, rect.Height, paint);
 
 
         public void ClipPath(VectorPath clipPath) => ClipPath(clipPath, ClipOperation.Intersect);
         public void ClipPath(VectorPath clipPath) => ClipPath(clipPath, ClipOperation.Intersect);
 
 
         public void ClipPath(VectorPath clipPath, ClipOperation clipOperation) =>
         public void ClipPath(VectorPath clipPath, ClipOperation clipOperation) =>
             ClipPath(clipPath, clipOperation, false);
             ClipPath(clipPath, clipOperation, false);
-        
+
         public void ClipPath(VectorPath clipPath, ClipOperation clipOperation, bool antialias)
         public void ClipPath(VectorPath clipPath, ClipOperation clipOperation, bool antialias)
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.ClipPath(ObjectPointer, clipPath, clipOperation, antialias);
             DrawingBackendApi.Current.CanvasImplementation.ClipPath(ObjectPointer, clipPath, clipOperation, antialias);
@@ -140,7 +142,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
             DrawingBackendApi.Current.CanvasImplementation.Clear(ObjectPointer);
             DrawingBackendApi.Current.CanvasImplementation.Clear(ObjectPointer);
             Changed?.Invoke(null);
             Changed?.Invoke(null);
         }
         }
-        
+
         public void Clear(Color color)
         public void Clear(Color color)
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.Clear(ObjectPointer, color);
             DrawingBackendApi.Current.CanvasImplementation.Clear(ObjectPointer, color);
@@ -190,6 +192,12 @@ namespace PixiEditor.DrawingApi.Core.Surface
             Changed?.Invoke(null);
             Changed?.Invoke(null);
         }
         }
 
 
+        public void DrawPaint(Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasImplementation.DrawPaint(ObjectPointer, paint);
+            Changed?.Invoke(null);
+        }
+
         public override void Dispose()
         public override void Dispose()
         {
         {
             DrawingBackendApi.Current.CanvasImplementation.Dispose(ObjectPointer);
             DrawingBackendApi.Current.CanvasImplementation.Dispose(ObjectPointer);

+ 20 - 3
src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Paint.cs

@@ -9,6 +9,9 @@ namespace PixiEditor.DrawingApi.Core.Surface.PaintImpl
     /// </summary>
     /// </summary>
     public class Paint : NativeObject
     public class Paint : NativeObject
     {
     {
+        private ColorFilter? colorFilter;
+        private Shader? shader;
+        
         public override object Native => DrawingBackendApi.Current.PaintImplementation.GetNativePaint(ObjectPointer);
         public override object Native => DrawingBackendApi.Current.PaintImplementation.GetNativePaint(ObjectPointer);
 
 
         public Color Color
         public Color Color
@@ -53,10 +56,24 @@ namespace PixiEditor.DrawingApi.Core.Surface.PaintImpl
             set => DrawingBackendApi.Current.PaintImplementation.SetStrokeWidth(this, value);
             set => DrawingBackendApi.Current.PaintImplementation.SetStrokeWidth(this, value);
         }
         }
         
         
-        public ColorFilter ColorFilter 
+        public ColorFilter ColorFilter
+        {
+            get => colorFilter ??= DrawingBackendApi.Current.PaintImplementation.GetColorFilter(this);
+            set
+            {
+                DrawingBackendApi.Current.PaintImplementation.SetColorFilter(this, value);
+                colorFilter = value;
+            }
+        }
+
+        public Shader Shader
         {
         {
-            get => DrawingBackendApi.Current.PaintImplementation.GetColorFilter(this);
-            set => DrawingBackendApi.Current.PaintImplementation.SetColorFilter(this, value);
+            get => shader ??= DrawingBackendApi.Current.PaintImplementation.GetShader(this);
+            set
+            {
+                DrawingBackendApi.Current.PaintImplementation.SetShader(this, value);
+                shader = value;
+            }
         }
         }
 
 
         public Paint(IntPtr objPtr) : base(objPtr)
         public Paint(IntPtr objPtr) : base(objPtr)

+ 30 - 0
src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Shader.cs

@@ -0,0 +1,30 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+
+public class Shader : NativeObject
+{
+    public override object Native => DrawingBackendApi.Current.ShaderImplementation.GetNativeShader(ObjectPointer);
+    
+    public Shader(IntPtr objPtr) : base(objPtr)
+    {
+    }
+    
+    public static Shader? CreateFromSksl(string sksl, bool isOpaque, out string errors)
+    {
+       return DrawingBackendApi.Current.ShaderImplementation.CreateFromSksl(sksl, isOpaque, out errors);
+    }
+
+    public override void Dispose()
+    {
+        DrawingBackendApi.Current.PaintImplementation.Dispose(ObjectPointer);
+    }
+
+    public static Shader CreateLinearGradient(VecI p1, VecI p2, Color[] colors)
+    {
+        return DrawingBackendApi.Current.ShaderImplementation.CreateLinearGradient(p1, p2, colors);
+    }
+}

+ 33 - 23
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaCanvasImplementation.cs

@@ -19,41 +19,40 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         private readonly SkObjectImplementation<SKBitmap> _bitmapImpl;
         private readonly SkObjectImplementation<SKBitmap> _bitmapImpl;
         private readonly SkObjectImplementation<SKPath> _pathImpl;
         private readonly SkObjectImplementation<SKPath> _pathImpl;
 
 
-        public SkiaCanvasImplementation(SkObjectImplementation<SKPaint> paintImpl, SkObjectImplementation<SKImage> imageImpl, SkObjectImplementation<SKBitmap> bitmapImpl, SkObjectImplementation<SKPath> pathImpl)
+        public SkiaCanvasImplementation(SkObjectImplementation<SKPaint> paintImpl,
+            SkObjectImplementation<SKImage> imageImpl, SkObjectImplementation<SKBitmap> bitmapImpl,
+            SkObjectImplementation<SKPath> pathImpl)
         {
         {
             _paintImpl = paintImpl;
             _paintImpl = paintImpl;
             _imageImpl = imageImpl;
             _imageImpl = imageImpl;
             _bitmapImpl = bitmapImpl;
             _bitmapImpl = bitmapImpl;
             _pathImpl = pathImpl;
             _pathImpl = pathImpl;
         }
         }
-        
+
         public void SetSurfaceImplementation(SkiaSurfaceImplementation surfaceImpl)
         public void SetSurfaceImplementation(SkiaSurfaceImplementation surfaceImpl)
         {
         {
             _surfaceImpl = surfaceImpl;
             _surfaceImpl = surfaceImpl;
         }
         }
-        
+
         public void DrawPixel(IntPtr objectPointer, int posX, int posY, Paint drawingPaint)
         public void DrawPixel(IntPtr objectPointer, int posX, int posY, Paint drawingPaint)
         {
         {
-            ManagedInstances[objectPointer].DrawPoint(
-                posX, 
-                posY, 
-                _paintImpl.ManagedInstances[drawingPaint.ObjectPointer]);
+            var canvas = ManagedInstances[objectPointer];
+            canvas.DrawPoint(posX, posY, _paintImpl.ManagedInstances[drawingPaint.ObjectPointer]);
         }
         }
 
 
         public void DrawSurface(IntPtr objPtr, DrawingSurface drawingSurface, int x, int y, Paint? paint)
         public void DrawSurface(IntPtr objPtr, DrawingSurface drawingSurface, int x, int y, Paint? paint)
         {
         {
-            ManagedInstances[objPtr]
-                .DrawSurface(
-                    _surfaceImpl.ManagedInstances[drawingSurface.ObjectPointer],
-                    x, y, 
-                    paint != null ? _paintImpl.ManagedInstances[paint.ObjectPointer] : null);
+            var canvas = ManagedInstances[objPtr];
+            canvas.DrawSurface(
+                _surfaceImpl.ManagedInstances[drawingSurface.ObjectPointer],
+                x, y,
+                paint != null ? _paintImpl.ManagedInstances[paint.ObjectPointer] : null);
         }
         }
 
 
         public void DrawImage(IntPtr objPtr, Image image, int x, int y)
         public void DrawImage(IntPtr objPtr, Image image, int x, int y)
         {
         {
-            ManagedInstances[objPtr]
-                .DrawImage(
-                    _imageImpl.ManagedInstances[image.ObjectPointer], x, y);
+            var canvas = ManagedInstances[objPtr];
+            canvas.DrawImage(_imageImpl.ManagedInstances[image.ObjectPointer], x, y);
         }
         }
 
 
         public int Save(IntPtr objPtr)
         public int Save(IntPtr objPtr)
@@ -79,15 +78,15 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         public void DrawPath(IntPtr objPtr, VectorPath path, Paint paint)
         public void DrawPath(IntPtr objPtr, VectorPath path, Paint paint)
         {
         {
             ManagedInstances[objPtr].DrawPath(
             ManagedInstances[objPtr].DrawPath(
-                _pathImpl[path.ObjectPointer], 
+                _pathImpl[path.ObjectPointer],
                 _paintImpl[paint.ObjectPointer]);
                 _paintImpl[paint.ObjectPointer]);
         }
         }
 
 
         public void DrawPoint(IntPtr objPtr, VecI pos, Paint paint)
         public void DrawPoint(IntPtr objPtr, VecI pos, Paint paint)
         {
         {
             ManagedInstances[objPtr].DrawPoint(
             ManagedInstances[objPtr].DrawPoint(
-                pos.X, 
-                pos.Y, 
+                pos.X,
+                pos.Y,
                 _paintImpl[paint.ObjectPointer]);
                 _paintImpl[paint.ObjectPointer]);
         }
         }
 
 
@@ -101,12 +100,16 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
 
         public void DrawRect(IntPtr objPtr, int x, int y, int width, int height, Paint paint)
         public void DrawRect(IntPtr objPtr, int x, int y, int width, int height, Paint paint)
         {
         {
-            ManagedInstances[objPtr].DrawRect(x, y, width, height, _paintImpl[paint.ObjectPointer]);
+            SKPaint skPaint = _paintImpl[paint.ObjectPointer];
+            
+            var canvas = ManagedInstances[objPtr];
+            canvas.DrawRect(x, y, width, height, skPaint);
         }
         }
 
 
         public void DrawCircle(IntPtr objPtr, int x, int y, int radius, Paint paint)
         public void DrawCircle(IntPtr objPtr, int x, int y, int radius, Paint paint)
         {
         {
-            ManagedInstances[objPtr].DrawCircle(x, y, radius, _paintImpl[paint.ObjectPointer]);
+            var canvas = ManagedInstances[objPtr];
+            canvas.DrawCircle(x, y, radius, _paintImpl[paint.ObjectPointer]);
         }
         }
 
 
         public void ClipPath(IntPtr objPtr, VectorPath clipPath, ClipOperation clipOperation, bool antialias)
         public void ClipPath(IntPtr objPtr, VectorPath clipPath, ClipOperation clipOperation, bool antialias)
@@ -133,7 +136,14 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
 
 
         public void DrawLine(IntPtr objPtr, VecI from, VecI to, Paint paint)
         public void DrawLine(IntPtr objPtr, VecI from, VecI to, Paint paint)
         {
         {
-            ManagedInstances[objPtr].DrawLine(from.X, from.Y, to.X, to.Y, _paintImpl[paint.ObjectPointer]);
+            var canvas = ManagedInstances[objPtr];
+            canvas.DrawLine(from.X, from.Y, to.X, to.Y, _paintImpl[paint.ObjectPointer]);
+        }
+
+        public void DrawPaint(IntPtr objectPointer, Paint paint)
+        {
+            var canvas = ManagedInstances[objectPointer];
+            canvas.DrawPaint(_paintImpl[paint.ObjectPointer]);
         }
         }
 
 
         public void Flush(IntPtr objPtr)
         public void Flush(IntPtr objPtr)
@@ -171,7 +181,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         {
         {
             ManagedInstances[objPtr].DrawImage(
             ManagedInstances[objPtr].DrawImage(
                 _imageImpl[image.ObjectPointer],
                 _imageImpl[image.ObjectPointer],
-                rect.ToSKRect(), 
+                rect.ToSKRect(),
                 _paintImpl[paint.ObjectPointer]);
                 _paintImpl[paint.ObjectPointer]);
         }
         }
 
 
@@ -183,7 +193,7 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
         public void Dispose(IntPtr objectPointer)
         public void Dispose(IntPtr objectPointer)
         {
         {
             ManagedInstances[objectPointer].Dispose();
             ManagedInstances[objectPointer].Dispose();
-            
+
             ManagedInstances.TryRemove(objectPointer, out _);
             ManagedInstances.TryRemove(objectPointer, out _);
         }
         }
 
 

+ 16 - 1
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaPaintImplementation.cs

@@ -10,11 +10,14 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
     public class SkiaPaintImplementation : SkObjectImplementation<SKPaint>, IPaintImplementation
     public class SkiaPaintImplementation : SkObjectImplementation<SKPaint>, IPaintImplementation
     {
     {
         private readonly SkiaColorFilterImplementation colorFilterImplementation;
         private readonly SkiaColorFilterImplementation colorFilterImplementation;
+        private readonly SkiaShaderImplementation shaderImplementation;
  
  
-        public SkiaPaintImplementation(SkiaColorFilterImplementation colorFilterImpl)
+        public SkiaPaintImplementation(SkiaColorFilterImplementation colorFilterImpl, SkiaShaderImplementation shaderImpl)
         {
         {
             colorFilterImplementation = colorFilterImpl;
             colorFilterImplementation = colorFilterImpl;
+            shaderImplementation = shaderImpl;
         }
         }
+
         
         
         public IntPtr CreatePaint()
         public IntPtr CreatePaint()
         {
         {
@@ -145,6 +148,18 @@ namespace PixiEditor.DrawingApi.Skia.Implementations
             SKPaint skPaint = ManagedInstances[paint.ObjectPointer];
             SKPaint skPaint = ManagedInstances[paint.ObjectPointer];
             skPaint.ColorFilter = colorFilterImplementation[value.ObjectPointer];
             skPaint.ColorFilter = colorFilterImplementation[value.ObjectPointer];
         }
         }
+        
+        public Shader GetShader(Paint paint)
+        {
+            SKPaint skPaint = ManagedInstances[paint.ObjectPointer];
+            return new Shader(skPaint.Shader.Handle);
+        }
+        
+        public void SetShader(Paint paint, Shader shader)
+        {
+            SKPaint skPaint = ManagedInstances[paint.ObjectPointer];
+            skPaint.Shader = shaderImplementation[shader.ObjectPointer];
+        }
 
 
         public object GetNativePaint(IntPtr objectPointer)
         public object GetNativePaint(IntPtr objectPointer)
         {
         {

+ 62 - 0
src/PixiEditor.DrawingApi.Skia/Implementations/SkiaShaderImplementation.cs

@@ -0,0 +1,62 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.PaintImpl;
+using PixiEditor.Numerics;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Skia.Implementations
+{
+    public class SkiaShaderImplementation : SkObjectImplementation<SKShader>, IShaderImplementation
+    {
+        public SkiaShaderImplementation()
+        {
+        }
+
+        public IntPtr CreateShader()
+        {
+            SKShader skShader = SKShader.CreateEmpty();
+            ManagedInstances[skShader.Handle] = skShader;
+            return skShader.Handle;
+        }
+
+        public Shader? CreateFromSksl(string sksl, bool isOpaque, out string errors)
+        {
+            SKRuntimeEffect effect = SKRuntimeEffect.Create(sksl, out errors);
+            
+            if (string.IsNullOrEmpty(errors))
+            {
+                SKShader shader = effect.ToShader(isOpaque);
+                ManagedInstances[shader.Handle] = shader;
+                return new Shader(shader.Handle);
+            }
+            
+            return null;
+        }
+        
+        public Shader CreateLinearGradient(VecI p1, VecI p2, Color[] colors)
+        {
+            SKShader shader = SKShader.CreateLinearGradient(
+                new SKPoint(p1.X, p1.Y), 
+                new SKPoint(p2.X, p2.Y),
+                CastUtility.UnsafeArrayCast<Color, SKColor>(colors),
+                null, 
+                SKShaderTileMode.Clamp);
+            ManagedInstances[shader.Handle] = shader;
+            return new Shader(shader.Handle);
+        }
+
+        public object GetNativeShader(IntPtr objectPointer)
+        {
+            return ManagedInstances[objectPointer]; 
+        }
+
+        public void Dispose(IntPtr shaderObjPointer)
+        {
+            if (!ManagedInstances.TryGetValue(shaderObjPointer, out var shader)) return;
+            shader.Dispose();
+            ManagedInstances.TryRemove(shaderObjPointer, out _);
+        }
+    }
+}