//Debug("%u turning points", turns.size());
for (unsigned i = 1; i < turns.size(); ++i)
{
- tu = turns[i];
+ if (tl > max) break;
+ tu = std::min(turns[i],tu);
CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
tl = turns[i];
}
- tu = max;
- CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
+ if (tu < max)
+ {
+ tu = max;
+ CubicSolveSegment(roots, a, b, c, d, tl, tu,delta);
+ }
return roots;
}
m_doc.AddText(msg, scale, xx, yy);
#ifndef QUADTREE_DISABLED
m_doc.PropagateQuadChanges(m_view.GetCurrentQuadtreeNode());
+ // We may have split the object across up-to four nodes, so try the neighbouring nodes.
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 0, 1, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 0, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 1, 0));
#endif
m_view.ForceRenderDirty();
m_view.ForceBufferDirty();
m_doc.ParseSVG(m_text_edit->toPlainText().toStdString(), bounds);
#ifndef QUADTREE_DISABLED
m_doc.PropagateQuadChanges(m_view.GetCurrentQuadtreeNode());
+ // We may have split the object across up-to four nodes, so try the neighbouring nodes.
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 0, 1, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 0, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 1, 0));
#endif
m_view.ForceRenderDirty();
m_view.ForceBufferDirty();
m_doc.LoadSVG(filename.toStdString(), bounds);
#ifndef QUADTREE_DISABLED
m_doc.PropagateQuadChanges(m_view.GetCurrentQuadtreeNode());
+ // We may have split the object across up-to four nodes, so try the neighbouring nodes.
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 0, 1, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 0, 0));
+ m_doc.PropagateQuadChanges(m_doc.GetQuadTree().GetNeighbour(m_view.GetCurrentQuadtreeNode(), 1, 1, 0));
#endif
m_view.ForceRenderDirty();
m_view.ForceBufferDirty();
#endif
#ifndef QUADTREE_DISABLED
view->Doc().PropagateQuadChanges(view->GetCurrentQuadtreeNode());
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 0, 1, 0));
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 1, 0, 0));
+ view->Doc().PropagateQuadChanges(view->Doc().GetQuadTree().GetNeighbour(view->GetCurrentQuadtreeNode(), 1, 1, 0));
#endif
currentAction.type = AT_WaitFrame;
view->ForceRenderDirty();
PROFILE_SCOPE("Document::GenQuadChild()");
QuadTreeIndex new_index = m_quadtree.nodes.size();
Debug("-------------- Generating Quadtree Node %d (parent %d, type %d) ----------------------", new_index, parent, type);
- m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, parent, type, 0, 0, -1});
+ m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, parent, type, 0, 0, -1, true});
m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
for (QuadTreeIndex overlay = parent; overlay != -1; overlay = m_quadtree.nodes[overlay].next_overlay)
PROFILE_SCOPE("Document::OverlayQuadChildren()");
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.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, orig_parent, type, 0, 0, -1, true});
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)
{
PROFILE_SCOPE("Document::OverlayQuadParent()");
QuadTreeIndex new_index = m_quadtree.nodes.size();
- m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1});
+ m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1, true});
m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
m_quadtree.nodes[new_index].object_dirty = m_objects.bounds.size();
{
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));
+ Rect new_bounds = TransformFromQuadChild(m_objects.bounds[i], type);
+ // If the object is too small to be seen, discard it.
+ if (!new_bounds.w || !new_bounds.h) continue;
+ m_objects.bounds.push_back(new_bounds);
m_objects.types.push_back(m_objects.types[i]);
m_objects.data_indices.push_back(m_objects.data_indices[i]);
m_count++;
QuadTreeIndex prev_overlay = orig_node;
while (m_quadtree.nodes[prev_overlay].next_overlay != -1) prev_overlay = m_quadtree.nodes[prev_overlay].next_overlay;
m_quadtree.nodes[prev_overlay].next_overlay = new_index;
+ Debug("OverlayQuadParent(%d, %d, %d) = %d", orig_child, child, type, new_index);
// Recurse into any extant parent.
if (m_quadtree.nodes[orig_node].parent != -1)
if (m_quadtree.nodes[overlay].object_dirty == m_quadtree.nodes[overlay].object_end) continue;
// Recurse into our parent, should we have any.
if (m_quadtree.nodes[node].parent != -1)
- OverlayQuadParent(node, overlay, m_quadtree.nodes[overlay].child_type);
+ OverlayQuadParent(node, overlay, m_quadtree.nodes[node].child_type);
// Recurse into any extant children.
if (m_quadtree.nodes[node].top_left != -1)
OverlayQuadChildren(node, overlay, QTC_TOP_LEFT);
QuadTreeIndex Document::GenQuadParent(QuadTreeIndex child, QuadTreeNodeChildren type)
{
QuadTreeIndex new_index = m_quadtree.nodes.size();
- m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1});
+ m_quadtree.nodes.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1, true});
m_quadtree.nodes[new_index].object_begin = m_objects.bounds.size();
for (QuadTreeIndex overlay = child; overlay != -1; overlay = m_quadtree.nodes[overlay].next_overlay)
{
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));
+ Rect new_bounds = TransformFromQuadChild(m_objects.bounds[i], type);
+ // If the object is too small to be seen, discard it.
+ if (!new_bounds.w || !new_bounds.h) continue;
+ m_objects.bounds.push_back(new_bounds);
m_objects.types.push_back(m_objects.types[i]);
m_objects.data_indices.push_back(m_objects.data_indices[i]);
m_count++;
{
PROFILE_SCOPE("Document::Add");
Rect new_bounds = bounds;
- int num_added = 1;
- bool still_to_add = true;
#ifndef QUADTREE_DISABLED
+ int num_added = 1;
if (qti == -1) qti = m_current_insert_node;
if (qti != -1)
{
// Move the object to the quadtree node it should be in.
m_quadtree.GetCanonicalCoords(qti, new_bounds.x, new_bounds.y, this);
Rect cliprect = Rect(0,0,1,1);
- // If an object spans multiple quadtree nodes...
- if (!cliprect.Contains(new_bounds))
- {
- num_added = AddClip(type, new_bounds, data_index, cliprect);
- still_to_add = false;
- }
+ num_added = AddClip(type, new_bounds, data_index, cliprect);
}
+ else
#endif
- if (still_to_add)
{
m_objects.types.push_back(type);
m_objects.bounds.push_back(new_bounds);
m_objects.data_indices.push_back(data_index);
}
+ m_document_dirty = true;
#ifndef QUADTREE_DISABLED
if (qti != -1)
{
if (m_count == m_quadtree.nodes[new_qti].object_end+1)
{
m_quadtree.nodes[new_qti].object_end += num_added;
- goto done;
+ m_quadtree.nodes[new_qti].render_dirty = true;
+ new_qti = -1;
+ break;
}
new_qti = m_quadtree.nodes[new_qti].next_overlay;
}
+ if (new_qti != -1)
{
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.push_back(QuadTreeNode{QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, QUADTREE_EMPTY, -1, QTC_UNKNOWN, 0, 0, -1});
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+num_added;
m_quadtree.nodes[overlay].next_overlay = -1;
+ m_quadtree.nodes[overlay].render_dirty = true;
m_quadtree.nodes[new_qti].next_overlay = overlay;
new_qti = overlay;
}
-done: // matches is not amused, but sulix is nice and moved it inside the #ifdef for him.
- m_count += num_added;
}
+ m_count += num_added;
return m_count-num_added;
#else // words fail me (still not amused)
return (m_count++);
// This sometimes makes Intel corrupt memory?
if (!length) return (m_map_pointer = 0);
+ if ((size_t)(length + offset) > m_buffer_size)
+ Fatal("Tried to map outside of range!");
+
RecreateBuffer();
{
if (!m_buffer_size)
{
+ m_invalidated = true;
m_buffer_size = length;
return;
}
- if (m_invalidated && m_buffer_size >= length)
+ if (m_invalidated)
{
m_buffer_size = length;
- }
- else if (length <= m_buffer_size)
- {
- // Don't need to do anything.
+ m_buffer_shape_dirty = true;
}
else
{
+ size_t oldsize = m_buffer_size;
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Resizing buffer.");
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, NULL, GL_TRUE);
// Create a new buffer and copy the old data into it.
Upload(length, NULL);
glBindBuffer(GL_COPY_READ_BUFFER, old_buffer);
glBindBuffer(GL_COPY_WRITE_BUFFER, m_buffer_handle);
- glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size);
+ glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, oldsize);
glDeleteBuffers(1, &old_buffer);
m_buffer_size = length;
glPopDebugGroup();
if (m_indexes.empty()) return;
unsigned first_index = 0;
- while (m_indexes.size() > first_index && m_indexes[first_index] < first_obj_id) first_index ++;
+ while (m_indexes.size() > first_index && m_indexes[first_index] < first_obj_id)
+ {
+ unsigned new_index = (first_index + first_obj_id) / 2;
+ if (new_index < m_indexes.size() && m_indexes[new_index] < first_obj_id)
+ first_index = new_index;
+ else
+ first_index ++;
+ }
unsigned last_index = first_index;
while (m_indexes.size() > last_index && m_indexes[last_index] < last_obj_id) last_index ++;
#ifndef _PROFILER_H
#define _PROFILER_H
+#include <stdint.h>
#include <map>
#include <string>
#include <stack>
QuadTreeIndex next_overlay;
// First object which has not yet been propagated to extant children/parent.
unsigned object_dirty;
+ bool render_dirty;
};
struct QuadTree
{
g_profiler.BeginZone("View::Render -- Quadtree view bounds management");
// If we're too far zoomed out, become the parent of the current node.
- if ( m_bounds.w > 1.0 || m_bounds.h > 1.0)
+ while ( m_bounds.w > 1.0 || m_bounds.h > 1.0)
{
// If a parent node exists, we'll become it.
//TODO: Generate a new parent node if none exists, and work out when to change child_type
m_bounds = TransformFromQuadChild(m_bounds, m_document.GetQuadTree().nodes[m_current_quadtree_node].child_type);
m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].parent;
}
+ else break;
}
// If we have a parent... (This prevents some crashes, but should disappear.)
// Otherwise, we'll arbitrarily select the bottom-right.
// TODO: Perhaps select based on greatest area?
- if (m_bounds.w < 0.5 || m_bounds.h < 0.5)
+ while (m_bounds.w < 0.5 || m_bounds.h < 0.5)
{
if (m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_right == QUADTREE_EMPTY)
{
#ifdef QUADTREE_DISABLED
RenderRange(width, height, 0, m_document.ObjectCount());
#else
+ // Make sure we update the gpu buffers properly.
+ if (m_document.m_document_dirty)
+ {
+ m_render_dirty = m_buffer_dirty = true;
+ m_document.m_document_dirty = false;
+ }
RenderQuadtreeNode(width, height, m_current_quadtree_node, m_quadtree_max_depth);
#endif
if (!m_use_gpu_rendering)
Rect old_bounds = m_bounds;
if (node == QUADTREE_EMPTY) return;
if (!remaining_depth) return;
- //Debug("Rendering QT node %d, (objs: %d -- %d)\n", node, m_document.GetQuadTree().nodes[node].object_begin, m_document.GetQuadTree().nodes[node].object_end);
m_bounds_dirty = true;
- if (m_document.m_document_dirty)
- {
- m_render_dirty = m_buffer_dirty = true;
- m_document.m_document_dirty = false;
- }
QuadTreeIndex overlay = node;
while(overlay != -1)
{
+ //Debug("Rendering QT node %d, (overlay %d, objs: %d -- %d)\n", node, overlay, m_document.GetQuadTree().nodes[overlay].object_begin, m_document.GetQuadTree().nodes[overlay].object_end);
+ if (m_document.GetQuadTree().nodes[overlay].render_dirty)
+ m_buffer_dirty = m_render_dirty = true;
RenderRange(width, height, m_document.GetQuadTree().nodes[overlay].object_begin, m_document.GetQuadTree().nodes[overlay].object_end);
+ const_cast<bool&>(m_document.GetQuadTree().nodes[overlay].render_dirty) = false;
overlay = m_document.GetQuadTree().nodes[overlay].next_overlay;
}
void View::RenderRange(int width, int height, unsigned first_obj, unsigned last_obj)
{
+ // We don't want to render an empty range,
+ // so don't waste time setting up everything.
+ if (first_obj == last_obj) return;
PROFILE_SCOPE("View::RenderRange");
glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 43, -1, "View::RenderRange()");
if (m_render_dirty) // document has changed
PrepareRender();
+
if (m_buffer_dirty || m_bounds_dirty || !m_lazy_rendering) // object bounds have changed
{
if (m_use_gpu_rendering)
UpdateObjBoundsVBO(first_obj, last_obj);
}
- if (m_use_gpu_transform)
- {
- #ifdef TRANSFORM_OBJECTS_NOT_VIEW
- //Debug("Transform objects, not view");
- GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
- 0.0f, 0.0f, float(width), float(height)};
- #else
- GLfloat glbounds[] = {static_cast<GLfloat>(Float(m_bounds.x)), static_cast<GLfloat>(Float(m_bounds.y)), static_cast<GLfloat>(Float(m_bounds.w)), static_cast<GLfloat>(Float(m_bounds.h)),
- 0.0, 0.0, static_cast<GLfloat>(width), static_cast<GLfloat>(height)};
- #endif
- m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
- }
- else
- {
- GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
- 0.0f, 0.0f, float(width), float(height)};
- m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
- }
- m_bounds_dirty = false;
-
// Render using GPU
if (m_use_gpu_rendering)
{
+
+ if (m_use_gpu_transform)
+ {
+ #ifdef TRANSFORM_OBJECTS_NOT_VIEW
+ //Debug("Transform objects, not view");
+ GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, float(width), float(height)};
+ #else
+ GLfloat glbounds[] = {static_cast<GLfloat>(Float(m_bounds.x)), static_cast<GLfloat>(Float(m_bounds.y)), static_cast<GLfloat>(Float(m_bounds.w)), static_cast<GLfloat>(Float(m_bounds.h)),
+ 0.0, 0.0, static_cast<GLfloat>(width), static_cast<GLfloat>(height)};
+ #endif
+ m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
+ }
+ else
+ {
+ GLfloat glbounds[] = {0.0f, 0.0f, 1.0f, 1.0f,
+ 0.0f, 0.0f, float(width), float(height)};
+ m_bounds_ubo.Upload(sizeof(float)*8, glbounds);
+ }
+ m_bounds_dirty = false;
+
if (m_colour.a < 1.0f)
{
glEnable(GL_BLEND);