diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 86059fcb9..42ef895b5 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -217,11 +217,6 @@ ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::s return s; } -void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &hashkey) -{ - cachedShaderStages[type].erase(hashkey); -} - Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel) { if (vertex.empty() && pixel.empty()) @@ -233,6 +228,21 @@ Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel) return newShaderInternal(vertexstage.get(), pixelstage.get()); } +Mesh *Graphics::newMesh(const std::vector &vertices, PrimitiveType drawmode, vertex::Usage usage) +{ + return newMesh(Mesh::getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage); +} + +Mesh *Graphics::newMesh(int vertexcount, PrimitiveType drawmode, vertex::Usage usage) +{ + return newMesh(Mesh::getDefaultVertexFormat(), vertexcount, drawmode, usage); +} + +void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &hashkey) +{ + cachedShaderStages[type].erase(hashkey); +} + bool Graphics::validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err) { if (vertex.empty() && pixel.empty()) @@ -1040,7 +1050,7 @@ void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t num bool is2D = t.isAffine2DTransform(); StreamDrawCommand cmd; - cmd.primitiveMode = vertex::PrimitiveMode::POINTS; + cmd.primitiveMode = PRIMITIVE_POINTS; cmd.formats[0] = vertex::getSinglePositionFormat(is2D); cmd.formats[1] = vertex::CommonFormat::RGBAub; cmd.vertexCount = (int) numpoints; diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index d9cd69bc4..7c591f484 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -252,7 +252,7 @@ public: struct StreamDrawCommand { - vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES; + PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES; vertex::CommonFormat formats[2]; vertex::TriangleIndexMode indexMode = vertex::TriangleIndexMode::NONE; int vertexCount = 0; @@ -391,11 +391,11 @@ public: virtual Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) = 0; - virtual Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) = 0; - virtual Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) = 0; + Mesh *newMesh(const std::vector &vertices, PrimitiveType drawmode, vertex::Usage usage); + Mesh *newMesh(int vertexcount, PrimitiveType drawmode, vertex::Usage usage); - virtual Mesh *newMesh(const std::vector &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) = 0; - virtual Mesh *newMesh(const std::vector &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) = 0; + virtual Mesh *newMesh(const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) = 0; + virtual Mesh *newMesh(const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) = 0; virtual Text *newText(Font *font, const std::vector &text = {}) = 0; @@ -861,7 +861,7 @@ protected: StreamBuffer *vb[2]; StreamBuffer *indexBuffer = nullptr; - vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES; + PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES; vertex::CommonFormat formats[2]; StrongRef texture; Shader::StandardShader standardShaderType = Shader::STANDARD_DEFAULT; diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index 9f0256728..bb2ec67f0 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -49,9 +49,9 @@ std::vector Mesh::getDefaultVertexFormat() { // Corresponds to the love::Vertex struct. std::vector vertexformat = { - {getBuiltinAttribName(ATTRIB_POS), Mesh::DATA_FLOAT, 2}, - {getBuiltinAttribName(ATTRIB_TEXCOORD), Mesh::DATA_FLOAT, 2}, - {getBuiltinAttribName(ATTRIB_COLOR), Mesh::DATA_BYTE, 4}, + { getBuiltinAttribName(ATTRIB_POS), vertex::DATA_FLOAT, 2 }, + { getBuiltinAttribName(ATTRIB_TEXCOORD), vertex::DATA_FLOAT, 2 }, + { getBuiltinAttribName(ATTRIB_COLOR), vertex::DATA_UNORM8, 4 }, }; return vertexformat; @@ -59,16 +59,16 @@ std::vector Mesh::getDefaultVertexFormat() love::Type Mesh::type("Mesh", &Drawable::type); -Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) : vertexFormat(vertexformat) , vbo(nullptr) , vertexCount(0) , vertexStride(0) , ibo(nullptr) , useIndexBuffer(false) - , elementCount(0) - , elementDataType(INDEX_UINT16) - , drawMode(drawmode) + , indexCount(0) + , indexDataType(INDEX_UINT16) + , primitiveType(drawmode) , rangeStart(-1) , rangeCount(-1) { @@ -76,7 +76,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexforma calculateAttributeSizes(); vertexCount = datasize / vertexStride; - elementDataType = vertex::getIndexDataTypeFromMax(vertexCount); + indexDataType = vertex::getIndexDataTypeFromMax(vertexCount); if (vertexCount == 0) throw love::Exception("Data size is too small for specified vertex attribute formats."); @@ -86,16 +86,16 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexforma vertexScratchBuffer = new char[vertexStride]; } -Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) : vertexFormat(vertexformat) , vbo(nullptr) , vertexCount((size_t) vertexcount) , vertexStride(0) , ibo(nullptr) , useIndexBuffer(false) - , elementCount(0) - , elementDataType(vertex::getIndexDataTypeFromMax(vertexcount)) - , drawMode(drawmode) + , indexCount(0) + , indexDataType(vertex::getIndexDataTypeFromMax(vertexcount)) + , primitiveType(drawmode) , rangeStart(-1) , rangeCount(-1) { @@ -149,16 +149,18 @@ void Mesh::calculateAttributeSizes() for (const AttribFormat &format : vertexFormat) { - // Hardware really doesn't like attributes that aren't 32 bit-aligned. - if (format.type == DATA_BYTE && format.components != 4) - throw love::Exception("byte vertex attributes must have 4 components."); + size_t size = vertex::getDataTypeSize(format.type) * format.components; if (format.components <= 0 || format.components > 4) throw love::Exception("Vertex attributes must have between 1 and 4 components."); + // Hardware really doesn't like attributes that aren't 32 bit-aligned. + if (size % 4 != 0) + throw love::Exception("Vertex attributes must have enough components to be a multiple of 32 bits."); + // Total size in bytes of each attribute in a single vertex. - attributeSizes.push_back(getAttribFormatSize(format)); - stride += attributeSizes.back(); + attributeSizes.push_back(size); + stride += size; } vertexStride = stride; @@ -258,15 +260,13 @@ const std::vector &Mesh::getVertexFormat() const return vertexFormat; } -Mesh::DataType Mesh::getAttributeInfo(int attribindex, int &components) const +vertex::DataType Mesh::getAttributeInfo(int attribindex, int &components) const { if (attribindex < 0 || attribindex >= (int) vertexFormat.size()) throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1); - DataType type = vertexFormat[attribindex].type; components = vertexFormat[attribindex].components; - - return type; + return vertexFormat[attribindex].type; } int Mesh::getAttributeIndex(const std::string &name) const @@ -417,9 +417,9 @@ void Mesh::setVertexMap(const std::vector &map) } useIndexBuffer = true; - elementCount = map.size(); + indexCount = map.size(); - if (!ibo || elementCount == 0) + if (!ibo || indexCount == 0) return; Buffer::Mapper ibomap(*ibo); @@ -436,7 +436,7 @@ void Mesh::setVertexMap(const std::vector &map) break; } - elementDataType = datatype; + indexDataType = datatype; } void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize) @@ -453,16 +453,16 @@ void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasiz ibo = gfx->newBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ); } - elementCount = datasize / vertex::getIndexDataSize(datatype); + indexCount = datasize / vertex::getIndexDataSize(datatype); - if (!ibo || elementCount == 0) + if (!ibo || indexCount == 0) return; Buffer::Mapper ibomap(*ibo); memcpy(ibomap.get(), data, datasize); useIndexBuffer = true; - elementDataType = datatype; + indexDataType = datatype; } void Mesh::setVertexMap() @@ -487,23 +487,23 @@ bool Mesh::getVertexMap(std::vector &map) const return false; map.clear(); - map.reserve(elementCount); + map.reserve(indexCount); - if (!ibo || elementCount == 0) + if (!ibo || indexCount == 0) return true; // We unmap the buffer in Mesh::draw, Mesh::setVertexMap, and Mesh::flush. void *buffer = ibo->map(); // Fill the vector from the buffer. - switch (elementDataType) + switch (indexDataType) { case INDEX_UINT16: - copyFromIndexBuffer(buffer, elementCount, map); + copyFromIndexBuffer(buffer, indexCount, map); break; case INDEX_UINT32: default: - copyFromIndexBuffer(buffer, elementCount, map); + copyFromIndexBuffer(buffer, indexCount, map); break; } @@ -512,7 +512,7 @@ bool Mesh::getVertexMap(std::vector &map) const size_t Mesh::getVertexMapCount() const { - return elementCount; + return indexCount; } void Mesh::setTexture(Texture *tex) @@ -530,14 +530,14 @@ Texture *Mesh::getTexture() const return texture.get(); } -void Mesh::setDrawMode(DrawMode mode) +void Mesh::setDrawMode(PrimitiveType mode) { - drawMode = mode; + primitiveType = mode; } -Mesh::DrawMode Mesh::getDrawMode() const +PrimitiveType Mesh::getDrawMode() const { - return drawMode; + return primitiveType; } void Mesh::setDrawRange(int start, int count) @@ -611,7 +611,7 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) if (!(enabledattribs & ATTRIBFLAG_POS)) throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn."); - bool useindexbuffer = useIndexBuffer && ibo != nullptr && elementCount > 0; + bool useindexbuffer = useIndexBuffer && ibo != nullptr && indexCount > 0; int start = 0; int count = 0; @@ -621,13 +621,13 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); - start = std::min(std::max(0, rangeStart), (int) elementCount - 1); + start = std::min(std::max(0, rangeStart), (int) indexCount - 1); - count = (int) elementCount; + count = (int) indexCount; if (rangeCount > 0) count = std::min(count, rangeCount); - count = std::min(count, (int) elementCount - start); + count = std::min(count, (int) indexCount - start); } else { @@ -646,89 +646,5 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) drawInternal(start, count, instancecount, useindexbuffer, enabledattribs, instancedattribs); } -size_t Mesh::getAttribFormatSize(const AttribFormat &format) -{ - switch (format.type) - { - case DATA_BYTE: - return format.components * sizeof(uint8); - case DATA_FLOAT: - return format.components * sizeof(float); - default: - return 0; - } -} - -bool Mesh::getConstant(const char *in, DrawMode &out) -{ - return drawModes.find(in, out); -} - -bool Mesh::getConstant(DrawMode in, const char *&out) -{ - return drawModes.find(in, out); -} - -std::vector Mesh::getConstants(DrawMode) -{ - return drawModes.getNames(); -} - -bool Mesh::getConstant(const char *in, DataType &out) -{ - return dataTypes.find(in, out); -} - -bool Mesh::getConstant(DataType in, const char *&out) -{ - return dataTypes.find(in, out); -} - -std::vector Mesh::getConstants(DataType) -{ - return dataTypes.getNames(); -} - -bool Mesh::getConstant(const char *in, AttributeStep &out) -{ - return attributeSteps.find(in, out); -} - -bool Mesh::getConstant(AttributeStep in, const char *&out) -{ - return attributeSteps.find(in, out); -} - -std::vector Mesh::getConstants(AttributeStep) -{ - return attributeSteps.getNames(); -} - -StringMap::Entry Mesh::drawModeEntries[] = -{ - { "fan", DRAWMODE_FAN }, - { "strip", DRAWMODE_STRIP }, - { "triangles", DRAWMODE_TRIANGLES }, - { "points", DRAWMODE_POINTS }, -}; - -StringMap Mesh::drawModes(Mesh::drawModeEntries, sizeof(Mesh::drawModeEntries)); - -StringMap::Entry Mesh::dataTypeEntries[] = -{ - { "byte", DATA_BYTE }, - { "float", DATA_FLOAT }, -}; - -StringMap Mesh::dataTypes(Mesh::dataTypeEntries, sizeof(Mesh::dataTypeEntries)); - -StringMap::Entry Mesh::attributeStepEntries[] = -{ - { "pervertex", STEP_PER_VERTEX }, - { "perinstance", STEP_PER_INSTANCE }, -}; - -StringMap Mesh::attributeSteps(Mesh::attributeStepEntries, sizeof(Mesh::attributeStepEntries)); - } // graphics } // love diff --git a/src/modules/graphics/Mesh.h b/src/modules/graphics/Mesh.h index dd250d91e..2cf103a34 100644 --- a/src/modules/graphics/Mesh.h +++ b/src/modules/graphics/Mesh.h @@ -52,41 +52,15 @@ public: static love::Type type; - // How the Mesh's vertices are used when drawing. - // http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png - enum DrawMode - { - DRAWMODE_FAN, - DRAWMODE_STRIP, - DRAWMODE_TRIANGLES, - DRAWMODE_POINTS, - DRAWMODE_MAX_ENUM - }; - - // The type of data a vertex attribute can store. - enum DataType - { - DATA_BYTE, - DATA_FLOAT, - DATA_MAX_ENUM - }; - - enum AttributeStep - { - STEP_PER_VERTEX, - STEP_PER_INSTANCE, - STEP_MAX_ENUM - }; - struct AttribFormat { std::string name; - DataType type; + vertex::DataType type; int components; // max 4 }; - Mesh(Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage); - Mesh(Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage); + Mesh(Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage); + Mesh(Graphics *gfx, const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage); virtual ~Mesh(); @@ -122,7 +96,7 @@ public: * Gets the format of each vertex attribute stored in the Mesh. **/ const std::vector &getVertexFormat() const; - DataType getAttributeInfo(int attribindex, int &components) const; + vertex::DataType getAttributeInfo(int attribindex, int &components) const; int getAttributeIndex(const std::string &name) const; /** @@ -186,8 +160,8 @@ public: /** * Sets the draw mode used when drawing the Mesh. **/ - void setDrawMode(DrawMode mode); - DrawMode getDrawMode() const; + void setDrawMode(PrimitiveType mode); + PrimitiveType getDrawMode() const; void setDrawRange(int start, int count); void setDrawRange(); @@ -200,17 +174,7 @@ public: void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount); - static bool getConstant(const char *in, DrawMode &out); - static bool getConstant(DrawMode in, const char *&out); - static std::vector getConstants(DrawMode); - - static bool getConstant(const char *in, DataType &out); - static bool getConstant(DataType in, const char *&out); - static std::vector getConstants(DataType); - - static bool getConstant(const char *in, AttributeStep &out); - static bool getConstant(AttributeStep in, const char *&out); - static std::vector getConstants(AttributeStep); + static std::vector getDefaultVertexFormat(); protected: @@ -228,9 +192,6 @@ protected: virtual void drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const = 0; - static size_t getAttribFormatSize(const AttribFormat &format); - static std::vector getDefaultVertexFormat(); - std::vector vertexFormat; std::vector attributeSizes; @@ -245,30 +206,19 @@ protected: // avoid memory allocations when using Mesh::setVertex etc. char *vertexScratchBuffer; - // Element (vertex index) buffer, for the vertex map. + // Index buffer, for the vertex map. Buffer *ibo; bool useIndexBuffer; - size_t elementCount; - IndexDataType elementDataType; - - DrawMode drawMode; - + size_t indexCount; + IndexDataType indexDataType; + + PrimitiveType primitiveType; + int rangeStart; int rangeCount; - + StrongRef texture; -private: - - static StringMap::Entry drawModeEntries[]; - static StringMap drawModes; - - static StringMap::Entry dataTypeEntries[]; - static StringMap dataTypes; - - static StringMap::Entry attributeStepEntries[]; - static StringMap attributeSteps; - }; // Mesh } // graphics diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index b338c6a4d..f2082f220 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -161,6 +161,8 @@ public: **/ virtual std::string getWarnings() const = 0; + virtual int getVertexAttributeIndex(const std::string &name) = 0; + virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0; virtual const UniformInfo *getUniformInfo(BuiltinUniform builtin) const = 0; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 3e8a248ad..37076b0ab 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -142,22 +142,12 @@ love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, Buffe return new Buffer(size, data, type, usage, mapflags); } -love::graphics::Mesh *Graphics::newMesh(const std::vector &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) -{ - return new Mesh(this, vertices, drawmode, usage); -} - -love::graphics::Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) -{ - return new Mesh(this, vertexcount, drawmode, usage); -} - -love::graphics::Mesh *Graphics::newMesh(const std::vector &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) +love::graphics::Mesh *Graphics::newMesh(const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) { return new Mesh(this, vertexformat, vertexcount, drawmode, usage); } -love::graphics::Mesh *Graphics::newMesh(const std::vector &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) +love::graphics::Mesh *Graphics::newMesh(const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) { return new Mesh(this, vertexformat, data, datasize, drawmode, usage); } @@ -387,17 +377,7 @@ void Graphics::flushStreamDraws() if (attribs == 0) return; - GLenum glmode = GL_ZERO; - - switch (sbstate.primitiveMode) - { - case PrimitiveMode::TRIANGLES: - glmode = GL_TRIANGLES; - break; - case PrimitiveMode::POINTS: - glmode = GL_POINTS; - break; - } + GLenum glprimitivetype = OpenGL::getGLPrimitiveType(sbstate.primitiveMode); Colorf nc = gl.getConstantColor(); if (attribs & ATTRIBFLAG_COLOR) @@ -419,10 +399,10 @@ void Graphics::flushStreamDraws() sbstate.indexBufferMap = StreamBuffer::MapInfo(); - gl.drawElements(glmode, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset)); + gl.drawElements(glprimitivetype, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset)); } else - gl.drawArrays(glmode, 0, sbstate.vertexCount); + gl.drawArrays(glprimitivetype, 0, sbstate.vertexCount); for (int i = 0; i < 2; i++) { @@ -1266,7 +1246,7 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode) void Graphics::setPointSize(float size) { - if (streamBufferState.primitiveMode == vertex::PrimitiveMode::POINTS) + if (streamBufferState.primitiveMode == PRIMITIVE_POINTS) flushStreamDraws(); gl.setPointSize(size * getCurrentDPIScale()); diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 6b3655d89..d1ef8a681 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -71,11 +71,8 @@ public: love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override; - love::graphics::Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) override; - love::graphics::Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) override; - - love::graphics::Mesh *newMesh(const std::vector &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) override; - love::graphics::Mesh *newMesh(const std::vector &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) override; + love::graphics::Mesh *newMesh(const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) override; + love::graphics::Mesh *newMesh(const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) override; love::graphics::Text *newText(love::graphics::Font *font, const std::vector &text = {}) override; diff --git a/src/modules/graphics/opengl/Mesh.cpp b/src/modules/graphics/opengl/Mesh.cpp index 2fc564f4f..2d89fb7bd 100644 --- a/src/modules/graphics/opengl/Mesh.cpp +++ b/src/modules/graphics/opengl/Mesh.cpp @@ -35,26 +35,16 @@ namespace graphics namespace opengl { -Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) : love::graphics::Mesh(gfx, vertexformat, data, datasize, drawmode, usage) { } -Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage) +Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) : love::graphics::Mesh(gfx, vertexformat, vertexcount, drawmode, usage) { } -Mesh::Mesh(graphics::Graphics *gfx, const std::vector &vertices, DrawMode drawmode, vertex::Usage usage) - : Mesh(gfx, getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage) -{ -} - -Mesh::Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage) - : Mesh(gfx, getDefaultVertexFormat(), vertexcount, drawmode, usage) -{ -} - Mesh::~Mesh() { } @@ -71,7 +61,7 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu if (vertex::getConstant(inputname.c_str(), builtinattrib)) attriblocation = (GLint) builtinattrib; else if (Shader::current) - attriblocation = ((Shader *) Shader::current)->getAttribLocation(inputname); + attriblocation = Shader::current->getVertexAttributeIndex(inputname); // The active shader might not use this vertex attribute name. if (attriblocation < 0) @@ -81,23 +71,11 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu vbo->unmap(); gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle()); - - GLenum datatype = 0; - switch (format.type) - { - case DATA_BYTE: - datatype = GL_UNSIGNED_BYTE; - break; - case DATA_FLOAT: - datatype = GL_FLOAT; - break; - default: - datatype = 0; - break; - } + + GLboolean normalized = GL_FALSE; + GLenum datatype = OpenGL::getGLVertexDataType(format.type, normalized); const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex)); - GLboolean normalized = (datatype == GL_UNSIGNED_BYTE); glVertexAttribPointer(attriblocation, format.components, datatype, normalized, (GLsizei) vertexStride, gloffset); @@ -111,37 +89,21 @@ void Mesh::drawInternal(int start, int count, int instancecount, bool useindexbu gl.useVertexAttribArrays(attribflags, instancedattribflags); gl.bindTextureToUnit(texture, 0, false); gl.prepareDraw(); - - GLenum gldrawmode = GL_TRIANGLES; - switch (drawMode) - { - case DRAWMODE_FAN: - gldrawmode = GL_TRIANGLE_FAN; - break; - case DRAWMODE_STRIP: - gldrawmode = GL_TRIANGLE_STRIP; - break; - case DRAWMODE_TRIANGLES: - default: - gldrawmode = GL_TRIANGLES; - break; - case DRAWMODE_POINTS: - gldrawmode = GL_POINTS; - break; - } + + GLenum glprimitivetype = OpenGL::getGLPrimitiveType(primitiveType); if (useindexbuffer) { - size_t elementsize = vertex::getIndexDataSize(elementDataType); + size_t elementsize = vertex::getIndexDataSize(indexDataType); const void *indices = BUFFER_OFFSET(start * elementsize); - GLenum type = OpenGL::getGLIndexDataType(elementDataType); + GLenum indextype = OpenGL::getGLIndexDataType(indexDataType); gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle()); - gl.drawElements(gldrawmode, count, type, indices, instancecount); + gl.drawElements(glprimitivetype, count, indextype, indices, instancecount); } else { - gl.drawArrays(gldrawmode, start, count, instancecount); + gl.drawArrays(glprimitivetype, start, count, instancecount); } } diff --git a/src/modules/graphics/opengl/Mesh.h b/src/modules/graphics/opengl/Mesh.h index 018e1a4ca..41d693974 100644 --- a/src/modules/graphics/opengl/Mesh.h +++ b/src/modules/graphics/opengl/Mesh.h @@ -35,11 +35,8 @@ class Mesh final : public love::graphics::Mesh { public: - Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage); - Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage); - - Mesh(graphics::Graphics *gfx, const std::vector &vertices, DrawMode drawmode, vertex::Usage usage); - Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage); + Mesh(graphics::Graphics *gfx, const std::vector &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage); virtual ~Mesh(); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 0df714c8b..6a73d236d 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -504,6 +504,25 @@ void OpenGL::prepareDraw() } } +GLenum OpenGL::getGLPrimitiveType(PrimitiveType type) +{ + switch (type) + { + case PRIMITIVE_TRIANGLES: + return GL_TRIANGLES; + case PRIMITIVE_TRIANGLE_STRIP: + return GL_TRIANGLE_STRIP; + case PRIMITIVE_TRIANGLE_FAN: + return GL_TRIANGLE_FAN; + case PRIMITIVE_POINTS: + return GL_POINTS; + case PRIMITIVE_MAX_ENUM: + return GL_ZERO; + } + + return GL_ZERO; +} + GLenum OpenGL::getGLBufferType(BufferType type) { switch (type) @@ -551,6 +570,28 @@ GLenum OpenGL::getGLIndexDataType(IndexDataType type) } } +GLenum OpenGL::getGLVertexDataType(vertex::DataType type, GLboolean &normalized) +{ + normalized = GL_FALSE; + + switch (type) + { + case vertex::DATA_UNORM8: + normalized = GL_TRUE; + return GL_UNSIGNED_BYTE; + case vertex::DATA_UNORM16: + normalized = GL_TRUE; + return GL_UNSIGNED_SHORT; + case vertex::DATA_FLOAT: + normalized = GL_FALSE; + return GL_FLOAT; + case vertex::DATA_MAX_ENUM: + return GL_ZERO; + } + + return GL_ZERO; +} + GLenum OpenGL::getGLBufferUsage(vertex::Usage usage) { switch (usage) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 034bbc885..37ff4b40d 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -380,8 +380,10 @@ public: **/ Vendor getVendor() const; + static GLenum getGLPrimitiveType(PrimitiveType type); static GLenum getGLBufferType(BufferType type); static GLenum getGLIndexDataType(IndexDataType type); + static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized); static GLenum getGLBufferUsage(vertex::Usage usage); static GLenum getGLTextureType(TextureType type); static GLint getGLWrapMode(Texture::WrapMode wmode); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index 6475e5120..67b183efb 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -669,7 +669,7 @@ ptrdiff_t Shader::getHandle() const return program; } -GLint Shader::getAttribLocation(const std::string &name) +int Shader::getVertexAttributeIndex(const std::string &name) { auto it = attributes.find(name); if (it != attributes.end()) diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 838422ad6..66c50a308 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -57,6 +57,7 @@ public: // Implements Shader. void attach() override; std::string getWarnings() const override; + int getVertexAttributeIndex(const std::string &name) override; const UniformInfo *getUniformInfo(const std::string &name) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; @@ -65,8 +66,6 @@ public: ptrdiff_t getHandle() const override; void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override; - GLint getAttribLocation(const std::string &name); - void updateScreenParams(); void updatePointSize(float size); void updateBuiltinUniforms(); diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index d0e721466..bf9218fce 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -124,6 +124,21 @@ size_t getIndexDataSize(IndexDataType type) } } +size_t getDataTypeSize(DataType datatype) +{ + switch (datatype) + { + case DATA_UNORM8: + return sizeof(uint8); + case DATA_UNORM16: + return sizeof(uint16); + case DATA_FLOAT: + return sizeof(float); + default: + return 0; + } +} + IndexDataType getIndexDataTypeFromMax(size_t maxvalue) { IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32}; @@ -234,6 +249,33 @@ static StringMap::Entry usageEntries[] = static StringMap usages(usageEntries, sizeof(usageEntries)); +static StringMap::Entry primitiveTypeEntries[] = +{ + { "fan", PRIMITIVE_TRIANGLE_FAN }, + { "strip", PRIMITIVE_TRIANGLE_STRIP }, + { "triangles", PRIMITIVE_TRIANGLES }, + { "points", PRIMITIVE_POINTS }, +}; + +static StringMap primitiveTypes(primitiveTypeEntries, sizeof(primitiveTypeEntries)); + +static StringMap::Entry attributeStepEntries[] = +{ + { "pervertex", STEP_PER_VERTEX }, + { "perinstance", STEP_PER_INSTANCE }, +}; + +static StringMap attributeSteps(attributeStepEntries, sizeof(attributeStepEntries)); + +static StringMap::Entry dataTypeEntries[] = +{ + { "byte", DATA_UNORM8 }, // Legacy / more user-friendly name... + { "unorm16", DATA_UNORM16 }, + { "float", DATA_FLOAT }, +}; + +static StringMap dataTypes(dataTypeEntries, sizeof(dataTypeEntries)); + bool getConstant(const char *in, VertexAttribID &out) { return attribNames.find(in, out); @@ -274,6 +316,36 @@ std::vector getConstants(Usage) return usages.getNames(); } +bool getConstant(const char *in, PrimitiveType &out) +{ + return primitiveTypes.find(in, out); +} + +bool getConstant(PrimitiveType in, const char *&out) +{ + return primitiveTypes.find(in, out); +} + +std::vector getConstants(PrimitiveType) +{ + return primitiveTypes.getNames(); +} + +bool getConstant(const char *in, AttributeStep &out) +{ + return attributeSteps.find(in, out); +} + +bool getConstant(AttributeStep in, const char *&out) +{ + return attributeSteps.find(in, out); +} + +std::vector getConstants(AttributeStep) +{ + return attributeSteps.getNames(); +} + } // vertex } // graphics } // love diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 3c7d2a991..613284f2c 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -67,6 +67,23 @@ enum IndexDataType INDEX_MAX_ENUM }; +// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png +enum PrimitiveType +{ + PRIMITIVE_TRIANGLES, + PRIMITIVE_TRIANGLE_STRIP, + PRIMITIVE_TRIANGLE_FAN, + PRIMITIVE_POINTS, + PRIMITIVE_MAX_ENUM +}; + +enum AttributeStep +{ + STEP_PER_VERTEX, + STEP_PER_INSTANCE, + STEP_MAX_ENUM +}; + namespace vertex { @@ -79,10 +96,12 @@ enum Usage USAGE_MAX_ENUM }; -enum class PrimitiveMode +enum DataType { - TRIANGLES, - POINTS, + DATA_UNORM8, + DATA_UNORM16, + DATA_FLOAT, + DATA_MAX_ENUM }; enum class TriangleIndexMode @@ -165,6 +184,7 @@ inline CommonFormat getSinglePositionFormat(bool is2D) } size_t getIndexDataSize(IndexDataType type); +size_t getDataTypeSize(DataType datatype); IndexDataType getIndexDataTypeFromMax(size_t maxvalue); @@ -184,6 +204,18 @@ bool getConstant(const char *in, Usage &out); bool getConstant(Usage in, const char *&out); std::vector getConstants(Usage); +bool getConstant(const char *in, PrimitiveType &out); +bool getConstant(PrimitiveType in, const char *&out); +std::vector getConstants(PrimitiveType); + +bool getConstant(const char *in, AttributeStep &out); +bool getConstant(AttributeStep in, const char *&out); +std::vector getConstants(AttributeStep); + +bool getConstant(const char *in, DataType &out); +bool getConstant(DataType in, const char *&out); +std::vector getConstants(DataType); + } // vertex typedef vertex::XYf_STf_RGBAub Vertex; diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index d4a51d237..184b2fcf9 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1408,12 +1408,12 @@ static vertex::Usage luax_optmeshusage(lua_State *L, int idx, vertex::Usage def) return def; } -static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode def) +static PrimitiveType luax_optmeshdrawmode(lua_State *L, int idx, PrimitiveType def) { const char *modestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx); - if (modestr && !Mesh::getConstant(modestr, def)) - luax_enumerror(L, "mesh draw mode", Mesh::getConstants(def), modestr); + if (modestr && !vertex::getConstant(modestr, def)) + luax_enumerror(L, "mesh draw mode", vertex::getConstants(def), modestr); return def; } @@ -1422,7 +1422,7 @@ static Mesh *newStandardMesh(lua_State *L) { Mesh *t = nullptr; - Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 2, Mesh::DRAWMODE_FAN); + PrimitiveType drawmode = luax_optmeshdrawmode(L, 2, PRIMITIVE_TRIANGLE_FAN); vertex::Usage usage = luax_optmeshusage(L, 3, vertex::USAGE_DYNAMIC); // First argument is a table of standard vertices, or the number of @@ -1482,7 +1482,7 @@ static Mesh *newCustomMesh(lua_State *L) // the number of vertices. std::vector vertexformat; - Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 3, Mesh::DRAWMODE_FAN); + PrimitiveType drawmode = luax_optmeshdrawmode(L, 3, PRIMITIVE_TRIANGLE_FAN); vertex::Usage usage = luax_optmeshusage(L, 4, vertex::USAGE_DYNAMIC); lua_rawgeti(L, 1, 1); @@ -1506,9 +1506,9 @@ static Mesh *newCustomMesh(lua_State *L) format.name = luaL_checkstring(L, -3); const char *tname = luaL_checkstring(L, -2); - if (!Mesh::getConstant(tname, format.type)) + if (!vertex::getConstant(tname, format.type)) { - luax_enumerror(L, "Mesh vertex data type name", Mesh::getConstants(format.type), tname); + luax_enumerror(L, "Mesh vertex data type name", vertex::getConstants(format.type), tname); return nullptr; } diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index e06644028..de32ddc77 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -37,7 +37,7 @@ Mesh *luax_checkmesh(lua_State *L, int idx) return luax_checktype(L, idx); } -static inline size_t writeByteData(lua_State *L, int startidx, int components, char *data) +static inline size_t writeUnorm8Data(lua_State *L, int startidx, int components, char *data) { uint8 *componentdata = (uint8 *) data; @@ -47,6 +47,16 @@ static inline size_t writeByteData(lua_State *L, int startidx, int components, c return sizeof(uint8) * components; } +static inline size_t writeUnorm16Data(lua_State *L, int startidx, int components, char *data) +{ + uint16 *componentdata = (uint16 *) data; + + for (int i = 0; i < components; i++) + componentdata[i] = (uint16) (luaL_optnumber(L, startidx + i, 1.0) * 65535.0); + + return sizeof(uint16) * components; +} + static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data) { float *componentdata = (float *) data; @@ -57,20 +67,22 @@ static inline size_t writeFloatData(lua_State *L, int startidx, int components, return sizeof(float) * components; } -char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data) +char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data) { switch (type) { - case Mesh::DATA_BYTE: - return data + writeByteData(L, startidx, components, data); - case Mesh::DATA_FLOAT: + case vertex::DATA_UNORM8: + return data + writeUnorm8Data(L, startidx, components, data); + case vertex::DATA_UNORM16: + return data + writeUnorm16Data(L, startidx, components, data); + case vertex::DATA_FLOAT: return data + writeFloatData(L, startidx, components, data); default: return data; } } -static inline size_t readByteData(lua_State *L, int components, const char *data) +static inline size_t readUnorm8Data(lua_State *L, int components, const char *data) { const uint8 *componentdata = (const uint8 *) data; @@ -80,6 +92,16 @@ static inline size_t readByteData(lua_State *L, int components, const char *data return sizeof(uint8) * components; } +static inline size_t readUnorm16Data(lua_State *L, int components, const char *data) +{ + const uint16 *componentdata = (const uint16 *) data; + + for (int i = 0; i < components; i++) + lua_pushnumber(L, (lua_Number) componentdata[i] / 65535.0); + + return sizeof(uint16) * components; +} + static inline size_t readFloatData(lua_State *L, int components, const char *data) { const float *componentdata = (const float *) data; @@ -90,13 +112,15 @@ static inline size_t readFloatData(lua_State *L, int components, const char *dat return sizeof(float) * components; } -const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data) +const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data) { switch (type) { - case Mesh::DATA_BYTE: - return data + readByteData(L, components, data); - case Mesh::DATA_FLOAT: + case vertex::DATA_UNORM8: + return data + readUnorm8Data(L, components, data); + case vertex::DATA_UNORM16: + return data + readUnorm16Data(L, components, data); + case vertex::DATA_FLOAT: return data + readFloatData(L, components, data); default: return data; @@ -239,7 +263,7 @@ int w_Mesh_setVertexAttribute(lua_State *L) size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1; int attribindex = (int) luaL_checkinteger(L, 3) - 1; - Mesh::DataType type; + vertex::DataType type; int components; luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); }); @@ -259,7 +283,7 @@ int w_Mesh_getVertexAttribute(lua_State *L) size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1; int attribindex = (int) luaL_checkinteger(L, 3) - 1; - Mesh::DataType type; + vertex::DataType type; int components; luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); }); @@ -290,8 +314,8 @@ int w_Mesh_getVertexFormat(lua_State *L) for (size_t i = 0; i < vertexformat.size(); i++) { - if (!Mesh::getConstant(vertexformat[i].type, tname)) - return luax_enumerror(L, "vertex attribute data type", Mesh::getConstants(vertexformat[i].type), tname); + if (!vertex::getConstant(vertexformat[i].type, tname)) + return luax_enumerror(L, "vertex attribute data type", vertex::getConstants(vertexformat[i].type), tname); lua_createtable(L, 3, 0); @@ -336,10 +360,10 @@ int w_Mesh_attachAttribute(lua_State *L) const char *name = luaL_checkstring(L, 2); Mesh *mesh = luax_checkmesh(L, 3); - Mesh::AttributeStep step = Mesh::STEP_PER_VERTEX; + AttributeStep step = STEP_PER_VERTEX; const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4); - if (stepstr != nullptr && !Mesh::getConstant(stepstr, step)) - return luax_enumerror(L, "vertex attribute step", Mesh::getConstants(step), stepstr); + if (stepstr != nullptr && !vertex::getConstant(stepstr, step)) + return luax_enumerror(L, "vertex attribute step", vertex::getConstants(step), stepstr); const char *attachname = luaL_optstring(L, 5, name); @@ -485,10 +509,10 @@ int w_Mesh_setDrawMode(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); const char *str = luaL_checkstring(L, 2); - Mesh::DrawMode mode; + PrimitiveType mode; - if (!Mesh::getConstant(str, mode)) - return luax_enumerror(L, "mesh draw mode", Mesh::getConstants(mode), str); + if (!vertex::getConstant(str, mode)) + return luax_enumerror(L, "mesh draw mode", vertex::getConstants(mode), str); t->setDrawMode(mode); return 0; @@ -497,10 +521,10 @@ int w_Mesh_setDrawMode(lua_State *L) int w_Mesh_getDrawMode(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); - Mesh::DrawMode mode = t->getDrawMode(); + PrimitiveType mode = t->getDrawMode(); const char *str; - if (!Mesh::getConstant(mode, str)) + if (!vertex::getConstant(mode, str)) return luaL_error(L, "Unknown mesh draw mode."); lua_pushstring(L, str); diff --git a/src/modules/graphics/wrap_Mesh.h b/src/modules/graphics/wrap_Mesh.h index 805defa3b..6d6801c33 100644 --- a/src/modules/graphics/wrap_Mesh.h +++ b/src/modules/graphics/wrap_Mesh.h @@ -30,8 +30,8 @@ namespace love namespace graphics { -char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data); -const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data); +char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data); +const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data); Mesh *luax_checkmesh(lua_State *L, int idx); extern "C" int luaopen_mesh(lua_State *L);