mirror of https://github.com/bjornbytes/lovr.git
Improve Mesh VAO state diffing;
Also permit empty tables for vertex formats.
This commit is contained in:
parent
dd3644bafd
commit
6fb977b5bb
|
@ -98,7 +98,7 @@ extern map_int_t VerticalAligns;
|
|||
extern map_int_t WrapModes;
|
||||
|
||||
// Shared helpers
|
||||
void luax_checkvertexformat(lua_State* L, int index, VertexFormat* format);
|
||||
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format);
|
||||
int luax_pushvertexformat(lua_State* L, VertexFormat* format);
|
||||
int luax_pushvertexattribute(lua_State* L, VertexPointer* vertex, Attribute attribute);
|
||||
int luax_pushvertex(lua_State* L, VertexPointer* vertex, VertexFormat* format);
|
||||
|
|
|
@ -99,8 +99,8 @@ int l_lovrDataNewVertexData(lua_State* L) {
|
|||
uint32_t count = luaL_checkinteger(L, 1);
|
||||
VertexFormat format;
|
||||
vertexFormatInit(&format);
|
||||
luax_checkvertexformat(L, 2, &format);
|
||||
VertexData* vertexData = lovrVertexDataCreate(count, format.count > 0 ? &format : NULL, true);
|
||||
bool hasFormat = luax_checkvertexformat(L, 2, &format);
|
||||
VertexData* vertexData = lovrVertexDataCreate(count, hasFormat ? &format : NULL, true);
|
||||
luax_pushtype(L, VertexData, vertexData);
|
||||
lovrRelease(vertexData);
|
||||
return 1;
|
||||
|
|
|
@ -945,6 +945,7 @@ int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
int dataIndex = 0;
|
||||
int drawModeIndex = 2;
|
||||
VertexData* vertexData = NULL;
|
||||
bool hasFormat = false;
|
||||
VertexFormat format;
|
||||
vertexFormatInit(&format);
|
||||
|
||||
|
@ -953,12 +954,12 @@ int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
} else if (lua_istable(L, 1)) {
|
||||
if (lua_isnumber(L, 2)) {
|
||||
drawModeIndex++;
|
||||
luax_checkvertexformat(L, 1, &format);
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
count = lua_tointeger(L, 2);
|
||||
dataIndex = 0;
|
||||
} else if (lua_istable(L, 2)) {
|
||||
drawModeIndex++;
|
||||
luax_checkvertexformat(L, 1, &format);
|
||||
hasFormat = luax_checkvertexformat(L, 1, &format);
|
||||
count = lua_objlen(L, 2);
|
||||
dataIndex = 2;
|
||||
} else {
|
||||
|
@ -969,6 +970,7 @@ int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
vertexData = luax_checktype(L, 1, VertexData);
|
||||
format = vertexData->format;
|
||||
count = vertexData->count;
|
||||
hasFormat = true;
|
||||
} else {
|
||||
luaL_argerror(L, 1, "table or number expected");
|
||||
return 0;
|
||||
|
@ -976,9 +978,9 @@ int l_lovrGraphicsNewMesh(lua_State* L) {
|
|||
|
||||
if (!vertexData) {
|
||||
#ifdef EMSCRIPTEN
|
||||
vertexData = lovrVertexDataCreate(count, format.count > 0 ? &format : NULL, true);
|
||||
vertexData = lovrVertexDataCreate(count, hasFormat ? &format : NULL, true);
|
||||
#else
|
||||
vertexData = lovrVertexDataCreate(count, format.count > 0 ? &format : NULL, false);
|
||||
vertexData = lovrVertexDataCreate(count, hasFormat ? &format : NULL, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,38 @@
|
|||
#include "api.h"
|
||||
|
||||
int l_lovrMeshAttachAttributes(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
Mesh* other = luax_checktype(L, 2, Mesh);
|
||||
int instanceDivisor = luaL_optinteger(L, 3, 0);
|
||||
if (lua_isnoneornil(L, 4)) {
|
||||
VertexFormat* format = lovrMeshGetVertexFormat(other);
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
lovrMeshAttachAttribute(mesh, other, format->attributes[i].name, instanceDivisor);
|
||||
}
|
||||
} else if (lua_istable(L, 4)) {
|
||||
int length = lua_objlen(L, 4);
|
||||
for (int i = 0; i < length; i++) {
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
lovrMeshAttachAttribute(mesh, other, lua_tostring(L, -1), instanceDivisor);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
} else {
|
||||
int top = lua_gettop(L);
|
||||
for (int i = 4; i <= top; i++) {
|
||||
lovrMeshAttachAttribute(mesh, other, lua_tostring(L, i), instanceDivisor);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshDetachAttribute(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
const char* name = luaL_checkstring(L, 2);
|
||||
lovrMeshDetachAttribute(mesh, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshDrawInstanced(lua_State* L) {
|
||||
Mesh* mesh = luax_checktype(L, 1, Mesh);
|
||||
int instances = luaL_checkinteger(L, 2);
|
||||
|
@ -246,21 +279,9 @@ int l_lovrMeshSetMaterial(lua_State* L) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int l_lovrMeshAttachAttributes(lua_State* L) {
|
||||
Mesh* attachTo = luax_checktype(L, 1, Mesh);
|
||||
Mesh* attachThis = luax_checktype(L, 2, Mesh);
|
||||
int instanceDivisor = luaL_optnumber(L, 3, 0);
|
||||
// TODO: Check attribute name(s) in 4th argument and if present only attach those
|
||||
|
||||
VertexFormat* format = &attachThis->vertexData->format;
|
||||
for(int c = 0; c < format->count; c++) {
|
||||
lovrMeshAttach(attachTo, attachThis, c, instanceDivisor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const luaL_Reg lovrMesh[] = {
|
||||
{ "attachAttributes", l_lovrMeshAttachAttributes },
|
||||
{ "detachAttribute", l_lovrMeshDetachAttribute },
|
||||
{ "drawInstanced", l_lovrMeshDrawInstanced },
|
||||
{ "draw", l_lovrMeshDraw },
|
||||
{ "getVertexFormat", l_lovrMeshGetVertexFormat },
|
||||
|
@ -280,6 +301,5 @@ const luaL_Reg lovrMesh[] = {
|
|||
{ "setDrawRange", l_lovrMeshSetDrawRange },
|
||||
{ "getMaterial", l_lovrMeshGetMaterial },
|
||||
{ "setMaterial", l_lovrMeshSetMaterial },
|
||||
{ "attachAttributes", l_lovrMeshAttachAttributes },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "api.h"
|
||||
|
||||
void luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
|
||||
bool luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
|
||||
if (!lua_istable(L, index)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = lua_objlen(L, index);
|
||||
|
@ -12,7 +12,7 @@ void luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
|
|||
|
||||
if (!lua_istable(L, -1) || lua_objlen(L, -1) != 3) {
|
||||
luaL_error(L, "Expected vertex format specified as tables containing name, data type, and size");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
|
@ -25,6 +25,8 @@ void luax_checkvertexformat(lua_State* L, int index, VertexFormat* format) {
|
|||
vertexFormatAppend(format, name, *type, count);
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int luax_pushvertexformat(lua_State* L, VertexFormat* format) {
|
||||
|
|
|
@ -4,60 +4,66 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void lovrMeshBindAttribute(Shader* shader, Mesh *mesh, VertexFormat *format, int i, bool enabled, int divisor) {
|
||||
Attribute attribute = format->attributes[i];
|
||||
int location = lovrShaderGetAttributeId(shader, attribute.name);
|
||||
|
||||
if (location >= 0) {
|
||||
if (enabled) {
|
||||
glEnableVertexAttribArray(location);
|
||||
|
||||
GLenum glType;
|
||||
switch (attribute.type) {
|
||||
case ATTR_FLOAT: glType = GL_FLOAT; break;
|
||||
case ATTR_BYTE: glType = GL_UNSIGNED_BYTE; break;
|
||||
case ATTR_INT: glType = GL_UNSIGNED_INT; break;
|
||||
}
|
||||
|
||||
// Divisor lives in the VAO and the VAO is per-mesh, so the only reason we would need to set a zero divisor for an attribute is if a nonzero divisor attribute is attached then disabled, and a zero divisor attribute is enabled afterward in its place. Nonzero attachments length is used to determine there is a risk this has happened.
|
||||
if (divisor || mesh->attachments.length)
|
||||
glVertexAttribDivisor(location, divisor);
|
||||
|
||||
if (attribute.type == ATTR_INT) {
|
||||
glVertexAttribIPointer(location, attribute.count, glType, format->stride, (void*) attribute.offset);
|
||||
} else {
|
||||
glVertexAttribPointer(location, attribute.count, glType, GL_TRUE, format->stride, (void*) attribute.offset);
|
||||
}
|
||||
} else {
|
||||
glDisableVertexAttribArray(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lovrMeshBindAttributes(Mesh* mesh) {
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attachments);
|
||||
Shader* shader = lovrGraphicsGetActiveShader();
|
||||
if (shader == mesh->lastShader && !mesh->attributesDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
lovrGraphicsBindVertexBuffer(mesh->vbo);
|
||||
MeshAttachment layout[MAX_ATTACHMENTS];
|
||||
memset(layout, 0, MAX_ATTACHMENTS * sizeof(MeshAttachment));
|
||||
|
||||
VertexFormat* format = &mesh->vertexData->format;
|
||||
for (int i = 0; i < format->count; i++) {
|
||||
lovrMeshBindAttribute(shader, mesh, format, i, mesh->enabledAttributes & (1 << i), 0);
|
||||
}
|
||||
while ((key = map_next(&mesh->attachments, &iter)) != NULL) {
|
||||
int location = lovrShaderGetAttributeId(shader, key);
|
||||
|
||||
{
|
||||
int i; MeshAttachment attachment;
|
||||
vec_foreach(&mesh->attachments, attachment, i) {
|
||||
lovrGraphicsBindVertexBuffer(attachment.mesh->vbo);
|
||||
// TODO: Allow disabling of attached attributes?
|
||||
lovrMeshBindAttribute(shader, attachment.mesh, &attachment.mesh->vertexData->format, attachment.attribute, true, attachment.instanceDivisor);
|
||||
if (location >= 0) {
|
||||
MeshAttachment* attachment = map_get(&mesh->attachments, key);
|
||||
layout[location] = *attachment;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->lastShader = shader;
|
||||
mesh->attributesDirty = false;
|
||||
for (int i = 0; i < MAX_ATTACHMENTS; i++) {
|
||||
MeshAttachment previous = mesh->layout[i];
|
||||
MeshAttachment current = layout[i];
|
||||
|
||||
if (!memcmp(&previous, ¤t, sizeof(MeshAttachment))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (previous.enabled != current.enabled) {
|
||||
if (current.enabled) {
|
||||
glEnableVertexAttribArray(i);
|
||||
} else {
|
||||
glDisableVertexAttribArray(i);
|
||||
mesh->layout[i] = current;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous.divisor != current.divisor) {
|
||||
glVertexAttribDivisor(i, current.divisor);
|
||||
}
|
||||
|
||||
if (previous.mesh != current.mesh || previous.attributeIndex != current.attributeIndex) {
|
||||
lovrGraphicsBindVertexBuffer(current.mesh->vbo);
|
||||
VertexFormat* format = ¤t.mesh->vertexData->format;
|
||||
Attribute attribute = format->attributes[current.attributeIndex];
|
||||
switch (attribute.type) {
|
||||
case ATTR_FLOAT:
|
||||
glVertexAttribPointer(i, attribute.count, GL_FLOAT, GL_TRUE, format->stride, (void*) attribute.offset);
|
||||
break;
|
||||
|
||||
case ATTR_BYTE:
|
||||
glVertexAttribPointer(i, attribute.count, GL_UNSIGNED_BYTE, GL_TRUE, format->stride, (void*) attribute.offset);
|
||||
break;
|
||||
|
||||
case ATTR_INT:
|
||||
glVertexAttribIPointer(i, attribute.count, GL_UNSIGNED_INT, format->stride, (void*) attribute.offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mesh->layout[i] = current;
|
||||
}
|
||||
}
|
||||
|
||||
Mesh* lovrMeshCreate(VertexData* vertexData, MeshDrawMode drawMode, MeshUsage usage) {
|
||||
|
@ -69,8 +75,6 @@ Mesh* lovrMeshCreate(VertexData* vertexData, MeshDrawMode drawMode, MeshUsage us
|
|||
mesh->indices.raw = NULL;
|
||||
mesh->indexCount = 0;
|
||||
mesh->indexSize = count > USHRT_MAX ? sizeof(uint32_t) : sizeof(uint16_t);
|
||||
mesh->enabledAttributes = ~0;
|
||||
mesh->attributesDirty = true;
|
||||
mesh->isMapped = false;
|
||||
mesh->mapStart = 0;
|
||||
mesh->mapCount = 0;
|
||||
|
@ -83,9 +87,7 @@ Mesh* lovrMeshCreate(VertexData* vertexData, MeshDrawMode drawMode, MeshUsage us
|
|||
mesh->vbo = 0;
|
||||
mesh->ibo = 0;
|
||||
mesh->material = NULL;
|
||||
vec_init(&mesh->attachments);
|
||||
mesh->lastShader = NULL;
|
||||
mesh->isAnAttachment = false;
|
||||
mesh->isAttachment = false;
|
||||
|
||||
glGenBuffers(1, &mesh->vbo);
|
||||
glGenBuffers(1, &mesh->ibo);
|
||||
|
@ -93,6 +95,14 @@ Mesh* lovrMeshCreate(VertexData* vertexData, MeshDrawMode drawMode, MeshUsage us
|
|||
glBufferData(GL_ARRAY_BUFFER, count * mesh->vertexData->format.stride, vertexData->blob.data, mesh->usage);
|
||||
glGenVertexArrays(1, &mesh->vao);
|
||||
|
||||
map_init(&mesh->attachments);
|
||||
for (int i = 0; i < vertexData->format.count; i++) {
|
||||
MeshAttachment attachment = { mesh, i, 0, true };
|
||||
map_set(&mesh->attachments, vertexData->format.attributes[i].name, attachment);
|
||||
}
|
||||
|
||||
memset(mesh->layout, 0, MAX_ATTACHMENTS * sizeof(MeshAttachment));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@ -103,19 +113,40 @@ void lovrMeshDestroy(void* ref) {
|
|||
glDeleteBuffers(1, &mesh->vbo);
|
||||
glDeleteBuffers(1, &mesh->ibo);
|
||||
glDeleteVertexArrays(1, &mesh->vao);
|
||||
|
||||
{
|
||||
int i; MeshAttachment attachment;
|
||||
vec_foreach(&mesh->attachments, attachment, i) {
|
||||
lovrRelease(attachment.mesh);
|
||||
const char* key;
|
||||
map_iter_t iter = map_iter(&mesh->attachments);
|
||||
while ((key = map_next(&mesh->attachments, &iter)) != NULL) {
|
||||
MeshAttachment* attachment = map_get(&mesh->attachments, key);
|
||||
if (attachment->mesh != mesh) {
|
||||
lovrRelease(attachment->mesh);
|
||||
}
|
||||
}
|
||||
vec_deinit(&mesh->attachments);
|
||||
|
||||
map_deinit(&mesh->attachments);
|
||||
free(mesh->indices.raw);
|
||||
free(mesh);
|
||||
}
|
||||
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, Mesh* other, const char* name, int divisor) {
|
||||
MeshAttachment* otherAttachment = map_get(&other->attachments, name);
|
||||
lovrAssert(!mesh->isAttachment, "Attempted to attach to a mesh which is an attachment itself");
|
||||
lovrAssert(otherAttachment, "No attribute named '%s' exists", name);
|
||||
lovrAssert(!map_get(&mesh->attachments, name), "Mesh already has an attribute named '%s'", name);
|
||||
lovrAssert(divisor >= 0, "Divisor can't be negative");
|
||||
|
||||
MeshAttachment attachment = { other, otherAttachment->attributeIndex, divisor, true };
|
||||
map_set(&mesh->attachments, name, attachment);
|
||||
other->isAttachment = true;
|
||||
lovrRetain(other);
|
||||
}
|
||||
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name) {
|
||||
MeshAttachment* attachment = map_get(&mesh->attachments, name);
|
||||
lovrAssert(attachment, "No attached attribute '%s' was found", name);
|
||||
lovrAssert(attachment->mesh != mesh, "Attribute '%s' was not attached from another Mesh", name);
|
||||
lovrRelease(attachment->mesh);
|
||||
map_remove(&mesh->attachments, name);
|
||||
}
|
||||
|
||||
void lovrMeshDraw(Mesh* mesh, mat4 transform, float* pose, int instances) {
|
||||
if (mesh->isMapped) {
|
||||
lovrMeshUnmap(mesh);
|
||||
|
@ -187,28 +218,15 @@ void lovrMeshSetVertexMap(Mesh* mesh, void* data, size_t count) {
|
|||
}
|
||||
|
||||
bool lovrMeshIsAttributeEnabled(Mesh* mesh, const char* name) {
|
||||
for (int i = 0; i < mesh->vertexData->format.count; i++) {
|
||||
if (!strcmp(mesh->vertexData->format.attributes[i].name, name)) {
|
||||
return mesh->enabledAttributes & (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
MeshAttachment* attachment = map_get(&mesh->attachments, name);
|
||||
lovrAssert(attachment, "Mesh does not have an attribute named '%s'", name);
|
||||
return attachment->enabled;
|
||||
}
|
||||
|
||||
void lovrMeshSetAttributeEnabled(Mesh* mesh, const char* name, bool enable) {
|
||||
for (int i = 0; i < mesh->vertexData->format.count; i++) {
|
||||
if (!strcmp(mesh->vertexData->format.attributes[i].name, name)) {
|
||||
int mask = 1 << i;
|
||||
if (enable && !(mesh->enabledAttributes & mask)) {
|
||||
mesh->enabledAttributes |= mask;
|
||||
mesh->attributesDirty = true;
|
||||
} else if (!enable && (mesh->enabledAttributes & mask)) {
|
||||
mesh->enabledAttributes &= ~(1 << i);
|
||||
mesh->attributesDirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
MeshAttachment* attachment = map_get(&mesh->attachments, name);
|
||||
lovrAssert(attachment, "Mesh does not have an attribute named '%s'", name);
|
||||
attachment->enabled = enable;
|
||||
}
|
||||
|
||||
bool lovrMeshIsRangeEnabled(Mesh* mesh) {
|
||||
|
@ -294,14 +312,3 @@ void lovrMeshUnmap(Mesh* mesh) {
|
|||
glUnmapBuffer(GL_ARRAY_BUFFER);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lovrMeshAttach(Mesh *attachTo, Mesh* attachThis, int attribute, int instanceDivisor)
|
||||
{
|
||||
lovrAssert(!attachTo->isAnAttachment, "Attempted to attach to a mesh which is an attachment itself");
|
||||
lovrAssert(!attachThis->attachments.length, "Attempted to attach a mesh which has attachments itself");
|
||||
|
||||
MeshAttachment attachment = {attachThis, attribute, instanceDivisor};
|
||||
attachThis->isAnAttachment = true;
|
||||
lovrRetain(attachThis);
|
||||
vec_push(&attachTo->attachments, attachment);
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
#include "graphics/shader.h"
|
||||
#include "graphics/material.h"
|
||||
#include "data/vertexData.h"
|
||||
#include "math/math.h"
|
||||
#include "lib/glfw.h"
|
||||
#include "lib/map/map.h"
|
||||
#include "util.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MAX_ATTACHMENTS 16
|
||||
|
||||
typedef enum {
|
||||
MESH_POINTS = GL_POINTS,
|
||||
MESH_LINES = GL_LINES,
|
||||
|
@ -25,12 +27,13 @@ typedef enum {
|
|||
typedef struct Mesh Mesh;
|
||||
|
||||
typedef struct {
|
||||
Mesh *mesh;
|
||||
int attribute;
|
||||
int instanceDivisor;
|
||||
Mesh* mesh;
|
||||
int attributeIndex;
|
||||
int divisor;
|
||||
bool enabled;
|
||||
} MeshAttachment;
|
||||
|
||||
typedef vec_t(MeshAttachment) vec_meshattachment_t;
|
||||
typedef map_t(MeshAttachment) map_attachment_t;
|
||||
|
||||
struct Mesh {
|
||||
Ref ref;
|
||||
|
@ -38,8 +41,6 @@ struct Mesh {
|
|||
IndexPointer indices;
|
||||
size_t indexCount;
|
||||
size_t indexSize;
|
||||
int enabledAttributes;
|
||||
bool attributesDirty;
|
||||
bool isMapped;
|
||||
int mapStart;
|
||||
size_t mapCount;
|
||||
|
@ -52,13 +53,15 @@ struct Mesh {
|
|||
GLuint vbo;
|
||||
GLuint ibo;
|
||||
Material* material;
|
||||
Shader* lastShader;
|
||||
vec_meshattachment_t attachments;
|
||||
bool isAnAttachment;
|
||||
map_attachment_t attachments;
|
||||
MeshAttachment layout[16];
|
||||
bool isAttachment;
|
||||
};
|
||||
|
||||
Mesh* lovrMeshCreate(VertexData* vertexData, MeshDrawMode drawMode, MeshUsage usage);
|
||||
void lovrMeshDestroy(void* ref);
|
||||
void lovrMeshAttachAttribute(Mesh* mesh, Mesh* other, const char* name, int divisor);
|
||||
void lovrMeshDetachAttribute(Mesh* mesh, const char* name);
|
||||
void lovrMeshDraw(Mesh* mesh, mat4 transform, float* pose, int instances);
|
||||
VertexFormat* lovrMeshGetVertexFormat(Mesh* mesh);
|
||||
MeshDrawMode lovrMeshGetDrawMode(Mesh* mesh);
|
||||
|
@ -76,4 +79,3 @@ Material* lovrMeshGetMaterial(Mesh* mesh);
|
|||
void lovrMeshSetMaterial(Mesh* mesh, Material* material);
|
||||
VertexPointer lovrMeshMap(Mesh* mesh, int start, size_t count, bool read, bool write);
|
||||
void lovrMeshUnmap(Mesh* mesh);
|
||||
void lovrMeshAttach(Mesh *attachTo, Mesh* attachThis, int attribute, int instanceDivisor);
|
||||
|
|
Loading…
Reference in New Issue