update skia renderer
diff --git a/include/rive/renderer.hpp b/include/rive/renderer.hpp
index dcd3b83..0053fa7 100644
--- a/include/rive/renderer.hpp
+++ b/include/rive/renderer.hpp
@@ -117,7 +117,7 @@
         virtual void transform(const Mat2D& transform) = 0;
         virtual void drawPath(RenderPath* path, RenderPaint* paint) = 0;
         virtual void clipPath(RenderPath* path) = 0;
-        virtual void drawImage(RenderImage*, BlendMode, float opacity) = 0;
+        virtual void drawImage(const RenderImage*, BlendMode, float opacity) = 0;
         virtual void drawImageMesh(const RenderImage*,
                                    rcp<RenderBuffer> vertices_f32,
                                    rcp<RenderBuffer> uvCoords_f32,
diff --git a/skia/renderer/include/skia_renderer.hpp b/skia/renderer/include/skia_renderer.hpp
index f28dfa7..74f78ff 100644
--- a/skia/renderer/include/skia_renderer.hpp
+++ b/skia/renderer/include/skia_renderer.hpp
@@ -63,8 +63,13 @@
         void transform(const Mat2D& transform) override;
         void clipPath(RenderPath* path) override;
         void drawPath(RenderPath* path, RenderPaint* paint) override;
-        void drawImage(RenderImage*, BlendMode, float opacity) override;
-        void drawMesh(const RenderMesh*, const RenderShader*, BlendMode, float opacity) override;
+        void drawImage(const RenderImage*, BlendMode, float opacity) override;
+        void drawImageMesh(const RenderImage*,
+                           rcp<RenderBuffer> vertices_f32,
+                           rcp<RenderBuffer> uvCoords_f32,
+                           rcp<RenderBuffer> indices_u16,
+                           BlendMode,
+                           float opacity) override;
     };
 } // namespace rive
 #endif
diff --git a/skia/renderer/src/skia_renderer.cpp b/skia/renderer/src/skia_renderer.cpp
index 6cafdc4..430a13f 100644
--- a/skia/renderer/src/skia_renderer.cpp
+++ b/skia/renderer/src/skia_renderer.cpp
@@ -25,7 +25,7 @@
         free(m_Buffer);
     }
 
-    const float* f32s() {
+    const float* f32s() const {
         assert(m_ElemSize == sizeof(float));
         return static_cast<const float*>(m_Buffer);
     }
@@ -34,6 +34,14 @@
         assert(m_ElemSize == sizeof(uint16_t));
         return static_cast<const uint16_t*>(m_Buffer);
     }
+    
+    const SkPoint* points() const {
+        return reinterpret_cast<const SkPoint*>(this->f32s());
+    }
+
+    static const SkiaBuffer* Cast(const RenderBuffer* buffer) {
+        return reinterpret_cast<const SkiaBuffer*>(buffer);
+    }
 };
 
 template <typename T> rcp<RenderBuffer> make_buffer(const T src[], size_t count) {
@@ -47,13 +55,6 @@
     sk_sp<SkShader> shader;
 };
 
-class SkiaRenderMesh : public RenderMesh {
-public:
-    SkiaRenderMesh(sk_sp<SkVertices> vt) : vertices(std::move(vt)) {}
-
-    sk_sp<SkVertices> vertices;
-};
-
 void SkiaRenderPath::fillRule(FillRule value) {
     switch (value) {
         case FillRule::evenOdd:
@@ -123,31 +124,52 @@
     m_Canvas->clipPath(reinterpret_cast<SkiaRenderPath*>(path)->path(), true);
 }
 
-void SkiaRenderer::drawImage(RenderImage* image,
+void SkiaRenderer::drawImage(const RenderImage* image,
                              BlendMode blendMode,
                              float opacity) {
     SkPaint paint;
     paint.setAlphaf(opacity);
     paint.setBlendMode(ToSkia::convert(blendMode));
-    auto skiaImage = reinterpret_cast<SkiaRenderImage*>(image);
-    SkSamplingOptions samplingOptions(SkFilterMode::kLinear,
-                                      SkMipmapMode::kNone);
-    m_Canvas->drawImage(
-        skiaImage->skImage(), 0.0f, 0.0f, samplingOptions, &paint);
+    auto skiaImage = reinterpret_cast<const SkiaRenderImage*>(image);
+    SkSamplingOptions sampling(SkFilterMode::kLinear);
+    m_Canvas->drawImage(skiaImage->skImage(), 0.0f, 0.0f, sampling, &paint);
 }
 
-void SkiaRenderer::drawMesh(const RenderMesh* mesh,
-                            const RenderShader* shader,
-                            BlendMode mode,
-                            float opacity) {
-    auto skmesh = reinterpret_cast<const SkiaRenderMesh*>(mesh);
-    auto skshader = reinterpret_cast<const SkiaRenderShader*>(shader);
+void SkiaRenderer::drawImageMesh(const RenderImage* image,
+                                 rcp<RenderBuffer> vertices,
+                                 rcp<RenderBuffer> uvCoords,
+                                 rcp<RenderBuffer> indices,
+                                 BlendMode blendMode,
+                                 float opacity) {
+    // need our vertices and uvs to agree
+    assert(vertices->count() == uvCoords->count());
+    // vertices and uvs are arrays of floats, so we need their counts to be even,
+    // since we treat them as arrays of points
+    assert((vertices->count() & 1) == 0);
+
+    auto skiaImage = reinterpret_cast<const SkiaRenderImage*>(image)->skImage();
+    const SkSamplingOptions sampling(SkFilterMode::kLinear);
+    auto shader = skiaImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
+                                        sampling, nullptr);
 
     SkPaint paint;
-    paint.setBlendMode(ToSkia::convert(mode));
     paint.setAlphaf(opacity);
-    paint.setShader(skshader->shader);
-    m_Canvas->drawVertices(skmesh->vertices, SkBlendMode::kModulate, paint);
+    paint.setBlendMode(ToSkia::convert(blendMode));
+    paint.setShader(shader);
+
+    const SkColor* no_colors = nullptr;
+    auto vertexMode = SkVertices::kTriangles_VertexMode;
+    const int vertexCount = vertices->count() >> 1;
+    auto vt = SkVertices::MakeCopy(vertexMode,
+                                   vertexCount,
+                                   SkiaBuffer::Cast(vertices.get())->points(),
+                                   SkiaBuffer::Cast(uvCoords.get())->points(),
+                                   no_colors,
+                                   indices->count(),
+                                   SkiaBuffer::Cast(indices.get())->u16s());
+
+    // The blend mode is ignored if we don't have colors && uvs
+    m_Canvas->drawVertices(vt, SkBlendMode::kModulate, paint);
 }
 
 bool SkiaRenderImage::decode(const uint8_t* bytes, std::size_t size) {
@@ -216,17 +238,4 @@
                                              0, &lm);
        return rcp<RenderShader>(new SkiaRenderShader(std::move(sh)));
    }
-
-    rcp<RenderMesh> makeMesh(int vertexCount, const float vertices[], const float texCoords[],
-                             int indexCount, const uint16_t indices[])
-    {
-        const SkColor* colors = nullptr;
-        auto mode = SkVertices::kTriangles_VertexMode;
-        auto vt = SkVertices::MakeCopy(mode, vertexCount,
-                                       (const SkPoint*)vertices,
-                                       (const SkPoint*)texCoords,
-                                       colors,
-                                       indexCount, indices);
-        return rcp<RenderMesh>(new SkiaRenderMesh(std::move(vt)));
-    }
 } // namespace rive