#include <fstream>
#include "../contrib/pugixml-1.4/src/pugixml.cpp"
+#include "transformationtype.h"
#include "stb_truetype.h"
m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, parent, type, 0, 0, -1});
m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
- for (unsigned i = m_quadtree.nodes[parent].object_begin; i < m_quadtree.nodes[parent].object_end; ++i)
+ for (QuadTreeIndex overlay = parent; overlay != -1; overlay = m_quadtree.nodes[overlay].next_overlay)
{
- if (IntersectsQuadChild(m_objects.bounds[i], type))
+ for (unsigned i = m_quadtree.nodes[overlay].object_begin; i < m_quadtree.nodes[overlay].object_end; ++i)
{
- m_count += ClipObjectToQuadChild(i, type);
+ if (IntersectsQuadChild(m_objects.bounds[i], type))
+ {
+ m_count += ClipObjectToQuadChild(i, type);
+ }
}
}
m_quadtree.nodes[new_index].object_end = m_objects.bounds.size();
+ // No objects are dirty.
+ m_quadtree.nodes[new_index].object_dirty = m_objects.bounds.size();
switch (type)
{
case QTC_TOP_LEFT:
return new_index;
}
+void Document::OverlayQuadChildren(QuadTreeIndex orig_parent, QuadTreeIndex parent, QuadTreeNodeChildren type)
+{
+ QuadTreeIndex new_index = m_quadtree.nodes.size();
+ Debug("-------------- Generating Quadtree Node %d (orig %d parent %d, type %d) ----------------------", new_index, orig_parent, parent, type);
+ m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, orig_parent, type, 0, 0, -1});
+
+ m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
+ for (unsigned i = m_quadtree.nodes[parent].object_dirty; i < m_quadtree.nodes[parent].object_end; ++i)
+ {
+ if (IntersectsQuadChild(m_objects.bounds[i], type))
+ {
+ m_count += ClipObjectToQuadChild(i, type);
+ }
+ }
+ m_quadtree.nodes[new_index].object_end = m_objects.bounds.size();
+ QuadTreeIndex orig_node = -1;
+ switch (type)
+ {
+ case QTC_TOP_LEFT:
+ orig_node = m_quadtree.nodes[orig_parent].top_left = new_index;
+ break;
+ case QTC_TOP_RIGHT:
+ orig_node = m_quadtree.nodes[orig_parent].top_right = new_index;
+ break;
+ case QTC_BOTTOM_LEFT:
+ orig_node = m_quadtree.nodes[orig_parent].bottom_left = new_index;
+ break;
+ case QTC_BOTTOM_RIGHT:
+ orig_node = m_quadtree.nodes[orig_parent].bottom_right = new_index;
+ break;
+ default:
+ Fatal("Tried to overlay a QuadTree child of invalid type!");
+ }
+ if (orig_node == -1)
+ Fatal("Tried to overlay a QuadTree child that didn't exist!");
+
+ // Add us to the node's overlay linked list.
+ QuadTreeIndex prev_overlay = orig_node;
+ while (m_quadtree.nodes[prev_overlay].next_overlay != -1);
+ m_quadtree.nodes[prev_overlay].next_overlay = new_index;
+
+ // Recurse into any extant children.
+ if (m_quadtree.nodes[orig_node].top_left != -1)
+ OverlayQuadChildren(orig_node, new_index, QTC_TOP_LEFT);
+ if (m_quadtree.nodes[orig_node].top_right != -1)
+ OverlayQuadChildren(orig_node, new_index, QTC_TOP_RIGHT);
+ if (m_quadtree.nodes[orig_node].bottom_left != -1)
+ OverlayQuadChildren(orig_node, new_index, QTC_BOTTOM_LEFT);
+ if (m_quadtree.nodes[orig_node].bottom_right != -1)
+ OverlayQuadChildren(orig_node, new_index, QTC_BOTTOM_RIGHT);
+
+ m_quadtree.nodes[new_index].object_dirty = m_quadtree.nodes[new_index].object_end;
+}
+
+void Document::PropagateQuadChanges(QuadTreeIndex node)
+{
+ for(QuadTreeIndex overlay = node; overlay != -1; overlay = m_quadtree.nodes[overlay].next_overlay)
+ {
+ // We don't care about clean overlays.
+ if (m_quadtree.nodes[overlay].object_dirty == m_quadtree.nodes[overlay].object_end) continue;
+ // Recurse into any extant children.
+ if (m_quadtree.nodes[node].top_left != -1)
+ OverlayQuadChildren(node, overlay, QTC_TOP_LEFT);
+ if (m_quadtree.nodes[node].top_right != -1)
+ OverlayQuadChildren(node, overlay, QTC_TOP_RIGHT);
+ if (m_quadtree.nodes[node].bottom_left != -1)
+ OverlayQuadChildren(node, overlay, QTC_BOTTOM_LEFT);
+ if (m_quadtree.nodes[node].bottom_right != -1)
+ OverlayQuadChildren(node, overlay, QTC_BOTTOM_RIGHT);
+
+ m_quadtree.nodes[overlay].object_dirty = m_quadtree.nodes[overlay].object_end;
+ }
+}
+
// Reparent a quadtree node, making it the "type" child of a new node.
QuadTreeIndex Document::GenQuadParent(QuadTreeIndex child, QuadTreeNodeChildren type)
{
m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1});
m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
- for (unsigned i = m_quadtree.nodes[child].object_begin; i < m_quadtree.nodes[child].object_end; ++i)
+ for (QuadTreeIndex overlay = child; overlay != -1; overlay = m_quadtree.nodes[overlay].next_overlay)
{
- m_objects.bounds.push_back(TransformFromQuadChild(m_objects.bounds[i], type));
- m_objects.types.push_back(m_objects.types[i]);
- m_objects.data_indices.push_back(m_objects.data_indices[i]);
- m_count++;
+ for (unsigned i = m_quadtree.nodes[overlay].object_begin; i < m_quadtree.nodes[overlay].object_end; ++i)
+ {
+ m_objects.bounds.push_back(TransformFromQuadChild(m_objects.bounds[i], type));
+ m_objects.types.push_back(m_objects.types[i]);
+ m_objects.data_indices.push_back(m_objects.data_indices[i]);
+ m_count++;
+ }
}
m_quadtree.nodes[new_index].object_end = m_objects.bounds.size();
+ m_quadtree.nodes[new_index].object_dirty = m_objects.bounds.size();
switch (type)
{
case QTC_TOP_LEFT:
unsigned data_index = AddPathData(path);
Rect bounds = path.SolveBounds(m_objects);
unsigned result = Add(PATH, bounds,data_index);
+ m_objects.paths[data_index].m_index = result;
//Debug("Added path %u -> %u (%u objects) colour {%u,%u,%u,%u}, stroke {%u,%u,%u,%u}", start_index, end_index, (end_index - start_index), fill.r, fill.g, fill.b, fill.a, stroke.r, stroke.g, stroke.b, stroke.a);
return result;
}
#ifndef QUADTREE_DISABLED
if (qti != -1)
{
- if (m_count == m_quadtree.nodes[qti].object_end+1)
+ QuadTreeIndex new_qti = qti;
+ while (m_quadtree.nodes[new_qti].next_overlay != -1)
{
- m_quadtree.nodes[qti].object_end++;
+ if (m_count == m_quadtree.nodes[new_qti].object_end+1)
+ {
+ m_quadtree.nodes[new_qti].object_end++;
+ goto done;
+ }
+ new_qti = m_quadtree.nodes[new_qti].next_overlay;
}
- else
{
QuadTreeIndex overlay = m_quadtree.nodes.size();
+ Debug("Adding new overlay, nqti = %d, overlay = %d", new_qti, overlay);
m_quadtree.nodes.push_back(m_quadtree.nodes[qti]);
m_quadtree.nodes[overlay].object_begin = m_count;
+ // All objects are dirty.
+ m_quadtree.nodes[overlay].object_dirty = m_count;
m_quadtree.nodes[overlay].object_end = m_count+1;
- m_quadtree.nodes[qti].next_overlay = overlay;
+ m_quadtree.nodes[overlay].next_overlay = -1;
+ m_quadtree.nodes[new_qti].next_overlay = overlay;
+ new_qti = overlay;
}
+done:
+ m_count++;
+ PropagateQuadChanges(qti);
}
#endif
- return (m_count++); // Why can't we just use the size of types or something?
+ return m_count; // Why can't we just use the size of types or something?
}
unsigned Document::AddBezierData(const Bezier & bezier)
if (!result)
Error("Couldn't load \"%s\" - %s", filename.c_str(), result.description());
- Debug("Loaded XML - %s", result.description());
+ Debug("Loaded XML from \"%s\" - %s", filename.c_str(), result.description());
input.close();
// a c e, b d f
}
}
-void Document::TranslateObjects(const Real & dx, const Real & dy)
+void Document::TranslateObjects(const Real & dx, const Real & dy, ObjectType type)
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ for (unsigned i = 0; i < m_objects.paths.size(); ++i)
+ {
+ Path & p = m_objects.paths[i];
+ p.m_bounds.x += dx;
+ p.m_bounds.y += dy;
+ }
+ return;
+ #endif
+
for (unsigned i = 0; i < m_count; ++i)
{
- m_objects.bounds[i].x += dx;
- m_objects.bounds[i].y += dy;
+ if (type == NUMBER_OF_OBJECT_TYPES || m_objects.types[i] == type)
+ {
+ m_objects.bounds[i].x += dx;
+ m_objects.bounds[i].y += dy;
+ }
}
}
-void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount)
+void Document::ScaleObjectsAboutPoint(const Real & x, const Real & y, const Real & scale_amount, ObjectType type)
{
+ #ifdef TRANSFORM_BEZIERS_TO_PATH
+ for (unsigned i = 0; i < m_objects.paths.size(); ++i)
+ {
+ Path & p = m_objects.paths[i];
+ p.m_bounds.w /= scale_amount;
+ p.m_bounds.h /= scale_amount;
+ p.m_bounds.x -= x;
+ p.m_bounds.x /= scale_amount;
+ p.m_bounds.x += x;
+ p.m_bounds.y -= y;
+ p.m_bounds.y /= scale_amount;
+ p.m_bounds.y += y;
+ }
+ return;
+ #endif
+
for (unsigned i = 0; i < m_count; ++i)
{
+ if (type != NUMBER_OF_OBJECT_TYPES && m_objects.types[i] != type)
+ continue;
+
m_objects.bounds[i].w /= scale_amount;
m_objects.bounds[i].h /= scale_amount;
//m_objects.bounds[i].x = x + (m_objects.bounds[i].x-x)/scale_amount;
m_objects.bounds[i].y -= y;
m_objects.bounds[i].y /= scale_amount;
m_objects.bounds[i].y += y;
+ }
- }
-
}
+
+