Experimental path factory pattern
diff --git a/include/rive/refcnt.hpp b/include/rive/refcnt.hpp
new file mode 100644
index 0000000..cf5792c
--- /dev/null
+++ b/include/rive/refcnt.hpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2021 Rive
+ */
+
+#ifndef _RIVE_REFCNT_HPP_
+#define _RIVE_REFCNT_HPP_
+
+#include <assert.h>
+
+#include <atomic>
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+
+/*
+ *  RefCnt : Threadsafe shared pointer baseclass.
+ *
+ *  The reference count is set to one in the constructor, and goes up on every call to ref(),
+ *  and down on every call to unref(). When a call to unref() brings the counter to 0,
+ *  delete is called on the object.
+ *
+ *  rcp : template wrapper for subclasses of RefCnt, to manage assignment and parameter passing
+ *  to safely keep track of shared ownership.
+ *
+ *  Both of these inspired by Skia's SkRefCnt and sk_sp
+ */
+
+namespace rive {
+
+class RefCnt {
+public:
+    RefCnt() : m_refcnt(1) {}
+
+    virtual ~RefCnt() {
+        assert(this->debugging_refcnt() == 1);
+    }
+
+    void ref() const {
+        (void)m_refcnt.fetch_add(+1, std::memory_order_relaxed);
+    }
+
+    void unref() const {
+        if (1 == m_refcnt.fetch_add(-1, std::memory_order_acq_rel)) {
+#ifndef NDEBUG
+            // we restore the "1" in debug builds just to make our destructor happy
+            (void)m_refcnt.fetch_add(+1, std::memory_order_relaxed);
+#endif
+            delete this;
+        }
+    }
+
+    // not reliable in actual threaded scenarios, but useful (perhaps) for debugging
+    int32_t debugging_refcnt() const {
+        return m_refcnt.load(std::memory_order_relaxed);
+    }
+
+private:
+    mutable std::atomic<int32_t> m_refcnt;
+
+    RefCnt(RefCnt&&) = delete;
+    RefCnt(const RefCnt&) = delete;
+    RefCnt& operator=(RefCnt&&) = delete;
+    RefCnt& operator=(const RefCnt&) = delete;
+};
+
+template <typename T> static inline T* safe_ref(T* obj) {
+    if (obj) {
+        obj->ref();
+    }
+    return obj;
+}
+
+template <typename T> static inline void safe_unref(T* obj) {
+    if (obj) {
+        obj->unref();
+    }
+}
+
+// rcp : smart point template for holding subclasses of RefCnt
+
+template <typename T> class rcp {
+public:
+    constexpr rcp() : m_ptr(nullptr) {}
+    constexpr rcp(std::nullptr_t) : m_ptr(nullptr) {}
+    explicit  rcp(T* ptr) : m_ptr(ptr) {}
+
+    rcp(const rcp<T>& other) : m_ptr(safe_ref(other.get())) {}
+    rcp(rcp<T>&& other) : m_ptr(other.release()) {}
+
+    /**
+     *  Calls unref() on the underlying object pointer.
+     */
+    ~rcp() {
+        safe_unref(m_ptr);
+    }
+
+    rcp<T>& operator=(std::nullptr_t) { this->reset(); return *this; }
+
+    rcp<T>& operator=(const rcp<T>& other) {
+        if (this != &other) {
+            this->reset(safe_ref(other.get()));
+        }
+        return *this;
+    }
+
+    rcp<T>& operator=(rcp<T>&& other) {
+        this->reset(other.release());
+        return *this;
+    }
+
+    T& operator*() const {
+        assert(this->get() != nullptr);
+        return *this->get();
+    }
+
+    explicit operator bool() const { return this->get() != nullptr; }
+
+    T* get() const { return m_ptr; }
+    T* operator->() const { return m_ptr; }
+
+    void reset(T* ptr = nullptr) {
+        // Calling m_ptr->unref() may call this->~() or this->reset(T*).
+        // http://wg21.cmeerw.net/lwg/issue998
+        // http://wg21.cmeerw.net/lwg/issue2262
+        T* oldPtr = m_ptr;
+        m_ptr = ptr;
+        safe_unref(oldPtr);
+    }
+
+    T* release() {
+        T* ptr = m_ptr;
+        m_ptr = nullptr;
+        return ptr;
+    }
+
+    void swap(rcp<T>& other) {
+        std::swap(m_ptr, other.m_ptr);
+    }
+
+private:
+    T* m_ptr;
+};
+
+template <typename T> inline void swap(rcp<T>& a, rcp<T>& b) {
+    a.swap(b);
+}
+
+// == variants
+
+template <typename T> inline bool operator==(const rcp<T>& a, std::nullptr_t) {
+    return !a;
+}
+template <typename T> inline bool operator==(std::nullptr_t, const rcp<T>& b) {
+    return !b;
+}
+template <typename T, typename U> inline bool operator==(const rcp<T>& a, const rcp<U>& b) {
+    return a.get() == b.get();
+}
+
+// != variants
+
+template <typename T> inline bool operator!=(const rcp<T>& a, std::nullptr_t) {
+    return static_cast<bool>(a);
+}
+template <typename T> inline bool operator!=(std::nullptr_t, const rcp<T>& b) {
+    return static_cast<bool>(b);
+}
+template <typename T, typename U> inline bool operator!=(const rcp<T>& a, const rcp<U>& b) {
+    return a.get() != b.get();
+}
+
+} // namespace rive
+
+#endif
+
diff --git a/include/rive/renderer.hpp b/include/rive/renderer.hpp
index 3b4bce5..cc4584b 100644
--- a/include/rive/renderer.hpp
+++ b/include/rive/renderer.hpp
@@ -3,6 +3,7 @@
 
 #include "rive/command_path.hpp"
 #include "rive/layout.hpp"
+#include "rive/refcnt.hpp"
 #include "rive/math/aabb.hpp"
 #include "rive/math/mat2d.hpp"
 #include "rive/shapes/paint/blend_mode.hpp"
@@ -52,18 +53,29 @@
 		int height() const { return m_Height; }
 	};
 
-	class RenderPath : public CommandPath
-	{
-	public:
-		RenderPath* renderPath() override { return this; }
-		void addPath(CommandPath* path, const Mat2D& transform) override
-		{
-			addRenderPath(path->renderPath(), transform);
-		}
+    class RenderPath : public RefCnt {};
 
-		virtual void addRenderPath(RenderPath* path,
-		                           const Mat2D& transform) = 0;
-	};
+    enum class FillRule {
+        nonZero,
+        evenOdd
+    };
+
+    enum class PathVerb {
+        move,
+        line,
+        quad,
+        cubic,
+        close,
+    };
+
+    /*  Returns an immutable RenderPath.
+     *
+     *  ptCount is the logical number of points. Since "pts" is passed as
+     *  an array of floats, there will be 2*ptCount number of floats in the array.
+     */
+    extern rcp<RenderPath> makeRenderPath(const float pts[], int ptCount,
+                                          const uint8_t verbs[], int verbCount,
+                                          FillRule);
 
 	class Renderer
 	{
@@ -72,8 +84,8 @@
 		virtual void save() = 0;
 		virtual void restore() = 0;
 		virtual void transform(const Mat2D& transform) = 0;
-		virtual void drawPath(RenderPath* path, RenderPaint* paint) = 0;
-		virtual void clipPath(RenderPath* path) = 0;
+		virtual void drawPath(rcp<RenderPath> path, RenderPaint* paint) = 0;
+		virtual void clipPath(rcp<RenderPath> path) = 0;
 		virtual void
 		drawImage(RenderImage* image, BlendMode value, float opacity) = 0;
 
@@ -168,8 +180,7 @@
 		}
 	};
 
-	extern RenderPath* makeRenderPath();
 	extern RenderPaint* makeRenderPaint();
 	extern RenderImage* makeRenderImage();
 } // namespace rive
-#endif
\ No newline at end of file
+#endif