Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configurable line width with modern OpenGL #232

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
4 changes: 3 additions & 1 deletion lib/gl/renderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ class GLDevice

std::array<float, 4> static_color;

float line_w;

protected:
TextureHandle passthrough_texture;

Expand Down Expand Up @@ -139,7 +141,7 @@ class GLDevice
void disableBlend() { glDisable(GL_BLEND); }
void enableDepthWrite() { glDepthMask(GL_TRUE); }
void disableDepthWrite() { glDepthMask(GL_FALSE); }
void setLineWidth(float w) { glLineWidth(w); }
void setLineWidth(float w) { line_w = w; glLineWidth(w); }

virtual void init();
virtual DeviceType getType() = 0;
Expand Down
251 changes: 239 additions & 12 deletions lib/gl/renderer_core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ const std::vector<std::string> CoreGLDevice::unif_list =
"useClipPlane",
"clipPlane",
"containsText",
"expandLines",
"lineWidth",
"aspectRatio",
"modelViewMatrix",
"projectionMatrix",
"textProjMatrix",
Expand All @@ -66,6 +69,84 @@ const std::vector<std::string> CoreGLDevice::unif_list =
"alphaTex"
};

struct alignas(16) CoreGLDevice::LineVertex
{
std::array<float, 3> vtx;
float orientation;
std::array<float, 3> prev;
std::array<float, 3> next;

static constexpr array_layout layout = LAYOUT_EXT_LINE_VTX;

static void Setup()
{
constexpr LineVertex base{};
const size_t vtx_offset = (size_t)(&base.vtx) - (size_t)(&base);
const size_t orient_offset = (size_t)(&base.orientation) - (size_t)(&base);
const size_t prev_offset = (size_t)(&base.prev) - (size_t)(&base);
const size_t next_offset = (size_t)(&base.next) - (size_t)(&base);

glEnableVertexAttribArray(ATTR_VERTEX);
glEnableVertexAttribArray(ATTR_LINE_ORIENT);
glEnableVertexAttribArray(ATTR_LINE_PREV);
glEnableVertexAttribArray(ATTR_LINE_NEXT);

glVertexAttribPointer(ATTR_VERTEX, 3, GL_FLOAT, false, sizeof(LineVertex), (void*)vtx_offset);
glVertexAttribPointer(ATTR_LINE_ORIENT, 1, GL_FLOAT, false, sizeof(LineVertex), (void*)orient_offset);
glVertexAttribPointer(ATTR_LINE_PREV, 3, GL_FLOAT, false, sizeof(LineVertex), (void*)prev_offset);
glVertexAttribPointer(ATTR_LINE_NEXT, 3, GL_FLOAT, false, sizeof(LineVertex), (void*)next_offset);
}

static void Finish()
{
glDisableVertexAttribArray(ATTR_VERTEX);
glDisableVertexAttribArray(ATTR_LINE_ORIENT);
glDisableVertexAttribArray(ATTR_LINE_PREV);
glDisableVertexAttribArray(ATTR_LINE_NEXT);
}
};

struct alignas(16) CoreGLDevice::LineColorVertex
{
std::array<float, 3> vtx;
std::array<uint8_t, 4> color;
float orientation;
std::array<float, 3> prev;
std::array<float, 3> next;

static constexpr array_layout layout = LAYOUT_EXT_LINE_VTX_COLOR;

static void Setup()
{
constexpr LineColorVertex base{};
const size_t vtx_offset = (size_t)(&base.vtx) - (size_t)(&base);
const size_t color_offset = (size_t)(&base.color) - (size_t)(&base);
const size_t orient_offset = (size_t)(&base.orientation) - (size_t)(&base);
const size_t prev_offset = (size_t)(&base.prev) - (size_t)(&base);
const size_t next_offset = (size_t)(&base.next) - (size_t)(&base);
glEnableVertexAttribArray(ATTR_VERTEX);
glEnableVertexAttribArray(ATTR_COLOR);
glEnableVertexAttribArray(ATTR_LINE_ORIENT);
glEnableVertexAttribArray(ATTR_LINE_PREV);
glEnableVertexAttribArray(ATTR_LINE_NEXT);

glVertexAttribPointer(ATTR_VERTEX, 3, GL_FLOAT, false, sizeof(LineColorVertex), (void*)vtx_offset);
glVertexAttribPointer(ATTR_COLOR, 4, GL_UNSIGNED_INT, true, sizeof(LineColorVertex), (void*)color_offset);
glVertexAttribPointer(ATTR_LINE_ORIENT, 1, GL_FLOAT, false, sizeof(LineColorVertex), (void*)orient_offset);
glVertexAttribPointer(ATTR_LINE_PREV, 3, GL_FLOAT, false, sizeof(LineColorVertex), (void*)prev_offset);
glVertexAttribPointer(ATTR_LINE_NEXT, 3, GL_FLOAT, false, sizeof(LineColorVertex), (void*)next_offset);
}

static void Finish()
{
glDisableVertexAttribArray(ATTR_VERTEX);
glDisableVertexAttribArray(ATTR_COLOR);
glDisableVertexAttribArray(ATTR_LINE_ORIENT);
glDisableVertexAttribArray(ATTR_LINE_PREV);
glDisableVertexAttribArray(ATTR_LINE_NEXT);
}
};

template<typename TVtx>
void setupVtxAttrLayout()
{
Expand Down Expand Up @@ -96,7 +177,10 @@ bool CoreGLDevice::compileShaders()
{ CoreGLDevice::ATTR_TEXT_VERTEX, "textVertex"},
{ CoreGLDevice::ATTR_NORMAL, "normal"},
{ CoreGLDevice::ATTR_COLOR, "color"},
{ CoreGLDevice::ATTR_TEXCOORD0, "texCoord0"}
{ CoreGLDevice::ATTR_TEXCOORD0, "texCoord0"},
{ CoreGLDevice::ATTR_LINE_ORIENT, "line_orientation"},
{ CoreGLDevice::ATTR_LINE_PREV, "line_prev_vtx"},
{ CoreGLDevice::ATTR_LINE_NEXT, "line_next_vtx"}
};

if (!default_prgm.create(DEFAULT_VS, DEFAULT_FS, attribMap, 1))
Expand Down Expand Up @@ -246,22 +330,128 @@ void CoreGLDevice::setClipPlaneEqn(const std::array<double, 4> &eqn)

void CoreGLDevice::bufferToDevice(array_layout layout, IVertexBuffer &buf)
{
if (buf.getHandle() == 0)
if (buf.getShape() == GL_LINES &&
(layout == Vertex::layout || layout == VertexColor::layout))
{
if (buf.getHandle() == 0)
{
array_layout ext_layout;
if (layout == Vertex::layout) { ext_layout = LineVertex::layout; }
else if (layout == VertexColor::layout) { ext_layout = LineColorVertex::layout; }
if (buf.count() == 0) { return; }
GLuint handle[2];
glGenBuffers(2, &handle[0]);
buf.setHandle(vbos.size());
vbos.emplace_back(VBOData{handle[0], handle[1], GL_TRIANGLES, 0, ext_layout});
}
glBindBuffer(GL_ARRAY_BUFFER, vbos[buf.getHandle()].vert_buf);
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
if (buf.count() == 0) { return; }
GLuint handle;
glGenBuffers(1, &handle);
buf.setHandle(vbos.size());
vbos.emplace_back(VBOData{handle, 0, buf.getShape(), buf.count(), layout});
// Create extended vertex data for generating shader-expanded lines
if (layout == Vertex::layout)
{
std::vector<LineVertex> ext_data(buf.count() * 2);
auto pts = static_cast<VertexBuffer<Vertex>&>(buf).begin();
for (size_t i = 0; i < buf.count(); i++)
{
const Vertex& pt = *(pts + i);
ext_data[2*i].vtx = pt.coord;
ext_data[2*i].orientation = 1;
ext_data[2*i+1].vtx = pt.coord;
ext_data[2*i+1].orientation = -1;
if (i % 2 == 0)
{
// first node in the segment
ext_data[2*(i+1)].prev = pt.coord;
ext_data[2*(i+1) + 1].prev = pt.coord;
ext_data[2*i].prev = pt.coord;
ext_data[2*i+1].prev = pt.coord;
}
else
{
// last node in the segment
ext_data[2*(i-1)].next = pt.coord;
ext_data[2*(i-1) + 1].next = pt.coord;
ext_data[2*i].next = pt.coord;
ext_data[2*i+1].next = pt.coord;
}
}
glBufferData(GL_ARRAY_BUFFER, ext_data.size() * sizeof(LineVertex),
ext_data.data(), GL_STATIC_DRAW);
}
else if (layout == VertexColor::layout)
{
std::vector<LineColorVertex> ext_data(buf.count() * 2);
auto pts = static_cast<VertexBuffer<VertexColor>&>(buf).begin();
for (size_t i = 0; i < buf.count(); i++)
{
const VertexColor& pt = *(pts + i);
ext_data[2*i].vtx = pt.coord;
ext_data[2*i].color = pt.color;
ext_data[2*i].orientation = 1;
ext_data[2*i+1].vtx = pt.coord;
ext_data[2*i+1].color = pt.color;
ext_data[2*i+1].orientation = -1;
if (i % 2 == 0)
{
// first node in the segment
ext_data[2*(i+1)].prev = pt.coord;
ext_data[2*(i+1) + 1].prev = pt.coord;
ext_data[2*i].prev = pt.coord;
ext_data[2*i+1].prev = pt.coord;
}
else
{
// last node in the segment
ext_data[2*(i-1)].next = pt.coord;
ext_data[2*(i-1) + 1].next = pt.coord;
ext_data[2*i].next = pt.coord;
ext_data[2*i+1].next = pt.coord;
}
}
glBufferData(GL_ARRAY_BUFFER, ext_data.size() * sizeof(LineColorVertex),
ext_data.data(), GL_STATIC_DRAW);
}
// Create indices to generate triangles for our lines
std::vector<int> index_data(buf.count() * 3);
for (size_t it = 0; it < buf.count() / 2; it++)
{
index_data[6*it] = 4*it;
index_data[6*it+1] = 4*it+1;
index_data[6*it+2] = 4*it+2;

index_data[6*it+3] = 4*it+1;
index_data[6*it+4] = 4*it+2;
index_data[6*it+5] = 4*it+3;
} // iterate over triangles

// Upload index data to GPU
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos[buf.getHandle()].elem_buf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_data.size() * sizeof(int),
index_data.data(), GL_STATIC_DRAW);

vbos[buf.getHandle()].count = index_data.size();
}
else
{
vbos[buf.getHandle()].count = buf.count();
if (buf.getHandle() == 0)
{
if (buf.count() == 0) { return; }
GLuint handle;
glGenBuffers(1, &handle);
buf.setHandle(vbos.size());
vbos.emplace_back(VBOData{handle, 0, buf.getShape(), buf.count(), layout});
}
else
{
vbos[buf.getHandle()].count = buf.count();
}
glBindBuffer(GL_ARRAY_BUFFER, vbos[buf.getHandle()].vert_buf);
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, buf.count() * buf.getStride(),
buf.getData(), GL_STATIC_DRAW);
}
glBindBuffer(GL_ARRAY_BUFFER, vbos[buf.getHandle()].vert_buf);
glBufferData(GL_ARRAY_BUFFER, 0, nullptr, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, buf.count() * buf.getStride(),
buf.getData(), GL_STATIC_DRAW);
}

void CoreGLDevice::bufferToDevice(array_layout layout, IIndexedBuffer& buf)
Expand Down Expand Up @@ -360,6 +550,38 @@ void CoreGLDevice::drawDeviceBufferImpl(GLenum shape, int count, bool indexed)
clearVtxAttrLayout<T>();
}

void CoreGLDevice::drawExtendedLineImpl(array_layout type, int count)
{
// Set polygon offset to pull lines towards camera
glPolygonOffset(0, 0);
// Set up uniforms
glUniform1i(uniforms["expandLines"], true);
glUniform1f(uniforms["lineWidth"], 2 * line_w / vp_width);
glUniform1f(uniforms["aspectRatio"], (float)vp_width / vp_height);
// Set up attributes
glVertexAttrib3f(CoreGLDevice::ATTR_NORMAL, 0.f, 0.f, 1.f);
if (type == LineVertex::layout)
{
LineVertex::Setup();
}
else if (type == LineColorVertex::layout)
{
LineColorVertex::Setup();
}
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, (void*)0);
if (type == LineVertex::layout)
{
LineVertex::Finish();
}
else if (type == LineColorVertex::layout)
{
LineColorVertex::Finish();
}
glUniform1i(uniforms["expandLines"], false);
// Reset polygon offset to default value
glPolygonOffset(1, 1);
}

void CoreGLDevice::drawDeviceBuffer(int hnd)
{
if (hnd == 0) { return; }
Expand All @@ -372,7 +594,8 @@ void CoreGLDevice::drawDeviceBuffer(int hnd)
indexed = true;
}
if (vbos[hnd].layout == Vertex::layout
|| vbos[hnd].layout == VertexNorm::layout)
|| vbos[hnd].layout == VertexNorm::layout
|| vbos[hnd].layout == LineVertex::layout)
{
glVertexAttrib4fv(ATTR_COLOR, static_color.data());
}
Expand All @@ -398,6 +621,10 @@ void CoreGLDevice::drawDeviceBuffer(int hnd)
case VertexNormTex::layout:
drawDeviceBufferImpl<VertexNormTex>(shape, count, indexed);
break;
case LineVertex::layout:
case LineColorVertex::layout:
drawExtendedLineImpl(vbos[hnd].layout, count);
break;
default:
cerr << "WARNING: Unhandled vertex layout " << vbos[hnd].layout << endl;
}
Expand Down
8 changes: 8 additions & 0 deletions lib/gl/renderer_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class CoreGLDevice : public GLDevice
ATTR_NORMAL,
ATTR_COLOR,
ATTR_TEXCOORD0,
ATTR_LINE_ORIENT,
ATTR_LINE_PREV,
ATTR_LINE_NEXT,
NUM_ATTRS
};

Expand Down Expand Up @@ -59,6 +62,9 @@ class CoreGLDevice : public GLDevice
array_layout layout;
};

struct LineVertex;
struct LineColorVertex;

std::vector<VBOData> vbos;

bool compileShaders();
Expand All @@ -67,6 +73,8 @@ class CoreGLDevice : public GLDevice
template<typename T>
void drawDeviceBufferImpl(GLenum shape, int count, bool indexed);

void drawExtendedLineImpl(array_layout type, int count);

void processTriangleXfbBuffer(CaptureBuffer& cbuf,
const vector<ShaderXfbVertex>& verts);
void processLineXfbBuffer(CaptureBuffer& cbuf,
Expand Down
Loading