Use a Mesh for primitives;

This commit is contained in:
bjorn 2018-03-21 22:03:03 -07:00
parent 4c2cd458ad
commit 1cd1b5e11d
8 changed files with 302 additions and 326 deletions

View File

@ -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;
}

View File

@ -1,4 +1,5 @@
#include "api.h"
#include "graphics/graphics.h"
#include <limits.h>
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;
}

View File

@ -8,18 +8,18 @@
#include <stdlib.h>
#include <stdio.h>
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) {

View File

@ -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 <stdint.h>
#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);

View File

@ -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();

View File

@ -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);

View File

@ -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
}

View File

@ -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);