From 1cd1b5e11da26be17525ea8d77ae6ef0014f28e5 Mon Sep 17 00:00:00 2001 From: bjorn Date: Wed, 21 Mar 2018 22:03:03 -0700 Subject: [PATCH] Use a Mesh for primitives; --- src/api/graphics.c | 60 ++--- src/api/types/mesh.c | 2 + src/graphics/font.c | 44 ++-- src/graphics/font.h | 4 +- src/graphics/graphics.c | 486 ++++++++++++++++++---------------------- src/graphics/graphics.h | 13 +- src/graphics/mesh.c | 17 +- src/graphics/mesh.h | 2 + 8 files changed, 302 insertions(+), 326 deletions(-) diff --git a/src/api/graphics.c b/src/api/graphics.c index 6018fb0d..7e257d0b 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -44,34 +44,42 @@ static int luax_optmatrixtype(lua_State* L, int index, MatrixType* type) { return index; } -static void luax_readvertices(lua_State* L, int index, vec_float_t* points) { +static uint32_t luax_readvertices(lua_State* L, int index) { bool isTable = lua_istable(L, index); if (!isTable && !lua_isnumber(L, index)) { luaL_error(L, "Expected number or table, got '%s'", lua_typename(L, lua_type(L, 1))); - return; + return 0; } - int count = isTable ? lua_objlen(L, index) : lua_gettop(L) - index + 1; + uint32_t count = isTable ? lua_objlen(L, index) : lua_gettop(L) - index + 1; if (count % 3 != 0) { - vec_deinit(points); luaL_error(L, "Number of coordinates must be a multiple of 3, got '%d'", count); - return; + return 0; } - vec_reserve(points, count); + VertexPointer pointer = lovrGraphicsGetVertexPointer(count / 3); if (isTable) { - for (int i = 1; i <= count; i++) { - lua_rawgeti(L, index, i); - vec_push(points, lua_tonumber(L, -1)); - lua_pop(L, 1); + for (uint32_t i = 1; i <= count; i += 3) { + for (int j = 0; j < 3; j++) { + lua_rawgeti(L, index, i + j); + pointer.floats[j] = lua_tonumber(L, -1); + lua_pop(L, 1); + } + + pointer.floats += 8; } } else { - for (int i = 0; i < count; i++) { - vec_push(points, lua_tonumber(L, index + i)); + for (uint32_t i = 0; i < count; i += 3) { + pointer.floats[0] = lua_tonumber(L, index + i + 0); + pointer.floats[1] = lua_tonumber(L, index + i + 1); + pointer.floats[2] = lua_tonumber(L, index + i + 2); + pointer.floats += 8; } } + + return count; } static void stencilCallback(void* userdata) { @@ -661,20 +669,14 @@ int l_lovrGraphicsTransform(lua_State* L) { // Primitives int l_lovrGraphicsPoints(lua_State* L) { - vec_float_t points; - vec_init(&points); - luax_readvertices(L, 1, &points); - lovrGraphicsPoints(points.data, points.length); - vec_deinit(&points); + uint32_t count = luax_readvertices(L, 1); + lovrGraphicsPoints(count); return 0; } int l_lovrGraphicsLine(lua_State* L) { - vec_float_t points; - vec_init(&points); - luax_readvertices(L, 1, &points); - lovrGraphicsLine(points.data, points.length); - vec_deinit(&points); + uint32_t count = luax_readvertices(L, 1); + lovrGraphicsLine(count); return 0; } @@ -687,15 +689,13 @@ int l_lovrGraphicsTriangle(lua_State* L) { drawMode = *(DrawMode*) luax_checkenum(L, 1, &DrawModes, "draw mode"); } + float points[9]; int top = lua_gettop(L); - if (top != 10) { - return luaL_error(L, "Expected 9 coordinates to make a triangle, got %d values", top - 1); + lovrAssert(top >= 10, "Expected 3 points to make a triangle, got %d\n", (top - 1) / 3); + for (int i = 0; i < 9; i++) { + points[i] = luaL_checknumber(L, i + 2); } - vec_float_t points; - vec_init(&points); - luax_readvertices(L, 2, &points); - lovrGraphicsTriangle(drawMode, material, points.data); - vec_deinit(&points); + lovrGraphicsTriangle(drawMode, material, points); return 0; } @@ -758,7 +758,7 @@ int l_lovrGraphicsArc(lua_State* L) { index = luax_readtransform(L, index, transform, 1); float theta1 = luaL_optnumber(L, index++, 0); float theta2 = luaL_optnumber(L, index++, 2 * M_PI); - int segments = luaL_optinteger(L, index, 32) * fabsf(theta2 - theta1) * 2 * M_PI + .5f; + int segments = luaL_optinteger(L, index, 64) * (MIN(fabsf(theta2 - theta1), 2 * M_PI) / (2 * M_PI)); lovrGraphicsArc(drawMode, arcMode, material, transform, theta1, theta2, segments); return 0; } diff --git a/src/api/types/mesh.c b/src/api/types/mesh.c index 34f1bc42..aa6a1dc1 100644 --- a/src/api/types/mesh.c +++ b/src/api/types/mesh.c @@ -1,4 +1,5 @@ #include "api.h" +#include "graphics/graphics.h" #include int l_lovrMeshAttachAttributes(lua_State* L) { @@ -56,6 +57,7 @@ int l_lovrMeshDrawInstanced(lua_State* L) { int instances = luaL_checkinteger(L, 2); float transform[16]; luax_readtransform(L, 3, transform, 1); + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); lovrMeshDraw(mesh, transform, NULL, instances); return 0; } diff --git a/src/graphics/font.c b/src/graphics/font.c index f4c87f67..a622567e 100644 --- a/src/graphics/font.c +++ b/src/graphics/font.c @@ -8,18 +8,18 @@ #include #include -static int lovrFontAlignLine(vec_float_t* vertices, int index, float width, HorizontalAlign halign) { - while (index < vertices->length) { +static float* lovrFontAlignLine(float* x, float* lineEnd, float width, HorizontalAlign halign) { + while(x < lineEnd) { if (halign == ALIGN_CENTER) { - vertices->data[index] -= width / 2.f; + *x -= width / 2.f; } else if (halign == ALIGN_RIGHT) { - vertices->data[index] -= width; + *x -= width; } - index += 5; + x += 8; } - return index; + return x; } Font* lovrFontCreate(Rasterizer* rasterizer) { @@ -61,7 +61,7 @@ void lovrFontDestroy(void* ref) { free(font); } -void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign halign, VerticalAlign valign, vec_float_t* vertices, float* offsety) { +void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign halign, VerticalAlign valign, VertexPointer vertices, float* offsety, uint32_t* vertexCount) { FontAtlas* atlas = &font->atlas; float cx = 0; @@ -77,17 +77,15 @@ void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign hal unsigned int codepoint; size_t bytes; - int linePtr = 0; + float* lineStart = vertices.floats; int lineCount = 1; - - vec_reserve(vertices, len * 30); - vec_clear(vertices); + *vertexCount = 0; while ((bytes = utf8_decode(str, end, &codepoint)) > 0) { // Newlines if (codepoint == '\n' || (wrap && cx * scale > wrap && codepoint == ' ')) { - linePtr = lovrFontAlignLine(vertices, linePtr, cx, halign); + lineStart = lovrFontAlignLine(lineStart, vertices.floats, cx, halign); lineCount++; cx = 0; cy -= font->rasterizer->height * font->lineHeight; @@ -105,7 +103,7 @@ void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign hal // Start over if texture was repacked if (u != atlas->width || v != atlas->height) { - lovrFontRender(font, start, wrap, halign, valign, vertices, offsety); + lovrFontRender(font, start, wrap, halign, valign, vertices, offsety, vertexCount); return; } @@ -120,16 +118,18 @@ void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign hal float s2 = (glyph->x + glyph->tw) / u; float t2 = glyph->y / v; - float quad[30] = { - x1, y1, 0, s1, t1, - x1, y2, 0, s1, t2, - x2, y1, 0, s2, t1, - x2, y1, 0, s2, t1, - x1, y2, 0, s1, t2, - x2, y2, 0, s2, t2 + float quad[48] = { + x1, y1, 0, 0, 0, 0, s1, t1, + x1, y2, 0, 0, 0, 0, s1, t2, + x2, y1, 0, 0, 0, 0, s2, t1, + x2, y1, 0, 0, 0, 0, s2, t1, + x1, y2, 0, 0, 0, 0, s1, t2, + x2, y2, 0, 0, 0, 0, s2, t2 }; - vec_pusharr(vertices, quad, 30); + memcpy(vertices.floats, quad, 6 * 8 * sizeof(float)); + vertices.floats += 48; + *vertexCount += 6; } // Advance cursor @@ -138,7 +138,7 @@ void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign hal } // Align the last line - lovrFontAlignLine(vertices, linePtr, cx, halign); + lovrFontAlignLine(lineStart, vertices.floats, cx, halign); // Calculate vertical offset if (valign == ALIGN_MIDDLE) { diff --git a/src/graphics/font.h b/src/graphics/font.h index bf8ab902..90ae6530 100644 --- a/src/graphics/font.h +++ b/src/graphics/font.h @@ -1,9 +1,9 @@ #include "data/rasterizer.h" +#include "data/vertexData.h" #include "util.h" #include "graphics/texture.h" #include "math/math.h" #include "lib/map/map.h" -#include "lib/vec/vec.h" #include #pragma once @@ -42,7 +42,7 @@ typedef struct { Font* lovrFontCreate(Rasterizer* rasterizer); void lovrFontDestroy(void* ref); -void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign halign, VerticalAlign valign, vec_float_t* vertices, float* offsety); +void lovrFontRender(Font* font, const char* str, float wrap, HorizontalAlign halign, VerticalAlign valign, VertexPointer vertices, float* offsety, uint32_t* vertexCount); float lovrFontGetWidth(Font* font, const char* string, float wrap); float lovrFontGetHeight(Font* font); float lovrFontGetAscent(Font* font); diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 8bc4716a..2bd83c9b 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -49,11 +49,7 @@ void lovrGraphicsDestroy() { lovrRelease(state.defaultMaterial); lovrRelease(state.defaultFont); lovrRelease(state.defaultTexture); - glDeleteVertexArrays(1, &state.streamVAO); - glDeleteBuffers(1, &state.streamVBO); - glDeleteBuffers(1, &state.streamIBO); - vec_deinit(&state.streamData); - vec_deinit(&state.streamIndices); + lovrRelease(state.mesh); memset(&state, 0, sizeof(GraphicsState)); } @@ -248,11 +244,12 @@ void lovrGraphicsCreateWindow(int w, int h, bool fullscreen, int msaa, const cha glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glGenVertexArrays(1, &state.streamVAO); - glGenBuffers(1, &state.streamVBO); - glGenBuffers(1, &state.streamIBO); - vec_init(&state.streamData); - vec_init(&state.streamIndices); + VertexFormat format; + vertexFormatInit(&format); + vertexFormatAppend(&format, "lovrPosition", ATTR_FLOAT, 3); + vertexFormatAppend(&format, "lovrNormal", ATTR_FLOAT, 3); + vertexFormatAppend(&format, "lovrTexCoord", ATTR_FLOAT, 2); + state.mesh = lovrMeshCreate(64, format, MESH_TRIANGLES, MESH_STREAM); lovrGraphicsReset(); state.initialized = true; } @@ -616,168 +613,149 @@ void lovrGraphicsMatrixTransform(MatrixType type, mat4 transform) { // Primitives -static void lovrGraphicsSetStreamData(float* data, int length) { - vec_clear(&state.streamData); - vec_pusharr(&state.streamData, data, length); -} - -static void lovrGraphicsSetIndexData(unsigned int* data, int length) { - vec_clear(&state.streamIndices); - vec_pusharr(&state.streamIndices, data, length); -} - -static void lovrGraphicsDrawPrimitive(Material* material, GLenum mode, bool hasNormals, bool hasTexCoords, bool useIndices) { - int stride = 3 + (hasNormals ? 3 : 0) + (hasTexCoords ? 2 : 0); - int strideBytes = stride * sizeof(float); - float* data = state.streamData.data; - unsigned int* indices = state.streamIndices.data; - - lovrGraphicsPrepare(material, NULL); - lovrGraphicsBindVertexArray(state.streamVAO); - lovrGraphicsBindVertexBuffer(state.streamVBO); - glBufferData(GL_ARRAY_BUFFER, state.streamData.length * sizeof(float), data, GL_STREAM_DRAW); - glEnableVertexAttribArray(LOVR_SHADER_POSITION); - glVertexAttribPointer(LOVR_SHADER_POSITION, 3, GL_FLOAT, GL_FALSE, strideBytes, (void*) 0); - - if (hasNormals) { - glEnableVertexAttribArray(LOVR_SHADER_NORMAL); - glVertexAttribPointer(LOVR_SHADER_NORMAL, 3, GL_FLOAT, GL_FALSE, strideBytes, (void*) (3 * sizeof(float))); - } else { - glDisableVertexAttribArray(LOVR_SHADER_NORMAL); +VertexPointer lovrGraphicsGetVertexPointer(uint32_t count) { + if (!state.mesh || state.mesh->count < count) { + size_t capacity = nextPo2(count); + lovrMeshResize(state.mesh, capacity); } - if (hasTexCoords) { - void* offset = (void*) ((hasNormals ? 6 : 3) * sizeof(float)); - glEnableVertexAttribArray(LOVR_SHADER_TEX_COORD); - glVertexAttribPointer(LOVR_SHADER_TEX_COORD, 2, GL_FLOAT, GL_FALSE, strideBytes, offset); - } else { - glDisableVertexAttribArray(LOVR_SHADER_TEX_COORD); - } - - glDisableVertexAttribArray(LOVR_SHADER_BONES); - glDisableVertexAttribArray(LOVR_SHADER_BONE_WEIGHTS); - - if (useIndices) { - lovrGraphicsBindIndexBuffer(state.streamIBO); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, state.streamIndices.length * sizeof(unsigned int), indices, GL_STREAM_DRAW); - lovrGraphicsDrawElements(mode, state.streamIndices.length, sizeof(uint32_t), 0, 1); - } else { - lovrGraphicsDrawArrays(mode, 0, state.streamData.length / stride, 1); - } + return lovrMeshMapVertices(state.mesh, 0, count, false, true); } -void lovrGraphicsPoints(float* points, int count) { +void lovrGraphicsPoints(uint32_t count) { lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(points, count); - lovrGraphicsDrawPrimitive(NULL, MESH_POINTS, false, false, false); + lovrMeshSetDrawMode(state.mesh, MESH_POINTS); + lovrMeshSetDrawRange(state.mesh, 0, count); + lovrMeshSetMaterial(state.mesh, NULL); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshDraw(state.mesh, NULL, NULL, 1); } -void lovrGraphicsLine(float* points, int count) { +void lovrGraphicsLine(uint32_t count) { lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(points, count); - lovrGraphicsDrawPrimitive(NULL, GL_LINE_STRIP, false, false, false); + lovrMeshSetDrawMode(state.mesh, MESH_LINE_STRIP); + lovrMeshSetDrawRange(state.mesh, 0, count); + lovrMeshSetMaterial(state.mesh, NULL); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshDraw(state.mesh, NULL, NULL, 1); } -void lovrGraphicsTriangle(DrawMode mode, Material* material, float* points) { - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - +void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]) { if (mode == DRAW_MODE_LINE) { - lovrGraphicsSetStreamData(points, 9); - lovrGraphicsDrawPrimitive(material, GL_LINE_LOOP, false, false, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(3); + + float vertices[24] = { + points[0], points[1], points[2], 0, 0, 0, 0, 0, + points[3], points[4], points[5], 0, 0, 0, 0, 0, + points[6], points[7], points[8], 0, 0, 0, 0, 0 + }; + + memcpy(vertexPointer.raw, vertices, 3 * 8 * sizeof(float)); + lovrMeshSetDrawMode(state.mesh, MESH_LINE_LOOP); } else { float normal[3]; vec3_cross(vec3_init(normal, &points[0]), &points[3]); - float data[18] = { - points[0], points[1], points[2], normal[0], normal[1], normal[2], - points[3], points[4], points[5], normal[0], normal[1], normal[2], - points[6], points[7], points[8], normal[0], normal[1], normal[2] + float vertices[24] = { + points[0], points[1], points[2], normal[0], normal[1], normal[2], 0, 0, + points[3], points[4], points[5], normal[0], normal[1], normal[2], 0, 0, + points[6], points[7], points[8], normal[0], normal[1], normal[2], 0, 0 }; - lovrGraphicsSetStreamData(data, 18); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_STRIP, true, false, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(3); + memcpy(vertexPointer.raw, vertices, 3 * 8 * sizeof(float)); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES); } + + lovrMeshSetDrawRange(state.mesh, 0, 3); + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshDraw(state.mesh, NULL, NULL, 1); } void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform) { - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); - if (mode == DRAW_MODE_LINE) { - float points[] = { - -.5, .5, 0, - .5, .5, 0, - .5, -.5, 0, - -.5, -.5, 0 + float vertices[] = { + -.5, .5, 0, 0, 0, 0, 0, 0, + .5, .5, 0, 0, 0, 0, 0, 0, + .5, -.5, 0, 0, 0, 0, 0, 0, + -.5, -.5, 0, 0, 0, 0, 0, 0 }; - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(points, 12); - lovrGraphicsDrawPrimitive(material, GL_LINE_LOOP, false, false, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4); + memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float)); + lovrMeshSetDrawMode(state.mesh, MESH_LINE_LOOP); } else if (mode == DRAW_MODE_FILL) { - float data[] = { + float vertices[] = { -.5, .5, 0, 0, 0, -1, 0, 1, -.5, -.5, 0, 0, 0, -1, 0, 0, .5, .5, 0, 0, 0, -1, 1, 1, .5, -.5, 0, 0, 0, -1, 1, 0 }; - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(data, 32); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_STRIP, true, true, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4); + memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float)); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP); } - lovrGraphicsPop(); + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshSetDrawRange(state.mesh, 0, 4); + lovrMeshDraw(state.mesh, transform, NULL, 1); } void lovrGraphicsPlaneFullscreen(Texture* texture) { - float data[] = { - -1, 1, 0, 0, 1, - -1, -1, 0, 0, 0, - 1, 1, 0, 1, 1, - 1, -1, 0, 1, 0 + float vertices[] = { + -1, 1, 0, 0, 0, 0, 0, 1, + -1, -1, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 1, 1, + 1, -1, 0, 0, 0, 0, 1, 0 }; lovrGraphicsSetDefaultShader(SHADER_FULLSCREEN); Material* material = lovrGraphicsGetDefaultMaterial(); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, texture); - lovrGraphicsSetStreamData(data, 20); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_STRIP, false, true, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(4); + memcpy(vertexPointer.raw, vertices, 4 * 8 * sizeof(float)); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP); + lovrMeshSetDrawRange(state.mesh, 0, 4); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL); + lovrMeshDraw(state.mesh, NULL, NULL, 1); } void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform) { - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); - if (mode == DRAW_MODE_LINE) { - float points[] = { + float vertices[] = { // Front - -.5, .5, -.5, - .5, .5, -.5, - .5, -.5, -.5, - -.5, -.5, -.5, + -.5, .5, -.5, 0, 0, 0, 0, 0, + .5, .5, -.5, 0, 0, 0, 0, 0, + .5, -.5, -.5, 0, 0, 0, 0, 0, + -.5, -.5, -.5, 0, 0, 0, 0, 0, // Back - -.5, .5, .5, - .5, .5, .5, - .5, -.5, .5, - -.5, -.5, .5 + -.5, .5, .5, 0, 0, 0, 0, 0, + .5, .5, .5, 0, 0, 0, 0, 0, + .5, -.5, .5, 0, 0, 0, 0, 0, + -.5, -.5, .5, 0, 0, 0, 0, 0 }; - unsigned int indices[] = { + uint16_t indices[] = { 0, 1, 1, 2, 2, 3, 3, 0, // Front 4, 5, 5, 6, 6, 7, 7, 4, // Back 0, 4, 1, 5, 2, 6, 3, 7 // Connections }; - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(points, 24); - lovrGraphicsSetIndexData(indices, 24); - lovrGraphicsDrawPrimitive(material, GL_LINES, false, false, true); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(8); + memcpy(vertexPointer.raw, vertices, 8 * 8 * sizeof(float)); + IndexPointer indexPointer = lovrMeshWriteIndices(state.mesh, 24, sizeof(uint16_t)); + memcpy(indexPointer.shorts, indices, 24 * sizeof(uint16_t)); + lovrMeshSetDrawMode(state.mesh, MESH_LINES); + lovrMeshSetDrawRange(state.mesh, 0, 24); } else { - float data[] = { + float vertices[] = { // Front -.5, -.5, -.5, 0, 0, -1, 0, 0, -.5, .5, -.5, 0, 0, -1, 0, 1, @@ -819,12 +797,16 @@ void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform) { .5, .5, .5, 0, 1, 0, 1, 0 }; - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsSetStreamData(data, 208); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_STRIP, true, true, false); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(26); + memcpy(vertexPointer.floats, vertices, 26 * 8 * sizeof(float)); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP); + lovrMeshSetDrawRange(state.mesh, 0, 26); } - lovrGraphicsPop(); + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshDraw(state.mesh, transform, NULL, 1); } void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 transform, float theta1, float theta2, int segments) { @@ -833,63 +815,46 @@ void lovrGraphicsArc(DrawMode mode, ArcMode arcMode, Material* material, mat4 tr theta2 = 2 * M_PI; } - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); + bool hasCenterPoint = arcMode == ARC_MODE_PIE && fabsf(theta1 - theta2) < 2 * M_PI; + uint32_t count = segments + 1 + hasCenterPoint; - vec_clear(&state.streamData); + VertexPointer vertices = lovrGraphicsGetVertexPointer(count); - if (arcMode == ARC_MODE_PIE && fabsf(theta1 - theta2) < 2 * M_PI) { - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 0); - - if (mode == DRAW_MODE_FILL) { - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 1); - - vec_push(&state.streamData, .5); - vec_push(&state.streamData, .5); - } + if (hasCenterPoint) { + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 1; + *vertices.floats++ = .5; + *vertices.floats++ = .5; } float theta = theta1; float angleShift = (theta2 - theta1) / (float) segments; - if (mode == DRAW_MODE_LINE) { - for (int i = 0; i <= segments; i++) { - float x = cos(theta) * .5; - float y = sin(theta) * .5; - vec_push(&state.streamData, x); - vec_push(&state.streamData, y); - vec_push(&state.streamData, 0); - theta += angleShift; - } + for (int i = 0; i <= segments; i++) { + float x = cos(theta) * .5; + float y = sin(theta) * .5; - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsDrawPrimitive(material, arcMode == ARC_MODE_OPEN ? GL_LINE_STRIP : GL_LINE_LOOP, false, false, false); - } else if (mode == DRAW_MODE_FILL) { - for (int i = 0; i <= segments; i++) { - float x = cos(theta) * .5; - float y = sin(theta) * .5; - vec_push(&state.streamData, x); - vec_push(&state.streamData, y); - vec_push(&state.streamData, 0); + *vertices.floats++ = x; + *vertices.floats++ = y; + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 0; + *vertices.floats++ = 1; + *vertices.floats++ = x + .5; + *vertices.floats++ = 1 - (y + .5); - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 0); - vec_push(&state.streamData, 1); - - vec_push(&state.streamData, x + .5); - vec_push(&state.streamData, 1 - (y + .5)); - theta += angleShift; - } - - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_FAN, true, true, false); + theta += angleShift; } - lovrGraphicsPop(); + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshSetDrawMode(state.mesh, mode == DRAW_MODE_LINE ? (arcMode == ARC_MODE_OPEN ? MESH_LINE_STRIP : MESH_LINE_LOOP) : MESH_TRIANGLE_FAN); + lovrMeshSetDrawRange(state.mesh, 0, count); + lovrMeshDraw(state.mesh, transform, NULL, 1); } void lovrGraphicsCircle(DrawMode mode, Material* material, mat4 transform, int segments) { @@ -902,19 +867,12 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa float p[3]; float q[3]; - int stride = 6; - int dataSize = stride * ((capped && r1) * (segments + 2) + (capped && r2) * (segments + 2) + 2 * (segments + 1)); - int indexSize = 3 * segments * ((capped && r1) + (capped && r2) + 2); + uint32_t vertexCount = ((capped && r1) * (segments + 2) + (capped && r2) * (segments + 2) + 2 * (segments + 1)); + uint32_t indexCount = 3 * segments * ((capped && r1) + (capped && r2) + 2); - vec_clear(&state.streamData); - vec_reserve(&state.streamData, dataSize); - state.streamData.length = 0; - float* data = state.streamData.data; - - vec_clear(&state.streamIndices); - vec_reserve(&state.streamIndices, indexSize); - state.streamIndices.length = 0; - unsigned int* indices = state.streamIndices.data; + VertexPointer vertices = lovrGraphicsGetVertexPointer(vertexCount); + IndexPointer indices = lovrMeshWriteIndices(state.mesh, indexCount, sizeof(uint32_t)); + float* baseVertex = vertices.floats; vec3_init(p, n); @@ -933,56 +891,52 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa vec3_normalize(axis); #define PUSH_CYLINDER_VERTEX(x, y, z, nx, ny, nz) \ - data[state.streamData.length++] = x; \ - data[state.streamData.length++] = y; \ - data[state.streamData.length++] = z; \ - data[state.streamData.length++] = nx; \ - data[state.streamData.length++] = ny; \ - data[state.streamData.length++] = nz; - + *vertices.floats++ = x; \ + *vertices.floats++ = y; \ + *vertices.floats++ = z; \ + *vertices.floats++ = nx; \ + *vertices.floats++ = ny; \ + *vertices.floats++ = nz; \ + *vertices.floats++ = 0; \ + *vertices.floats++ = 0; #define PUSH_CYLINDER_TRIANGLE(i1, i2, i3) \ - indices[state.streamIndices.length++] = i1; \ - indices[state.streamIndices.length++] = i2; \ - indices[state.streamIndices.length++] = i3; + *indices.ints++ = i1; \ + *indices.ints++ = i2; \ + *indices.ints++ = i3; \ // Ring - int ringOffset = state.streamData.length / 6; for (int i = 0; i <= segments; i++) { float theta = i * (2 * M_PI) / segments; - n[0] = cos(theta) * p[0] + sin(theta) * q[0]; n[1] = cos(theta) * p[1] + sin(theta) * q[1]; n[2] = cos(theta) * p[2] + sin(theta) * q[2]; - PUSH_CYLINDER_VERTEX(x1 + r1 * n[0], y1 + r1 * n[1], z1 + r1 * n[2], n[0], n[1], n[2]); PUSH_CYLINDER_VERTEX(x2 + r2 * n[0], y2 + r2 * n[1], z2 + r2 * n[2], n[0], n[1], n[2]); } // Top - int topOffset = state.streamData.length / 6; + int topOffset = (segments + 1) * 2; if (capped && r1 != 0) { PUSH_CYLINDER_VERTEX(x1, y1, z1, axis[0], axis[1], axis[2]); - for (int i = 0; i <= segments; i++) { - int j = i * 2 * stride; - PUSH_CYLINDER_VERTEX(data[j + 0], data[j + 1], data[j + 2], axis[0], axis[1], axis[2]); + int j = i * 2 * 8; + PUSH_CYLINDER_VERTEX(baseVertex[j + 0], baseVertex[j + 1], baseVertex[j + 2], axis[0], axis[1], axis[2]); } } // Bottom - int bottomOffset = state.streamData.length / 6; + int bottomOffset = (segments + 1) * 2 + (1 + segments + 1) * (capped && r1 != 0); if (capped && r2 != 0) { - PUSH_CYLINDER_VERTEX(x2, y2, z2, -axis[0], -axis[1], -axis[2]); - + PUSH_CYLINDER_VERTEX(x2, y2, z1, -axis[0], -axis[1], -axis[2]); for (int i = 0; i <= segments; i++) { - int j = i * 2 * stride + stride; - PUSH_CYLINDER_VERTEX(data[j + 0], data[j + 1], data[j + 2], -axis[0], -axis[1], -axis[2]); + int j = i * 2 * 8 + 8; + PUSH_CYLINDER_VERTEX(baseVertex[j + 0], baseVertex[j + 1], baseVertex[j + 2], -axis[0], -axis[1], -axis[2]); } } // Indices for (int i = 0; i < segments; i++) { - int j = ringOffset + 2 * i; + int j = 2 * i; PUSH_CYLINDER_TRIANGLE(j, j + 1, j + 2); PUSH_CYLINDER_TRIANGLE(j + 1, j + 3, j + 2); @@ -994,16 +948,19 @@ void lovrGraphicsCylinder(Material* material, float x1, float y1, float z1, floa PUSH_CYLINDER_TRIANGLE(bottomOffset, bottomOffset + i + 1, bottomOffset + i + 2); } } - - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLES, true, false, true); #undef PUSH_CYLINDER_VERTEX #undef PUSH_CYLINDER_TRIANGLE + + lovrGraphicsSetDefaultShader(SHADER_DEFAULT); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES); + lovrMeshSetDrawRange(state.mesh, 0, indexCount); + lovrMeshDraw(state.mesh, NULL, NULL, 1); } void lovrGraphicsSphere(Material* material, mat4 transform, int segments) { - vec_clear(&state.streamData); - vec_clear(&state.streamIndices); + VertexPointer vertices = lovrGraphicsGetVertexPointer((segments + 1) * (segments + 1)); + IndexPointer indices = lovrMeshWriteIndices(state.mesh, segments * segments * 6, sizeof(uint32_t)); for (int i = 0; i <= segments; i++) { float v = i / (float) segments; @@ -1014,16 +971,14 @@ void lovrGraphicsSphere(Material* material, mat4 transform, int segments) { float y = cos(v * M_PI); float z = -cos(u * 2 * M_PI) * sin(v * M_PI); - vec_push(&state.streamData, x); - vec_push(&state.streamData, y); - vec_push(&state.streamData, z); - - vec_push(&state.streamData, x); - vec_push(&state.streamData, y); - vec_push(&state.streamData, z); - - vec_push(&state.streamData, u); - vec_push(&state.streamData, 1 - v); + *vertices.floats++ = x; + *vertices.floats++ = y; + *vertices.floats++ = z; + *vertices.floats++ = x; + *vertices.floats++ = y; + *vertices.floats++ = z; + *vertices.floats++ = u; + *vertices.floats++ = 1 - v; } } @@ -1033,26 +988,20 @@ void lovrGraphicsSphere(Material* material, mat4 transform, int segments) { for (int j = 0; j < segments; j++) { unsigned int index0 = offset0 + j; unsigned int index1 = offset1 + j; - vec_push(&state.streamIndices, index0); - vec_push(&state.streamIndices, index1); - vec_push(&state.streamIndices, index0 + 1); - vec_push(&state.streamIndices, index1); - vec_push(&state.streamIndices, index1 + 1); - vec_push(&state.streamIndices, index0 + 1); + *indices.ints++ = index0; + *indices.ints++ = index1; + *indices.ints++ = index0 + 1; + *indices.ints++ = index1; + *indices.ints++ = index1 + 1; + *indices.ints++ = index0 + 1; } } - if (transform) { - lovrGraphicsPush(); - lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); - } - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLES, true, true, true); - - if (transform) { - lovrGraphicsPop(); - } + lovrMeshSetDrawMode(state.mesh, GL_TRIANGLES); + lovrMeshSetDrawRange(state.mesh, 0, segments * segments * 6); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshDraw(state.mesh, transform, NULL, 1); } void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float az) { @@ -1064,53 +1013,57 @@ void lovrGraphicsSkybox(Texture* texture, float angle, float ax, float ay, float lovrGraphicsSetWinding(WINDING_COUNTERCLOCKWISE); if (texture->type == TEXTURE_CUBE) { - float cube[] = { + float vertices[] = { // Front - 1.f, -1.f, -1.f, - 1.f, 1.f, -1.f, - -1.f, -1.f, -1.f, - -1.f, 1.f, -1.f, + 1.f, -1.f, -1.f, 0, 0, 0, 0, 0, + 1.f, 1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, -1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, 1.f, -1.f, 0, 0, 0, 0, 0, // Left - -1.f, 1.f, -1.f, - -1.f, 1.f, 1.f, - -1.f, -1.f, -1.f, - -1.f, -1.f, 1.f, + -1.f, 1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, 1.f, 1.f, 0, 0, 0, 0, 0, + -1.f, -1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, -1.f, 1.f, 0, 0, 0, 0, 0, // Back - -1.f, -1.f, 1.f, - -1.f, 1.f, 1.f, - 1.f, -1.f, 1.f, - 1.f, 1.f, 1.f, + -1.f, -1.f, 1.f, 0, 0, 0, 0, 0, + -1.f, 1.f, 1.f, 0, 0, 0, 0, 0, + 1.f, -1.f, 1.f, 0, 0, 0, 0, 0, + 1.f, 1.f, 1.f, 0, 0, 0, 0, 0, // Right - 1.f, 1.f, 1.f, - 1.f, 1.f, -1.f, - 1.f, -1.f, 1.f, - 1.f, -1.f, -1.f, + 1.f, 1.f, 1.f, 0, 0, 0, 0, 0, + 1.f, 1.f, -1.f, 0, 0, 0, 0, 0, + 1.f, -1.f, 1.f, 0, 0, 0, 0, 0, + 1.f, -1.f, -1.f, 0, 0, 0, 0, 0, // Bottom - 1.f, -1.f, -1.f, - -1.f, -1.f, -1.f, - 1.f, -1.f, 1.f, - -1.f, -1.f, 1.f, + 1.f, -1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, -1.f, -1.f, 0, 0, 0, 0, 0, + 1.f, -1.f, 1.f, 0, 0, 0, 0, 0, + -1.f, -1.f, 1.f, 0, 0, 0, 0, 0, // Adjust - -1.f, -1.f, 1.f, - -1.f, 1.f, -1.f, + -1.f, -1.f, 1.f, 0, 0, 0, 0, 0, + -1.f, 1.f, -1.f, 0, 0, 0, 0, 0, // Top - -1.f, 1.f, -1.f, - 1.f, 1.f, -1.f, - -1.f, 1.f, 1.f, - 1.f, 1.f, 1.f + -1.f, 1.f, -1.f, 0, 0, 0, 0, 0, + 1.f, 1.f, -1.f, 0, 0, 0, 0, 0, + -1.f, 1.f, 1.f, 0, 0, 0, 0, 0, + 1.f, 1.f, 1.f, 0, 0, 0, 0, 0 }; - lovrGraphicsSetStreamData(cube, 78); - lovrGraphicsSetDefaultShader(SHADER_SKYBOX); + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(26); + memcpy(vertexPointer.raw, vertices, 26 * 8 * sizeof(float)); Material* material = lovrGraphicsGetDefaultMaterial(); lovrMaterialSetTexture(material, TEXTURE_ENVIRONMENT_MAP, texture); - lovrGraphicsDrawPrimitive(material, GL_TRIANGLE_STRIP, false, false, false); + lovrGraphicsSetDefaultShader(SHADER_SKYBOX); + lovrMeshWriteIndices(state.mesh, 0, 0); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLE_STRIP); + lovrMeshSetDrawRange(state.mesh, 0, 26); lovrMaterialSetTexture(material, TEXTURE_ENVIRONMENT_MAP, NULL); } else if (texture->type == TEXTURE_2D) { CompareMode mode; @@ -1134,7 +1087,11 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl Font* font = lovrGraphicsGetFont(); float scale = 1 / font->pixelDensity; float offsety; - lovrFontRender(font, str, wrap, halign, valign, &state.streamData, &offsety); + uint32_t vertexCount; + uint32_t maxVertices = strlen(str) * 6; + VertexPointer vertexPointer = lovrGraphicsGetVertexPointer(maxVertices); + lovrFontRender(font, str, wrap, halign, valign, vertexPointer, &offsety, &vertexCount); + lovrMeshWriteIndices(state.mesh, 0, 0); lovrGraphicsPush(); lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); @@ -1147,7 +1104,10 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl bool write; lovrGraphicsGetDepthTest(&mode, &write); lovrGraphicsSetDepthTest(mode, false); - lovrGraphicsDrawPrimitive(NULL, GL_TRIANGLES, false, true, false); + lovrMeshSetMaterial(state.mesh, material); + lovrMeshSetDrawMode(state.mesh, MESH_TRIANGLES); + lovrMeshSetDrawRange(state.mesh, 0, vertexCount); + lovrMeshDraw(state.mesh, NULL, NULL, 1); lovrGraphicsSetDepthTest(mode, write); lovrMaterialSetTexture(material, TEXTURE_DIFFUSE, NULL); lovrGraphicsPop(); diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 6f4473ec..8cfd78b6 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -124,11 +124,7 @@ typedef struct { int stencilValue; Winding winding; bool wireframe; - uint32_t streamVAO; - uint32_t streamVBO; - uint32_t streamIBO; - vec_float_t streamData; - vec_uint_t streamIndices; + Mesh* mesh; Display displays[MAX_DISPLAYS]; int display; Texture* textures[MAX_TEXTURES]; @@ -196,9 +192,9 @@ void lovrGraphicsScale(MatrixType type, float x, float y, float z); void lovrGraphicsMatrixTransform(MatrixType type, mat4 transform); // Primitives -void lovrGraphicsPoints(float* points, int count); -void lovrGraphicsLine(float* points, int count); -void lovrGraphicsTriangle(DrawMode mode, Material* material, float* points); +void lovrGraphicsPoints(uint32_t count); +void lovrGraphicsLine(uint32_t count); +void lovrGraphicsTriangle(DrawMode mode, Material* material, float points[9]); void lovrGraphicsPlane(DrawMode mode, Material* material, mat4 transform); void lovrGraphicsPlaneFullscreen(Texture* texture); void lovrGraphicsBox(DrawMode mode, Material* material, mat4 transform); @@ -211,6 +207,7 @@ void lovrGraphicsPrint(const char* str, mat4 transform, float wrap, HorizontalAl void lovrGraphicsStencil(StencilAction action, int replaceValue, StencilCallback callback, void* userdata); // Internal State +VertexPointer lovrGraphicsGetVertexPointer(uint32_t capacity); void lovrGraphicsPushDisplay(int framebuffer, mat4 projection, int* viewport); void lovrGraphicsPopDisplay(); void lovrGraphicsSetViewport(int x, int y, int w, int h); diff --git a/src/graphics/mesh.c b/src/graphics/mesh.c index c4919bcc..52956b89 100644 --- a/src/graphics/mesh.c +++ b/src/graphics/mesh.c @@ -85,6 +85,10 @@ Mesh* lovrMeshCreate(uint32_t count, VertexFormat format, MeshDrawMode drawMode, map_set(&mesh->attachments, format.attributes[i].name, ((MeshAttachment) { mesh, i, 0, true })); } +#ifdef EMSCRIPTEN + mesh->data.raw = calloc(count, format.stride); +#endif + return mesh; } @@ -140,7 +144,6 @@ void lovrMeshDraw(Mesh* mesh, mat4 transform, float* pose, int instances) { lovrGraphicsMatrixTransform(MATRIX_MODEL, transform); } - lovrGraphicsSetDefaultShader(SHADER_DEFAULT); lovrGraphicsPrepare(mesh->material, pose); lovrGraphicsBindVertexArray(mesh->vao); lovrMeshBindAttributes(mesh); @@ -309,3 +312,15 @@ void lovrMeshUnmapIndices(Mesh* mesh) { glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); #endif } + +void lovrMeshResize(Mesh* mesh, uint32_t count) { + mesh->count = count; + mesh->mappedVertices = false; + lovrGraphicsBindVertexBuffer(mesh->vbo); +#ifdef EMSCRIPTEN + mesh->data.raw = realloc(mesh->data.raw, count * mesh->format.stride); + glBufferData(GL_ARRAY_BUFFER, count * mesh->format.stride, mesh->data.raw, mesh->usage); +#else + glBufferData(GL_ARRAY_BUFFER, count * mesh->format.stride, NULL, mesh->usage); +#endif +} diff --git a/src/graphics/mesh.h b/src/graphics/mesh.h index 3dd95776..1cfcb1b9 100644 --- a/src/graphics/mesh.h +++ b/src/graphics/mesh.h @@ -13,6 +13,7 @@ typedef enum { MESH_POINTS = GL_POINTS, MESH_LINES = GL_LINES, MESH_LINE_STRIP = GL_LINE_STRIP, + MESH_LINE_LOOP = GL_LINE_LOOP, MESH_TRIANGLE_STRIP = GL_TRIANGLE_STRIP, MESH_TRIANGLES = GL_TRIANGLES, MESH_TRIANGLE_FAN = GL_TRIANGLE_FAN @@ -83,3 +84,4 @@ void lovrMeshUnmapVertices(Mesh* mesh); IndexPointer lovrMeshReadIndices(Mesh* mesh, uint32_t* count, size_t* size); IndexPointer lovrMeshWriteIndices(Mesh* mesh, uint32_t count, size_t size); void lovrMeshUnmapIndices(Mesh* mesh); +void lovrMeshResize(Mesh* mesh, uint32_t count);