Skip to content
Permalink
Browse files

opengl: render triangulated lines

Workaround for glLineWidth always == 1f on some systems
  • Loading branch information
JaCzekanski committed Sep 28, 2019
1 parent 05827d2 commit d31ccc02e7c3faeef14c931de67cb8a15189638b
@@ -31,7 +31,7 @@ flat SHARED uint fragFlags;
flat SHARED uint fragTextureWindow;

#ifdef VERTEX_SHADER
in ivec2 position;
in vec2 position;
in uvec3 color;
in ivec2 texcoord;
in uint bitcount;
@@ -41,7 +41,7 @@ in uint flags;
in uint textureWindow;

void main() {
vec2 pos = vec2((float(position.x) - displayAreaPos.x) / displayAreaSize.x, (float(position.y) - displayAreaPos.y) / displayAreaSize.y);
vec2 pos = vec2((position.x - displayAreaPos.x) / displayAreaSize.x, (position.y - displayAreaPos.y) / displayAreaSize.y);
// vec2 pos = vec2(position.x / 1024.f, position.y / 512.f);
fragColor = vec3(float(color.r) / 255.f, float(color.g) / 255.f, float(color.b) / 255.f);
fragTexcoord = vec2(texcoord.x, texcoord.y);
@@ -64,8 +64,7 @@ void GPU::drawTriangle(const primitive::Triangle& triangle) {
for (int i : {0, 1, 2}) {
auto& v = triangle.v[i];
vertices.push_back({
Vertex::Type::Polygon,
{v.pos.x + drawingOffsetX, v.pos.y + drawingOffsetY},
{static_cast<float>(v.pos.x + drawingOffsetX), static_cast<float>(v.pos.y + drawingOffsetY)},
{v.color.r, v.color.g, v.color.b},
{v.uv.x, v.uv.y},
triangle.bits,
@@ -100,30 +99,32 @@ void GPU::drawLine(const primitive::Line& line) {
flags |= static_cast<int>(gp0_e1.semiTransparency) << 5;
}

vertices.push_back({
Vertex::Type::Line,
{p[0].x, p[0].y},
{c[0].r, c[0].g, c[0].b},
{0, 0}, // UV: 0
0, // Bits: 0
{0, 0}, // clut: 0
{0, 0}, // texPage: 0
flags,
gp0_e2,
gp0_e6,
});
vertices.push_back({
Vertex::Type::Line,
{p[1].x, p[1].y},
{c[1].r, c[1].g, c[1].b},
{0, 0}, // UV: 0
0, // Bits: 0
{0, 0}, // clut: 0
{0, 0}, // texPage: 0
flags,
gp0_e2,
gp0_e6,
});
// Calculate vector b perpendicular to p0p1 line
glm::vec2 angle(p[1] - p[0]);
// Rotate 90°, normalize and make it half size
glm::vec2 b = glm::normalize(glm::vec2(angle.y, -angle.x)) / 2.f;

auto pushVertex = [&](float x, float y, const RGB c) {
vertices.push_back({
{x, y},
{c.r, c.g, c.b},
{0, 0}, // UV: 0
0, // Bits: 0
{0, 0}, // clut: 0
{0, 0}, // texPage: 0
flags,
gp0_e2,
gp0_e6,
});
};

// Trianglulate line
pushVertex(p[0].x - b.x, p[0].y - b.y, c[0]);
pushVertex(p[0].x + b.x, p[0].y + b.y, c[0]);
pushVertex(p[1].x - b.x, p[1].y - b.y, c[1]);
pushVertex(p[0].x + b.x, p[0].y + b.y, c[0]);
pushVertex(p[1].x + b.x, p[1].y + b.y, c[1]);
pushVertex(p[1].x - b.x, p[1].y - b.y, c[1]);
}

if (softwareRendering) {
@@ -134,7 +135,7 @@ void GPU::drawLine(const primitive::Line& line) {
void GPU::drawRectangle(const primitive::Rect& rect) {
if (hardwareRendering) {
glm::ivec2 p;
int x[4], y[4];
float x[4], y[4];
glm::ivec2 uv[4];

p.x = rect.pos.x + drawingOffsetX;
@@ -174,7 +175,6 @@ void GPU::drawRectangle(const primitive::Rect& rect) {
Vertex v[6];
for (int i : {0, 1, 2, 1, 2, 3}) {
v[i] = {
Vertex::Type::Polygon,
{x[i], y[i]},
{rect.color.r, rect.color.g, rect.color.b},
{uv[i].x, uv[i].y},
@@ -219,7 +219,12 @@ void GPU::cmdFillRectangle() {
cmd = Command::None;

if (hardwareRendering) {
glm::ivec2 p[4] = {{startX, startY}, {endX, startY}, {startX, endY}, {endX, endY}};
glm::ivec2 p[4] = {
{startX, startY},
{endX, startY},
{startX, endY},
{endX, endY},
};

RGB c;
c.raw = arguments[0];
@@ -230,8 +235,7 @@ void GPU::cmdFillRectangle() {
Vertex v[6];
for (int i : {0, 1, 2, 1, 2, 3}) {
v[i] = {
Vertex::Type::Polygon,
{p[i].x, p[i].y},
{static_cast<float>(p[i].x), static_cast<float>(p[i].y)},
{c.r, c.g, c.b},
{0, 0}, // UV: 0
0, // Bits: 0
@@ -206,10 +206,8 @@ enum class Command : int {

struct Vertex {
enum Flags { SemiTransparency = 1 << 0, RawTexture = 1 << 1, Dithering = 1 << 2, GouroudShading = 1 << 3 };
enum Type { Polygon = 0, Rectangle, Line };

int type;
int position[2];
float position[2];
int color[3];
int texcoord[2];
int bitcount;
@@ -157,14 +157,20 @@ std::vector<OpenGL::BlitStruct> OpenGL::makeBlitBuf(int screenX, int screenY, in
}

void OpenGL::bindRenderAttributes() {
renderShader->getAttrib("position").pointer(2, GL_INT, sizeof(gpu::Vertex), 1 * sizeof(int));
renderShader->getAttrib("color").pointer(3, GL_UNSIGNED_INT, sizeof(gpu::Vertex), 3 * sizeof(int));
renderShader->getAttrib("texcoord").pointer(2, GL_INT, sizeof(gpu::Vertex), 6 * sizeof(int));
renderShader->getAttrib("bitcount").pointer(1, GL_UNSIGNED_INT, sizeof(gpu::Vertex), 8 * sizeof(int));
renderShader->getAttrib("clut").pointer(2, GL_INT, sizeof(gpu::Vertex), 9 * sizeof(int));
renderShader->getAttrib("texpage").pointer(2, GL_INT, sizeof(gpu::Vertex), 11 * sizeof(int));
renderShader->getAttrib("flags").pointer(1, GL_UNSIGNED_INT, sizeof(gpu::Vertex), 13 * sizeof(int));
renderShader->getAttrib("textureWindow").pointer(1, GL_UNSIGNED_INT, sizeof(gpu::Vertex), 14 * sizeof(int));
const size_t stride = sizeof(gpu::Vertex);
size_t offset = 0;
auto attrib = [&](const char* name, GLint size, GLenum type) {
renderShader->getAttrib(name).pointer(size, type, stride, offset);
offset += size * Attribute::getSize(type);
};
attrib("position", 2, GL_FLOAT);
attrib("color", 3, GL_UNSIGNED_INT);
attrib("texcoord", 2, GL_INT);
attrib("bitcount", 1, GL_UNSIGNED_INT);
attrib("clut", 2, GL_INT);
attrib("texpage", 2, GL_INT);
attrib("flags", 1, GL_UNSIGNED_INT);
attrib("textureWindow", 1, GL_UNSIGNED_INT);
}

void OpenGL::bindBlitAttributes() {
@@ -262,42 +268,31 @@ void OpenGL::renderVertices(gpu::GPU* gpu) {
renderShader->getUniform("displayAreaPos").f(areaX, areaY);
renderShader->getUniform("displayAreaSize").f(areaW, areaH);

auto mapType = [](int type) {
if (type == gpu::Vertex::Type::Line)
return GL_LINES;
else
return GL_TRIANGLES;
};

glBlendColor(0.25f, 0.25f, 0.25f, 0.5f);

// Unbatched render
using Transparency = gpu::SemiTransparency;

for (size_t i = 0; i < buffer.size();) {
auto type = mapType(buffer[i].type);
int count = type == GL_TRIANGLES ? 3 : 2;

const int count = 3;
for (size_t i = 0; i < buffer.size(); i += count) {
// Skip rendering when distance between vertices is bigger than 1023x511
bool skipRender = false;
for (int j = 0; j < count; j++) {
auto& v0 = buffer[i + j];
auto& v1 = buffer[i + ((j + 1) % count)];
int x = abs(v0.position[0] - v1.position[0]);
int y = abs(v0.position[1] - v1.position[1]);
if (x >= 1024 || y >= 1024) {
if (x >= 1024 || y >= 512) {
skipRender = true;
break;
}
}

if (skipRender) {
i += count;
continue;
}

if (buffer[i].flags & gpu::Vertex::SemiTransparency) {
glEnable(GL_BLEND);
auto semi = static_cast<Transparency>((buffer[i].flags >> 5) & 3);
// TODO: Refactor and batch
if (semi == Transparency::Bby2plusFby2) {
@@ -313,13 +308,13 @@ void OpenGL::renderVertices(gpu::GPU* gpu) {
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE, GL_ONE, GL_ZERO);
}

glEnable(GL_BLEND);
} else {
glDisable(GL_BLEND);
}

glDrawArrays(type, i, count);

i += count;
glDrawArrays(GL_TRIANGLES, i, count);
}
lastPos = glm::vec2(gpu->displayAreaStartX, gpu->displayAreaStartY);

@@ -16,4 +16,17 @@ void Attribute::pointer(GLint size, GLenum type, GLsizei stride, uintptr_t point
} else {
glVertexAttribPointer(id, size, type, false, stride, (const GLvoid*)pointer);
}
}

size_t Attribute::getSize(GLenum type) {
switch (type) {
case GL_BYTE: return sizeof(char);
case GL_UNSIGNED_BYTE: return sizeof(unsigned char);
case GL_SHORT: return sizeof(short);
case GL_UNSIGNED_SHORT: return sizeof(unsigned short);
case GL_INT: return sizeof(int);
case GL_UNSIGNED_INT: return sizeof(unsigned int);
case GL_FLOAT: return sizeof(float);
case GL_DOUBLE: return sizeof(double);
}
}
@@ -11,4 +11,6 @@ class Attribute {
void enable();
void disable();
void pointer(GLint size, GLenum type, GLsizei stride, uintptr_t pointer);

static size_t getSize(GLenum type);
};

0 comments on commit d31ccc0

Please sign in to comment.
You can’t perform that action at this time.