CXX = g++ -std=gnu++0x -g
# -Wall -Werror -Wshadow -pedantic
MAIN = main.o
-OBJ = log.o real.o document.o view.o screen.o vfpu.o stb_truetype.o
+OBJ = log.o real.o document.o view.o screen.o vfpu.o graphicsbuffer.o stb_truetype.o
LIB_x86_64 = ../contrib/lib/libSDL2-2.0.so.0 -lGL
LIB_i386 = ../contrib/lib32/libSDL2-2.0.so.0 -lGL
--- /dev/null
+#include "graphicsbuffer.h"
+#define GL_GLEXT_PROTOTYPES
+#include <SDL_opengl.h>
+#include <GL/glext.h>
+
+using namespace IPDF;
+
+GraphicsBuffer::GraphicsBuffer()
+{
+ SetUsage(BufferUsageStaticDraw);
+}
+
+GraphicsBuffer::~GraphicsBuffer()
+{
+ if (m_map_pointer)
+ {
+ UnMap();
+ }
+ glDeleteBuffers(1, &m_buffer_handle);
+}
+
+void GraphicsBuffer::SetType(GraphicsBuffer::BufferType bufType)
+{
+ glGenBuffers(1, &m_buffer_handle);
+ m_buffer_type = bufType;
+}
+
+void GraphicsBuffer::SetUsage(GraphicsBuffer::BufferUsage bufUsage)
+{
+ m_buffer_usage = bufUsage;
+}
+
+void* GraphicsBuffer::Map(bool read, bool write, bool invalidate)
+{
+ GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_BUFFER_BIT:0);
+ GLenum target = (m_buffer_type == GraphicsBuffer::BufferTypeVertex)?GL_ARRAY_BUFFER:GL_ELEMENT_ARRAY_BUFFER;
+
+ Bind();
+
+ return glMapBufferRange(target, 0, m_buffer_size, access);
+
+ //TODO: Emulate DSA
+ //return glMapNamedBufferEXT(m_bufferHandle, access);
+}
+
+void* GraphicsBuffer::MapRange(int offset, int length, bool read, bool write, bool invalidate)
+{
+ GLbitfield access = ((read)?GL_MAP_READ_BIT:0) | ((write)?GL_MAP_WRITE_BIT:0) | ((invalidate)?GL_MAP_INVALIDATE_RANGE_BIT:0);
+ GLenum target = (m_buffer_type == GraphicsBuffer::BufferTypeVertex)?GL_ARRAY_BUFFER:GL_ELEMENT_ARRAY_BUFFER;
+
+ Bind();
+
+ return glMapBufferRange(target, offset, length, access);
+
+ //TODO: Emulate DSA
+ //return glMapNamedBufferRangeEXT(m_bufferHandle, offset, length, access);
+}
+
+void GraphicsBuffer::UnMap()
+{
+ GLenum target = (m_buffer_type == GraphicsBuffer::BufferTypeVertex)?GL_ARRAY_BUFFER:GL_ELEMENT_ARRAY_BUFFER;
+
+ Bind();
+ glUnmapBuffer(target);
+ //glUnmapNamedBufferEXT(m_bufferHandle);
+}
+
+void GraphicsBuffer::Upload(size_t length, const void* data)
+{
+ GLenum target = (m_buffer_type == GraphicsBuffer::BufferTypeVertex)?GL_ARRAY_BUFFER:GL_ELEMENT_ARRAY_BUFFER;
+
+ GLenum usage;
+ switch (m_buffer_usage)
+ {
+ case BufferUsageStaticDraw:
+ usage = GL_STATIC_DRAW;
+ break;
+ case BufferUsageStaticRead:
+ usage = GL_STATIC_READ;
+ break;
+ case BufferUsageStaticCopy:
+ usage = GL_STATIC_COPY;
+ break;
+ case BufferUsageDynamicDraw:
+ usage = GL_DYNAMIC_DRAW;
+ break;
+ case BufferUsageDynamicRead:
+ usage = GL_DYNAMIC_READ;
+ break;
+ case BufferUsageDynamicCopy:
+ usage = GL_DYNAMIC_COPY;
+ break;
+ case BufferUsageStreamDraw:
+ usage = GL_STREAM_DRAW;
+ break;
+ case BufferUsageStreamRead:
+ usage = GL_STREAM_READ;
+ break;
+ case BufferUsageStreamCopy:
+ usage = GL_STREAM_COPY;
+ break;
+ default:
+ SDL_assert(false && "Unknown buffer usage type.");
+ usage = GL_DYNAMIC_DRAW;
+ }
+
+ Bind();
+ glBufferData(target, length, data, usage);
+ m_buffer_size = length;
+ //glNamedBufferDataEXT(m_bufferHandle, length, data, usage);
+}
+
+void GraphicsBuffer::UploadRange(size_t length, intptr_t offset, const void* data)
+{
+ GLenum target = (m_buffer_type == GraphicsBuffer::BufferTypeVertex)?GL_ARRAY_BUFFER:GL_ELEMENT_ARRAY_BUFFER;
+
+ Bind();
+ glBufferSubData(target, offset, length, data);
+ //glNamedBufferSubDataEXT(m_bufferHandle, offset, length, data);
+}
+
+void GraphicsBuffer::Bind()
+{
+ if (m_buffer_type == BufferTypeVertex)
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer_handle);
+ else if (m_buffer_type == BufferTypeIndex)
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer_handle);
+ else if (m_buffer_type == BufferTypePixelPack)
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, m_buffer_handle);
+ else if (m_buffer_type == BufferTypePixelUnpack)
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_buffer_handle);
+ else if (m_buffer_type == BufferTypeUniform)
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_buffer_handle);
+ else if (m_buffer_type == BufferTypeDrawIndirect)
+ glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_buffer_handle);
+}
+
--- /dev/null
+#ifndef _GRAPHICSBUFFER_H
+#define _GRAPHICSBUFFER_H
+
+#include <SDL.h>
+#define GL_GLEXT_PROTOTYPES
+#include <SDL_opengl.h>
+
+
+namespace IPDF
+{
+ /*
+ * The "Screen" class handles managing the OS window (using SDL2).
+ */
+ class GraphicsBuffer
+ {
+ public:
+ enum BufferType
+ {
+ BufferTypeVertex, // A Vertex Buffer
+ BufferTypeIndex, // An Index Buffer
+ BufferTypePixelPack, // Pixel Pack buffer
+ BufferTypePixelUnpack,
+ BufferTypeUniform, // Uniform/Constant buffer
+ BufferTypeDrawIndirect,
+ };
+
+ enum BufferUsage
+ {
+ BufferUsageStaticDraw,
+ BufferUsageStaticRead,
+ BufferUsageStaticCopy,
+ BufferUsageDynamicDraw,
+ BufferUsageDynamicRead,
+ BufferUsageDynamicCopy,
+ BufferUsageStreamDraw,
+ BufferUsageStreamRead,
+ BufferUsageStreamCopy
+ };
+
+ GraphicsBuffer();
+ ~GraphicsBuffer();
+
+ void SetType(BufferType bufType);
+ void SetUsage(BufferUsage bufUsage);
+
+ void *Map(bool read, bool write, bool invalidate);
+ void *MapRange(int offset, int length, bool read, bool write, bool invalidate);
+
+ void UnMap();
+
+ void Upload(size_t length, const void *data);
+ void UploadRange(size_t length, intptr_t offset, const void *data);
+
+ void Resize(size_t length);
+
+ void Bind();
+ private:
+ GLuint m_buffer_handle;
+ BufferType m_buffer_type;
+ BufferUsage m_buffer_usage;
+ void *m_map_pointer;
+ size_t m_buffer_size;
+ bool m_invalidated;
+ };
+
+}
+
+#endif // _SCREEN_H
}
else
{
- doc.Add(RECT_OUTLINE, Rect(0.5,0.5,1,1));
+ for(int i = 0; i < 1024; ++i)
+ {
+ for (int j = 0; j < 1024; ++j)
+ {
+ doc.Add(((i^j)&1)?RECT_OUTLINE:RECT_FILLED, Rect(0.2+i-512.0,0.2+j-512.0,0.6,0.6));
+ }
+ }
+
}
Rect bounds(b[0],b[1],b[2],b[3]);
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ glMatrixMode(GL_PROJECTION);
glPopMatrix();
}
m_bounds.x += x;
m_bounds.y += y;
Debug("View Bounds => %s", m_bounds.Str().c_str());
+ if (!m_use_gpu_transform)
+ m_bounds_dirty = true;
}
void View::ScaleAroundPoint(Real x, Real y, Real scaleAmt)
m_bounds.w *= scaleAmt;
m_bounds.h *= scaleAmt;
Debug("View Bounds => %s", m_bounds.Str().c_str());
+ if (!m_use_gpu_transform)
+ m_bounds_dirty = true;
}
Rect View::TransformToViewCoords(const Rect& inp) const
}
}
+void glPrimitiveRestartIndex(GLuint index);
+
void View::Render()
{
- static bool debug_output_done = false;
- if (!debug_output_done)
- {
- m_document.DebugDumpObjects();
- debug_output_done = true;
- }
-
-
- //DrawGrid(); // Draw the gridlines
-
+
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (m_use_gpu_transform)
{
glOrtho(0,1,1,0,-1,1);
}
+
+ if (m_bounds_dirty)
+ ReRender();
+
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
-
if (m_colour.a < 1.0f)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
glColor4f(m_colour.r, m_colour.g, m_colour.b, m_colour.a);
- glBegin(GL_QUADS);
+ m_vertex_buffer.Bind();
+ m_index_buffer.Bind();
+ glEnable(GL_PRIMITIVE_RESTART);
+ glPrimitiveRestartIndex(0xFFFFFFFF);
+ glVertexPointer(2, GL_FLOAT, 0, 0);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDrawElements(GL_TRIANGLE_STRIP, m_rendered_filled * 5, GL_UNSIGNED_INT, 0);
+ glDrawElements(GL_LINE_LOOP, m_rendered_outline*5, GL_UNSIGNED_INT,(void*)(sizeof(uint32_t)*m_rendered_filled*5));
+ glDisable(GL_PRIMITIVE_RESTART);
+ if (m_colour.a < 1.0f)
+ {
+ glDisable(GL_BLEND);
+ }
+
+
+}
+
+void View::ReRender()
+{
+ static bool debug_output_done = false;
+ if (!debug_output_done)
+ {
+ m_document.DebugDumpObjects();
+ debug_output_done = true;
+
+ m_vertex_buffer.SetType(GraphicsBuffer::BufferTypeVertex);
+ m_index_buffer.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
+ m_index_buffer.SetType(GraphicsBuffer::BufferTypeIndex);
+
+ m_vertex_buffer.Upload(m_document.ObjectCount() * 8 * sizeof(float), NULL);
+ m_index_buffer.Upload(m_document.ObjectCount() * 5 * sizeof(uint32_t), NULL);
+ }
+ m_rendered_filled = m_rendered_outline = 0;
+
+ if (m_use_gpu_transform)
+ {
+ m_vertex_buffer.SetUsage(GraphicsBuffer::BufferUsageStaticDraw);
+ }
+ else
+ {
+ m_vertex_buffer.SetUsage(GraphicsBuffer::BufferUsageDynamicDraw);
+ }
+
+
+ //DrawGrid(); // Draw the gridlines
+
+
+
+ float *vertexData = (float*)m_vertex_buffer.Map(false, true, true);
+ uint32_t *indexData = (uint32_t*)m_index_buffer.Map(false, true, true);
+
+ uint32_t currentIndex = 0;
for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
{
if (m_document.m_objects.types[id] != RECT_FILLED)
{
obj_bounds = TransformToViewCoords(m_document.m_objects.bounds[id]);
}
- glVertex2f(Float(obj_bounds.x), Float(obj_bounds.y));
- glVertex2f(Float(obj_bounds.x) + Float(obj_bounds.w), Float(obj_bounds.y));
- glVertex2f(Float(obj_bounds.x) + Float(obj_bounds.w), Float(obj_bounds.y) + Float(obj_bounds.h));
- glVertex2f(Float(obj_bounds.x), Float(obj_bounds.y) + Float(obj_bounds.h));
- }
- glEnd();
+ *vertexData = Float(obj_bounds.x); vertexData++;
+ *vertexData = Float(obj_bounds.y); vertexData++;
+ *vertexData = Float(obj_bounds.x) + Float(obj_bounds.w); vertexData++;
+ *vertexData = Float(obj_bounds.y); vertexData++;
+ *vertexData = Float(obj_bounds.x) + Float(obj_bounds.w); vertexData++;
+ *vertexData = Float(obj_bounds.y) + Float(obj_bounds.h); vertexData++;
+ *vertexData = Float(obj_bounds.x); vertexData++;
+ *vertexData = Float(obj_bounds.y) + Float(obj_bounds.h); vertexData++;
+
+ *indexData = currentIndex; indexData++;
+ *indexData = currentIndex+1; indexData++;
+ *indexData = currentIndex+3; indexData++;
+ *indexData = currentIndex+2; indexData++;
+ *indexData = 0xFFFFFFFF; // Primitive restart.
+ indexData++;
+ currentIndex += 4;
+ m_rendered_filled++;
+ }
for (unsigned id = 0; id < m_document.ObjectCount(); ++id)
{
{
obj_bounds = TransformToViewCoords(m_document.m_objects.bounds[id]);
}
- glBegin(GL_LINE_LOOP);
- glVertex2f(Float(obj_bounds.x), Float(obj_bounds.y));
- glVertex2f(Float(obj_bounds.x) + Float(obj_bounds.w), Float(obj_bounds.y));
- glVertex2f(Float(obj_bounds.x) + Float(obj_bounds.w), Float(obj_bounds.y) + Float(obj_bounds.h));
- glVertex2f(Float(obj_bounds.x), Float(obj_bounds.y) + Float(obj_bounds.h));
- glEnd();
+ *vertexData = Float(obj_bounds.x); vertexData++;
+ *vertexData = Float(obj_bounds.y); vertexData++;
+ *vertexData = Float(obj_bounds.x) + Float(obj_bounds.w); vertexData++;
+ *vertexData = Float(obj_bounds.y); vertexData++;
+ *vertexData = Float(obj_bounds.x) + Float(obj_bounds.w); vertexData++;
+ *vertexData = Float(obj_bounds.y) + Float(obj_bounds.h); vertexData++;
+ *vertexData = Float(obj_bounds.x); vertexData++;
+ *vertexData = Float(obj_bounds.y) + Float(obj_bounds.h); vertexData++;
+
+ *indexData = currentIndex; indexData++;
+ *indexData = currentIndex+1; indexData++;
+ *indexData = currentIndex+2; indexData++;
+ *indexData = currentIndex+3; indexData++;
+ *indexData = 0xFFFFFFFF; // Primitive restart.
+ indexData++;
+ currentIndex += 4;
+ m_rendered_outline++;
}
+ m_vertex_buffer.UnMap();
+ m_index_buffer.UnMap();
- if (m_colour.a < 1.0f)
- {
- glDisable(GL_BLEND);
- }
+ m_bounds_dirty = false;
}
#include "ipdf.h"
#include "document.h"
+#include "graphicsbuffer.h"
namespace IPDF
{
{
public:
View(Document & document, const Rect & bounds = Rect(0,0,1,1), const Colour & colour = Colour(0.f,0.f,0.f,1.f))
- : m_document(document), m_bounds(bounds), m_colour(colour), m_use_gpu_transform(false)
+ : m_document(document), m_bounds(bounds), m_colour(colour), m_use_gpu_transform(false), m_bounds_dirty(true)
{
Debug("View Created - Bounds => {%s}", m_bounds.Str().c_str());
}
const Rect& GetBounds() const { return m_bounds; }
const bool UsingGPUTransform() const { return m_use_gpu_transform; }
- void ToggleGPUTransform() { m_use_gpu_transform = (!m_use_gpu_transform); }
+ void ToggleGPUTransform() { m_use_gpu_transform = (!m_use_gpu_transform); m_bounds_dirty = true; }
private:
+ void ReRender();
void DrawGrid();
bool m_use_gpu_transform;
+ bool m_bounds_dirty;
+ GraphicsBuffer m_vertex_buffer;
+ GraphicsBuffer m_index_buffer;
Document & m_document;
Rect m_bounds;
Colour m_colour;
+ uint32_t m_rendered_filled;
+ uint32_t m_rendered_outline;
};
}