+
+
+/**
+ * Render Path (shading)
+ */
+void PathRenderer::RenderUsingCPU(Objects & objects, const View & view, const CPURenderTarget & target, unsigned first_obj_id, unsigned last_obj_id)
+{
+
+
+ for (unsigned i = 0; i < m_indexes.size(); ++i)
+ {
+ if (m_indexes[i] < first_obj_id) continue;
+ if (m_indexes[i] >= last_obj_id) continue;
+
+
+
+ Path & path = objects.paths[objects.data_indices[m_indexes[i]]];
+ Rect bounds(CPURenderBounds(path.GetBounds(objects), view, target));
+ PixelBounds pix_bounds(bounds);
+
+ if (view.ShowingFillPoints())
+ {
+
+ PixelPoint start(CPUPointLocation((path.m_top+path.m_left+path.m_right+path.m_bottom)/4, view, target));
+ for (unsigned f = 0; f < path.m_fill_points.size(); ++f)
+ {
+ PixelPoint end(CPUPointLocation(path.m_fill_points[f], view, target));
+ RenderLineOnCPU(start.first, start.second, end.first, end.second, target, Colour(0,0,255,0));
+ }
+ }
+
+ #ifndef TRANSFORM_BEZIERS_TO_PATH
+ if (!view.PerformingShading())
+ continue;
+ for (unsigned b = path.m_start; b <= path.m_end; ++b)
+ {
+ Rect bbounds = view.TransformToViewCoords(objects.bounds[b]);
+ Bezier & bez = objects.beziers[objects.data_indices[b]];
+ BezierRenderer::RenderBezierOnCPU(bez,bbounds,view,target,path.m_stroke);
+ }
+ #else
+ // Outlines still get drawn if using TRANSFORM_BEZIERS_TO_PATH
+ for (unsigned b = path.m_start; b <= path.m_end; ++b)
+ {
+ Colour stroke = (view.PerformingShading()) ? path.m_stroke : Colour(0,0,0,255);
+ // bezier's bounds are relative to this object's bounds, convert back to view bounds
+ Rect bbounds = objects.bounds[b];
+ bbounds.x *= objects.bounds[m_indexes[i]].w;
+ bbounds.x += objects.bounds[m_indexes[i]].x;
+ bbounds.y *= objects.bounds[m_indexes[i]].h;
+ bbounds.y += objects.bounds[m_indexes[i]].y;
+ bbounds.w *= objects.bounds[m_indexes[i]].w;
+ bbounds.h *= objects.bounds[m_indexes[i]].h;
+ bbounds = view.TransformToViewCoords(bbounds);
+ //Debug("Bounds: %s", objects.bounds[m_indexes[i]].Str().c_str());
+ //Debug("Relative Bez Bounds: %s", objects.bounds[b].Str().c_str());
+ //Debug("Bez Bounds: %s", bbounds.Str().c_str());
+
+ Bezier & bez = objects.beziers[objects.data_indices[b]];
+
+ BezierRenderer::RenderBezierOnCPU(bez,bbounds,view,target, stroke);
+ }
+ if (!view.PerformingShading())
+ continue;
+ #endif
+
+
+ if (pix_bounds.w*pix_bounds.h > 100)
+ {
+ vector<Vec2> & fill_points = path.FillPoints(objects, view);
+ Debug("High resolution; use fill points %u,%u", pix_bounds.w, pix_bounds.h);
+ for (unsigned f = 0; f < fill_points.size(); ++f)
+ {
+ PixelPoint fill_point(CPUPointLocation(fill_points[f], view, target));
+
+ FloodFillOnCPU(fill_point.first, fill_point.second, pix_bounds, target, path.m_fill, path.m_stroke);
+ }
+ }
+ else
+ {
+ Debug("Low resolution; use brute force %u,%u",pix_bounds.w, pix_bounds.h);
+ int64_t y_min = max((int64_t)0, pix_bounds.y);
+ int64_t y_max = min(pix_bounds.y+pix_bounds.h, target.h);
+ int64_t x_min = max((int64_t)0, pix_bounds.x);
+ int64_t x_max = min(pix_bounds.x+pix_bounds.w, target.w);
+ for (int64_t y = y_min; y < y_max; ++y)
+ {
+ for (int64_t x = x_min; x < x_max; ++x)
+ {
+ Rect pb(path.SolveBounds(objects));
+ Vec2 pt(pb.x + (Real(x-pix_bounds.x)/Real(pix_bounds.w))*pb.w,
+ pb.y + (Real(y-pix_bounds.y)/Real(pix_bounds.h))*pb.h);
+ if (path.PointInside(objects, pt))
+ {
+ FloodFillOnCPU(x, y, pix_bounds, target, path.m_fill, path.m_stroke);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+