From: David Gow Date: Wed, 13 Aug 2014 11:49:33 +0000 (+0800) Subject: Automatically generate quadtree children. X-Git-Url: https://git.ucc.asn.au/?a=commitdiff_plain;h=5f25f354c33142215147b1fa3d18445bd0d7a6ee;p=ipdf%2Fcode.git Automatically generate quadtree children. This mostly works, and does the view reparenting. It doesn't do any clipping, so we still hit precision issues as (for example) bézier control points are outside the quadtree node's coordinate system, and become very, very large. There are some issues with the boundaries of quadtree nodes, as the system currently can't display two nodes at once. To compensate, it traverses up the tree until it finds a single node which contains both, though this will be a distant anscestor if the nodes are distantly related. Quadtrees are still disabled by default. There are also a couple of minor changes to the GL code to make it spit out fewer error messages and run slightly faster on some hardware. --- diff --git a/src/document.cpp b/src/document.cpp index 9d9011e..e684f3e 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -107,8 +107,9 @@ QuadTreeIndex Document::GenQuadChild(QuadTreeIndex parent, QuadTreeNodeChildren 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) { - if (ContainedInQuadChild(m_objects.bounds[i], type)) + if (IntersectsQuadChild(m_objects.bounds[i], type)) { + Debug("Adding %s -> %s", m_objects.bounds[i].Str().c_str(), TransformToQuadChild(m_objects.bounds[i], type).Str().c_str()); m_objects.bounds.push_back(TransformToQuadChild(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]); diff --git a/src/graphicsbuffer.cpp b/src/graphicsbuffer.cpp index 91c3478..217fa9a 100644 --- a/src/graphicsbuffer.cpp +++ b/src/graphicsbuffer.cpp @@ -243,13 +243,14 @@ void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* dat void GraphicsBuffer::Resize(size_t length) { - glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, -1, "Resizing buffer."); if (m_invalidated) { m_buffer_size = length; } else { + 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. UnMap(); GLuint old_buffer = m_buffer_handle; @@ -260,8 +261,8 @@ void GraphicsBuffer::Resize(size_t length) glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, m_buffer_size); glDeleteBuffers(1, &old_buffer); m_buffer_size = length; + glPopDebugGroup(); } - glPopDebugGroup(); } void GraphicsBuffer::Bind() const diff --git a/src/quadtree.cpp b/src/quadtree.cpp index 04630b7..2aace7a 100644 --- a/src/quadtree.cpp +++ b/src/quadtree.cpp @@ -24,10 +24,6 @@ Rect TransformToQuadChild(const Rect& src, QuadTreeNodeChildren child_type) Rect TransformFromQuadChild(const Rect& src, QuadTreeNodeChildren child_type) { Rect dst = src; - dst.x *= 0.5; - dst.y *= 0.5; - dst.w *= 0.5; - dst.h *= 0.5; if (child_type == QTC_BOTTOM_LEFT || child_type == QTC_BOTTOM_RIGHT) { dst.y += 1; @@ -36,10 +32,14 @@ Rect TransformFromQuadChild(const Rect& src, QuadTreeNodeChildren child_type) { dst.x += 1; } + dst.x *= 0.5; + dst.y *= 0.5; + dst.w *= 0.5; + dst.h *= 0.5; return dst; } -bool ContainedInQuadChild(const Rect& src, QuadTreeNodeChildren child_type) +bool IntersectsQuadChild(const Rect& src, QuadTreeNodeChildren child_type) { Rect std = {0,0,1,1}; Rect dst = TransformFromQuadChild(std, child_type); @@ -47,6 +47,19 @@ bool ContainedInQuadChild(const Rect& src, QuadTreeNodeChildren child_type) if (src.y + src.h < dst.y) return false; if (src.x > dst.x + dst.w) return false; if (src.y > dst.y + dst.h) return false; + Debug("%s is contained in %s\n", src.Str().c_str(), dst.Str().c_str()); + return true; +} + +bool ContainedInQuadChild(const Rect& src, QuadTreeNodeChildren child_type) +{ + Rect std = {0,0,1,1}; + Rect dst = TransformFromQuadChild(std, child_type); + if (src.x < dst.x) return false; + if (src.y < dst.y) return false; + if (src.x + src.w > dst.x + dst.w) return false; + if (src.y + src.h > dst.y + dst.h) return false; + Debug("%s is contained in %s... \n", src.Str().c_str(), dst.Str().c_str()); return true; } diff --git a/src/quadtree.h b/src/quadtree.h index 61f0a1b..1443650 100644 --- a/src/quadtree.h +++ b/src/quadtree.h @@ -50,6 +50,7 @@ namespace IPDF Rect TransformToQuadChild(const Rect& src, QuadTreeNodeChildren child_type); Rect TransformFromQuadChild(const Rect& src, QuadTreeNodeChildren child_type); + bool IntersectsQuadChild(const Rect& src, QuadTreeNodeChildren child_type); bool ContainedInQuadChild(const Rect& src, QuadTreeNodeChildren child_type); } diff --git a/src/screen.cpp b/src/screen.cpp index c183bf6..27675d5 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -16,6 +16,8 @@ using namespace std; static void opengl_debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* msg, const void *data) { + // Don't print out gl Errors we generated. + if (source == GL_DEBUG_SOURCE_APPLICATION) return; Error("OpenGL Error (%d): %s", id, msg); } diff --git a/src/view.cpp b/src/view.cpp index 749df66..8b1857d 100644 --- a/src/view.cpp +++ b/src/view.cpp @@ -37,7 +37,7 @@ View::View(Document & document, Screen & screen, const Rect & bounds, const Colo #ifndef QUADTREE_DISABLED - m_quadtree_max_depth = 2; + m_quadtree_max_depth = 1; m_current_quadtree_node = document.GetQuadTree().root_id; #endif } @@ -151,18 +151,62 @@ void View::Render(int width, int height) #ifndef QUADTREE_DISABLED if (m_bounds_dirty) { - if (ContainedInQuadChild(m_bounds, QTC_TOP_LEFT) && m_document.GetQuadTree().nodes[m_current_quadtree_node].top_left != QUADTREE_EMPTY) + if (m_bounds.x > 1.0 || m_bounds.x < 0.0 || m_bounds.y > 1.0 || m_bounds.y < 0.0 || m_bounds.w > 1.0 || m_bounds.h > 1.0) { + //TODO: Generate a new parent node. + if (m_document.GetQuadTree().nodes[m_current_quadtree_node].parent != QUADTREE_EMPTY) + { + 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; + } + } + if (ContainedInQuadChild(m_bounds, QTC_TOP_LEFT)) + { + if (m_document.GetQuadTree().nodes[m_current_quadtree_node].top_left == QUADTREE_EMPTY) + { + // We want to reparent into a child node, but none exist. Get the document to create one. + m_document.GenQuadChild(m_current_quadtree_node, QTC_TOP_LEFT); + m_render_dirty = true; + } m_bounds = TransformToQuadChild(m_bounds, QTC_TOP_LEFT); m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].top_left; } - if ((m_bounds.w > 1 || m_bounds.h > 1) && m_document.GetQuadTree().nodes[m_current_quadtree_node].parent != QUADTREE_EMPTY) + if (ContainedInQuadChild(m_bounds, QTC_TOP_RIGHT)) + { + if (m_document.GetQuadTree().nodes[m_current_quadtree_node].top_right == QUADTREE_EMPTY) + { + // We want to reparent into a child node, but none exist. Get the document to create one. + m_document.GenQuadChild(m_current_quadtree_node, QTC_TOP_RIGHT); + m_render_dirty = true; + } + m_bounds = TransformToQuadChild(m_bounds, QTC_TOP_RIGHT); + m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].top_right; + } + if (ContainedInQuadChild(m_bounds, QTC_BOTTOM_LEFT)) + { + if (m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_left == QUADTREE_EMPTY) + { + // We want to reparent into a child node, but none exist. Get the document to create one. + m_document.GenQuadChild(m_current_quadtree_node, QTC_BOTTOM_LEFT); + m_render_dirty = true; + } + m_bounds = TransformToQuadChild(m_bounds, QTC_BOTTOM_LEFT); + m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_left; + } + if (ContainedInQuadChild(m_bounds, QTC_BOTTOM_RIGHT)) { - 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; + if (m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_right == QUADTREE_EMPTY) + { + // We want to reparent into a child node, but none exist. Get the document to create one. + m_document.GenQuadChild(m_current_quadtree_node, QTC_BOTTOM_RIGHT); + m_render_dirty = true; + } + m_bounds = TransformToQuadChild(m_bounds, QTC_BOTTOM_RIGHT); + m_current_quadtree_node = m_document.GetQuadTree().nodes[m_current_quadtree_node].bottom_right; } } - m_screen.DebugFontPrintF("Current View QuadTree Node: %d\n", m_current_quadtree_node); + m_screen.DebugFontPrintF("Current View QuadTree Node: %d (objs: %d -> %d)\n", m_current_quadtree_node, m_document.GetQuadTree().nodes[m_current_quadtree_node].object_begin, + m_document.GetQuadTree().nodes[m_current_quadtree_node].object_end); #endif if (!m_use_gpu_rendering) @@ -293,11 +337,11 @@ void View::UpdateObjBoundsVBO(unsigned first_obj, unsigned last_obj) } else { - m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw); + m_objbounds_vbo.SetUsage(GraphicsBuffer::BufferUsageDynamicCopy); } m_objbounds_vbo.Resize(m_document.ObjectCount()*sizeof(GPUObjBounds)); - BufferBuilder obj_bounds_builder(m_objbounds_vbo.MapRange(first_obj*sizeof(GPUObjBounds), (last_obj-first_obj)*sizeof(GPUObjBounds), false, true, false), m_objbounds_vbo.GetSize()); + BufferBuilder obj_bounds_builder(m_objbounds_vbo.MapRange(first_obj*sizeof(GPUObjBounds), (last_obj-first_obj)*sizeof(GPUObjBounds), false, true, true), m_objbounds_vbo.GetSize()); for (unsigned id = first_obj; id < last_obj; ++id) {