diff --git a/jni/love/src/modules/graphics/Graphics.cpp b/jni/love/src/modules/graphics/Graphics.cpp index c805cc17..86886c76 100644 --- a/jni/love/src/modules/graphics/Graphics.cpp +++ b/jni/love/src/modules/graphics/Graphics.cpp @@ -165,6 +165,7 @@ StringMap::Entry Graphics::suppor { "mipmap", Graphics::SUPPORT_MIPMAP }, { "dxt", Graphics::SUPPORT_DXT }, { "bc5", Graphics::SUPPORT_BC5 }, + { "instancing", Graphics::SUPPORT_INSTANCING }, }; StringMap Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); diff --git a/jni/love/src/modules/graphics/Graphics.h b/jni/love/src/modules/graphics/Graphics.h index ed724135..d41d24cb 100644 --- a/jni/love/src/modules/graphics/Graphics.h +++ b/jni/love/src/modules/graphics/Graphics.h @@ -94,6 +94,7 @@ public: SUPPORT_MIPMAP, SUPPORT_DXT, SUPPORT_BC5, + SUPPORT_INSTANCING, SUPPORT_MAX_ENUM }; diff --git a/jni/love/src/modules/graphics/opengl/Font.cpp b/jni/love/src/modules/graphics/opengl/Font.cpp index 5b63fcc2..d7ce211d 100644 --- a/jni/love/src/modules/graphics/opengl/Font.cpp +++ b/jni/love/src/modules/graphics/opengl/Font.cpp @@ -154,7 +154,7 @@ void Font::createTexture() { // Clean up before throwing. gl.deleteTexture(t); - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); textures.pop_back(); throw love::Exception("Could not create font texture!"); diff --git a/jni/love/src/modules/graphics/opengl/Graphics.cpp b/jni/love/src/modules/graphics/opengl/Graphics.cpp index 94df82e7..8a31fc2e 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/Graphics.cpp @@ -508,6 +508,11 @@ Mesh *Graphics::newMesh(const std::vector &vertices, Mesh::DrawMode mode return new Mesh(vertices, mode); } +Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode mode) +{ + return new Mesh(vertexcount, mode); +} + void Graphics::setColor(const Color &c) { gl.setColor(c); @@ -856,7 +861,7 @@ void Graphics::point(float x, float y) { gl.prepareDraw(); - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); GLfloat coord[] = {x, y}; @@ -957,7 +962,7 @@ void Graphics::arc(DrawMode mode, float x, float y, float radius, float angle1, { gl.prepareDraw(); - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); gl.enableVertexAttribArray(OpenGL::ATTRIB_POS); gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, (GLvoid *) coords); @@ -985,7 +990,7 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) { gl.prepareDraw(); - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); gl.enableVertexAttribArray(OpenGL::ATTRIB_POS); gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, (GLvoid *) coords); diff --git a/jni/love/src/modules/graphics/opengl/Graphics.h b/jni/love/src/modules/graphics/opengl/Graphics.h index 24be1d07..1ef59246 100644 --- a/jni/love/src/modules/graphics/opengl/Graphics.h +++ b/jni/love/src/modules/graphics/opengl/Graphics.h @@ -213,6 +213,7 @@ public: Shader *newShader(const Shader::ShaderSources &sources); Mesh *newMesh(const std::vector &vertices, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); + Mesh *newMesh(int vertexcount, Mesh::DrawMode mode = Mesh::DRAW_MODE_FAN); /** * Sets the foreground color. diff --git a/jni/love/src/modules/graphics/opengl/Mesh.cpp b/jni/love/src/modules/graphics/opengl/Mesh.cpp index b158956e..1c43a114 100644 --- a/jni/love/src/modules/graphics/opengl/Mesh.cpp +++ b/jni/love/src/modules/graphics/opengl/Mesh.cpp @@ -23,6 +23,9 @@ #include "common/Matrix.h" #include "common/Exception.h" +// C++ +#include + namespace love { namespace graphics @@ -35,7 +38,10 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) , vertex_count(0) , ibo(nullptr) , element_count(0) + , instance_count(1) , draw_mode(mode) + , range_min(-1) + , range_max(-1) , texture(nullptr) , colors_enabled(false) , wireframe(false) @@ -43,6 +49,35 @@ Mesh::Mesh(const std::vector &verts, Mesh::DrawMode mode) setVertices(verts); } +Mesh::Mesh(int vertexcount, Mesh::DrawMode mode) + : vbo(nullptr) + , vertex_count(0) + , ibo(nullptr) + , element_count(0) + , draw_mode(mode) + , range_min(-1) + , range_max(-1) + , texture(nullptr) + , colors_enabled(false) + , wireframe(false) +{ + if (vertexcount < 1) + throw love::Exception("Invalid number of vertices."); + + std::vector verts(vertexcount); + + // Default-initialized vertices should have a white opaque color. + for (size_t i = 0; i < verts.size(); i++) + { + verts[i].r = 255; + verts[i].g = 255; + verts[i].b = 255; + verts[i].a = 255; + } + + setVertices(verts); +} + Mesh::~Mesh() { delete vbo; @@ -51,8 +86,8 @@ Mesh::~Mesh() void Mesh::setVertices(const std::vector &verts) { - if (verts.size() < 3) - throw love::Exception("At least 3 vertices are required."); + if (verts.size() == 0) + throw love::Exception("At least one vertex is required."); size_t size = sizeof(Vertex) * verts.size(); @@ -162,7 +197,7 @@ const uint32 *Mesh::getVertexMap() const return (uint32 *) ibo->map(); } - return 0; + return nullptr; } size_t Mesh::getVertexMapCount() const @@ -170,6 +205,16 @@ size_t Mesh::getVertexMapCount() const return element_count; } +void Mesh::setInstanceCount(int count) +{ + instance_count = std::max(count, 1); +} + +int Mesh::getInstanceCount() const +{ + return instance_count; +} + void Mesh::setTexture(Texture *tex) { tex->retain(); @@ -203,6 +248,26 @@ Mesh::DrawMode Mesh::getDrawMode() const return draw_mode; } +void Mesh::setDrawRange(int min, int max) +{ + if (min < 0 || max < 0 || min > max) + throw love::Exception("Invalid draw range."); + + range_min = min; + range_max = max; +} + +void Mesh::setDrawRange() +{ + range_min = range_max = -1; +} + +void Mesh::getDrawRange(int &min, int &max) const +{ + min = range_min; + max = range_max; +} + void Mesh::setVertexColors(bool enable) { colors_enabled = enable; @@ -235,7 +300,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo if (texture) texture->predraw(); else - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); Matrix m; m.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); @@ -270,18 +335,43 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo if (ibo && element_count > 0) { + // Use the custom vertex map (index buffer) to draw the vertices. VertexBuffer::Bind ibo_bind(*ibo); // Make sure the index buffer isn't mapped (sends data to GPU if needed.) ibo->unmap(); - // Use the custom vertex map to draw the vertices. - glDrawElements(mode, element_count, GL_UNSIGNED_INT, ibo->getPointer(0)); + int max = element_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) element_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + + const void *indices = ibo->getPointer(min * sizeof(uint32)); + GLenum type = GL_UNSIGNED_INT; + + if (instance_count > 1) + gl.drawElementsInstanced(mode, max - min + 1, type, indices, instance_count); + else + glDrawElements(mode, max - min + 1, type, indices); } else { + int max = vertex_count - 1; + if (range_max >= 0) + max = std::min(std::max(range_max, 0), (int) vertex_count - 1); + + int min = 0; + if (range_min >= 0) + min = std::min(std::max(range_min, 0), max); + // Normal non-indexed drawing (no custom vertex map.) - glDrawArrays(mode, 0, vertex_count); + if (instance_count > 1) + gl.drawArraysInstanced(mode, min, max - min + 1, instance_count); + else + glDrawArrays(mode, min, max - min + 1); } gl.disableVertexAttribArray(OpenGL::ATTRIB_POS); diff --git a/jni/love/src/modules/graphics/opengl/Mesh.h b/jni/love/src/modules/graphics/opengl/Mesh.h index 498e501e..7719c1c5 100644 --- a/jni/love/src/modules/graphics/opengl/Mesh.h +++ b/jni/love/src/modules/graphics/opengl/Mesh.h @@ -22,6 +22,7 @@ #define LOVE_GRAPHICS_OPENGL_MESH_H // LOVE +#include "common/config.h" #include "common/int.h" #include "common/math.h" #include "common/StringMap.h" @@ -64,6 +65,16 @@ public: * @param mode The draw mode to use when drawing the Mesh. **/ Mesh(const std::vector &verts, DrawMode mode = DRAW_MODE_FAN); + + /** + * Constructor. + * Creates a Mesh with a certain number of default-initialized (hidden) + * vertices. + * @param vertexcount The number of vertices to use in the Mesh. + * @param mode The draw mode to use when drawing the Mesh. + **/ + Mesh(int vertexcount, DrawMode mode = DRAW_MODE_FAN); + virtual ~Mesh(); /** @@ -109,6 +120,15 @@ public: **/ size_t getVertexMapCount() const; + /** + * Sets the number of instances of this Mesh to draw (uses hardware + * instancing when possible.) + * A custom vertex shader is necessary in order to introduce differences + * in each instance. + **/ + void setInstanceCount(int count); + int getInstanceCount() const; + /** * Sets the texture used when drawing the Mesh. **/ @@ -131,6 +151,10 @@ public: void setDrawMode(DrawMode mode); DrawMode getDrawMode() const; + void setDrawRange(int min, int max); + void setDrawRange(); + void getDrawRange(int &min, int &max) const; + /** * Sets whether per-vertex colors are enabled. If this is disabled, the * global color (love.graphics.setColor) will be used for the entire Mesh. @@ -165,8 +189,13 @@ private: VertexBuffer *ibo; size_t element_count; + int instance_count; + DrawMode draw_mode; + int range_min; + int range_max; + Texture *texture; // Whether the per-vertex colors are used when drawing. diff --git a/jni/love/src/modules/graphics/opengl/OpenGL.cpp b/jni/love/src/modules/graphics/opengl/OpenGL.cpp index 02d1a4e6..aa0e6cc6 100644 --- a/jni/love/src/modules/graphics/opengl/OpenGL.cpp +++ b/jni/love/src/modules/graphics/opengl/OpenGL.cpp @@ -129,6 +129,8 @@ bool OpenGL::initContext() initMaxValues(); createDefaultTexture(); + state.lastPseudoInstanceID = -1; + contextInitialized = true; return true; } @@ -138,6 +140,9 @@ void OpenGL::deInitContext() if (!contextInitialized) return; + glDeleteTextures(1, &state.defaultTexture); + state.defaultTexture = 0; + contextInitialized = false; } @@ -213,13 +218,15 @@ void OpenGL::initMatrices() void OpenGL::createDefaultTexture() { - // Set the 'default' texture (id 0) as a repeating white pixel. Otherwise, + // Set the 'default' texture as a repeating white pixel. Otherwise, // texture2D calls inside a shader would return black when drawing graphics // primitives, which would create the need to use different "passthrough" // shaders for untextured primitives vs images. GLuint curtexture = state.textureUnits[state.curTextureUnit]; - bindTexture(0); + + glGenTextures(1, &state.defaultTexture); + bindTexture(state.defaultTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -240,16 +247,26 @@ void OpenGL::prepareDraw() Shader *shader = Shader::current; - // Make sure the active shader has the correct values for the built-in - // screen params uniform. + // Make sure the active shader has the correct values for its love-provided + // uniforms. if (shader) + { shader->checkSetScreenParams(); + // Make sure the Instance ID variable is up-to-date when + // pseudo-instancing is used. + if (state.lastPseudoInstanceID != 0 && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID)) + { + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, 0.0f); + state.lastPseudoInstanceID = 0; + } + } + if (GLAD_ES_VERSION_2_0 && shader) { // Send built-in uniforms to the current shader. shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, transform.getElements(), 1); - shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_MATRIX, 4, proj.getElements(), 1); + shader->sendBuiltinMatrix(Shader::BUILTIN_PROJECTION_MATRIX, 4, proj.getElements(), 1); Matrix tp_matrix(proj * transform); shader->sendBuiltinMatrix(Shader::BUILTIN_TRANSFORM_PROJECTION_MATRIX, 4, tp_matrix.getElements(), 1); @@ -265,6 +282,58 @@ void OpenGL::prepareDraw() } } +void OpenGL::drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount) +{ + Shader *shader = Shader::current; + + if (GLAD_ARB_draw_instanced) + glDrawArraysInstancedARB(mode, first, count, primcount); + else if (GLAD_EXT_draw_instanced && GLAD_ES_VERSION_2_0) + glDrawArraysInstancedEXT(mode, first, count, primcount); + else + { + bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID); + + // Pseudo-instancing fallback. + for (int i = 0; i < primcount; i++) + { + if (shaderHasID) + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i); + + glDrawArrays(mode, first, count); + } + + if (shaderHasID) + state.lastPseudoInstanceID = primcount - 1; + } +} + +void OpenGL::drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount) +{ + Shader *shader = Shader::current; + + if (GLAD_ARB_draw_instanced) + glDrawElementsInstancedARB(mode, count, type, indices, primcount); + else if (GLAD_EXT_draw_instanced && GLAD_ES_VERSION_2_0) + glDrawElementsInstancedEXT(mode, count, type, indices, primcount); + else + { + bool shaderHasID = shader && shader->hasVertexAttrib(ATTRIB_PSEUDO_INSTANCE_ID); + + // Pseudo-instancing fallback. + for (int i = 0; i < primcount; i++) + { + if (shaderHasID) + glVertexAttrib1f((GLuint) ATTRIB_PSEUDO_INSTANCE_ID, (GLfloat) i); + + glDrawElements(mode, count, type, indices); + } + + if (shaderHasID) + state.lastPseudoInstanceID = primcount - 1; + } +} + void OpenGL::setColor(const Color &c) { if (GLAD_ES_VERSION_2_0) @@ -415,6 +484,11 @@ GLuint OpenGL::getDefaultFBO() const return state.defaultFBO; } +GLuint OpenGL::getDefaultTexture() const +{ + return state.defaultTexture; +} + void OpenGL::setTextureUnit(int textureunit) { if (textureunit < 0 || (size_t) textureunit >= state.textureUnits.size()) diff --git a/jni/love/src/modules/graphics/opengl/OpenGL.h b/jni/love/src/modules/graphics/opengl/OpenGL.h index 5f3213c2..26684d64 100644 --- a/jni/love/src/modules/graphics/opengl/OpenGL.h +++ b/jni/love/src/modules/graphics/opengl/OpenGL.h @@ -71,13 +71,15 @@ public: VENDOR_UNKNOWN }; - // Vertex attributes. The values map to OpenGL generic vertex attribute - // indices, when applicable (GLES2.) + // Vertex attributes used in shaders by LOVE. The values map to OpenGL + // generic vertex attribute indices, when applicable. + // LOVE uses the old hard-coded attribute APIs on desktop GL (for now.) enum VertexAttrib { ATTRIB_POS = 0, ATTRIB_TEXCOORD = 1, ATTRIB_COLOR = 2, + ATTRIB_PSEUDO_INSTANCE_ID = 3, // Shader pseudo-instance ID. ATTRIB_MAX_ENUM }; @@ -125,6 +127,16 @@ public: **/ void prepareDraw(); + /** + * glDrawArraysInstanced with a pseudo-instancing fallback. + **/ + void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount); + + /** + * glDrawElementsInstanced with a pseudo-instancing fallback. + **/ + void drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount); + /** * Sets the current constant color. **/ @@ -201,6 +213,11 @@ public: **/ GLuint getDefaultFBO() const; + /** + * Gets the ID for love's default texture (used for "untextured" draws.) + **/ + GLuint getDefaultTexture() const; + /** * Helper for setting the active texture unit. * @@ -295,8 +312,13 @@ private: float pointSize; + GLuint defaultTexture; + GLuint defaultFBO; + // The last ID value used for pseudo-instancing. + int lastPseudoInstanceID; + } state; }; // OpenGL diff --git a/jni/love/src/modules/graphics/opengl/Polyline.cpp b/jni/love/src/modules/graphics/opengl/Polyline.cpp index 5922b896..59718530 100644 --- a/jni/love/src/modules/graphics/opengl/Polyline.cpp +++ b/jni/love/src/modules/graphics/opengl/Polyline.cpp @@ -330,7 +330,7 @@ void Polyline::draw() gl.prepareDraw(); // draw the core line - gl.bindTexture(0); + gl.bindTexture(gl.getDefaultTexture()); gl.enableVertexAttribArray(OpenGL::ATTRIB_POS); gl.setVertexAttribArray(OpenGL::ATTRIB_POS, 2, GL_FLOAT, 0, (GLvoid *) vertices); glDrawArrays(draw_mode, 0, vertex_count); diff --git a/jni/love/src/modules/graphics/opengl/Shader.cpp b/jni/love/src/modules/graphics/opengl/Shader.cpp index 5bbbb7d8..7917701a 100644 --- a/jni/love/src/modules/graphics/opengl/Shader.cpp +++ b/jni/love/src/modules/graphics/opengl/Shader.cpp @@ -73,6 +73,7 @@ Shader::Shader(const ShaderSources &sources) : shaderSources(sources) , program(0) , builtinUniforms() + , vertexAttributes() , lastCanvas((Canvas *) -1) { if (shaderSources.empty()) @@ -184,17 +185,16 @@ void Shader::createProgram(const std::vector &shaderids) for (it = shaderids.begin(); it != shaderids.end(); ++it) glAttachShader(program, *it); - // We use generic vertex attributes in OpenGL ES 2, so we have to bind the - // attribute indices to names in the shader. - if (GLAD_ES_VERSION_2_0) + // Bind generic vertex attribute indices to names in the shader. + for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) { - const char *name = nullptr; - for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) - { - if (attribNames.find(OpenGL::VertexAttrib(i), name)) - glBindAttribLocation(program, i, (const GLchar *) name); - } + // Desktop OpenGL should ignore some of these. + if (!GLAD_ES_VERSION_2_0 && i <= int(OpenGL::ATTRIB_COLOR)) + continue; + const char *name = nullptr; + if (attribNames.find((OpenGL::VertexAttrib) i, name)) + glBindAttribLocation(program, i, (const GLchar *) name); } glLinkProgram(program); @@ -268,10 +268,6 @@ bool Shader::loadVolatile() activeTexUnits.clear(); activeTexUnits.insert(activeTexUnits.begin(), maxTexUnits, 0); - // Built-in uniform locations default to -1 (nonexistant.) - for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++) - builtinUniforms[i] = -1; - // Built-in uniform locations default to -1 (nonexistant.) for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++) builtinUniforms[i] = -1; @@ -307,6 +303,15 @@ bool Shader::loadVolatile() // Retrieve all active uniform variables in this shader from OpenGL. mapActiveUniforms(); + for (int i = 0; i < int(OpenGL::ATTRIB_MAX_ENUM); i++) + { + const char *name = nullptr; + if (attribNames.find(OpenGL::VertexAttrib(i), name)) + vertexAttributes[i] = glGetAttribLocation(program, name); + else + vertexAttributes[i] = -1; + } + if (current == this) { // make sure glUseProgram gets called. @@ -679,6 +684,11 @@ int Shader::getTextureUnit(const std::string &name) return texunit; } +bool Shader::hasVertexAttrib(OpenGL::VertexAttrib attrib) const +{ + return vertexAttributes[int(attrib)] != -1; +} + bool Shader::hasBuiltinExtern(BuiltinExtern builtin) const { return builtinUniforms[int(builtin)] != -1; @@ -808,6 +818,7 @@ StringMap::Entry Shader::attribNa {"VertexPosition", OpenGL::ATTRIB_POS}, {"VertexTexCoord", OpenGL::ATTRIB_TEXCOORD}, {"VertexColor", OpenGL::ATTRIB_COLOR}, + {"love_PseudoInstanceID", OpenGL::ATTRIB_PSEUDO_INSTANCE_ID}, }; StringMap Shader::attribNames(Shader::attribNameEntries, sizeof(Shader::attribNameEntries)); diff --git a/jni/love/src/modules/graphics/opengl/Shader.h b/jni/love/src/modules/graphics/opengl/Shader.h index fce5b38f..9c9a80f1 100644 --- a/jni/love/src/modules/graphics/opengl/Shader.h +++ b/jni/love/src/modules/graphics/opengl/Shader.h @@ -146,6 +146,7 @@ public: /** * Internal use only. **/ + bool hasVertexAttrib(OpenGL::VertexAttrib attrib) const; bool hasBuiltinExtern(BuiltinExtern builtin) const; bool sendBuiltinMatrix(BuiltinExtern builtin, int size, const GLfloat *m, int count); bool sendBuiltinFloat(BuiltinExtern builtin, int size, const GLfloat *m, int count); @@ -211,6 +212,9 @@ private: // Location values for any built-in uniform variables. GLint builtinUniforms[BUILTIN_MAX_ENUM]; + // Location values for any generic vertex attribute variables. + GLint vertexAttributes[OpenGL::ATTRIB_MAX_ENUM]; + // Uniform location buffer map std::map uniforms; @@ -234,11 +238,11 @@ private: static StringMap::Entry typeNameEntries[]; static StringMap typeNames; - // Names for the generic vertex attributes used in OpenGL ES 2. + // Names for the generic vertex attributes used by love. static StringMap::Entry attribNameEntries[]; static StringMap attribNames; - // Names for the LOVE-defined built-in uniform variables. + // Names for the built-in uniform variables. static StringMap::Entry builtinNameEntries[]; static StringMap builtinNames; diff --git a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp index 7effaae3..8db87269 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -440,8 +440,10 @@ int w_newShader(lua_State *L) int w_newMesh(lua_State *L) { - // Check first argument: mandatory table of vertices. - luaL_checktype(L, 1, LUA_TTABLE); + // Check first argument: table of vertices or number of vertices. + int ttype = lua_type(L, 1); + if (ttype != LUA_TTABLE && ttype != LUA_TNUMBER) + luaL_argerror(L, 1, "table or number expected"); // Second argument: optional texture. Texture *tex = nullptr; @@ -456,52 +458,60 @@ int w_newMesh(lua_State *L) if (str && !Mesh::getConstant(str, mode)) return luaL_error(L, "Invalid mesh draw mode: %s", str); - size_t vertex_count = lua_objlen(L, 1); - std::vector vertices; - vertices.reserve(vertex_count); - - bool use_colors = false; - - // Get the vertices from the table. - for (size_t i = 1; i <= vertex_count; i++) - { - lua_rawgeti(L, 1, i); - - if (lua_type(L, -1) != LUA_TTABLE) - return luax_typerror(L, 1, "table of tables"); - - for (int j = 1; j <= 8; j++) - lua_rawgeti(L, -j, j); - - Vertex v; - - v.x = (float) luaL_checknumber(L, -8); - v.y = (float) luaL_checknumber(L, -7); - - v.s = (float) luaL_checknumber(L, -6); - v.t = (float) luaL_checknumber(L, -5); - - v.r = (unsigned char) luaL_optinteger(L, -4, 255); - v.g = (unsigned char) luaL_optinteger(L, -3, 255); - v.b = (unsigned char) luaL_optinteger(L, -2, 255); - v.a = (unsigned char) luaL_optinteger(L, -1, 255); - - // Enable per-vertex coloring if any color is not the default. - if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) - use_colors = true; - - lua_pop(L, 9); - vertices.push_back(v); - } - Mesh *t = nullptr; - EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + + if (ttype == LUA_TTABLE) + { + size_t vertex_count = lua_objlen(L, 1); + std::vector vertices; + vertices.reserve(vertex_count); + + bool use_colors = false; + + // Get the vertices from the table. + for (size_t i = 1; i <= vertex_count; i++) + { + lua_rawgeti(L, 1, i); + + if (lua_type(L, -1) != LUA_TTABLE) + return luax_typerror(L, 1, "table of tables"); + + for (int j = 1; j <= 8; j++) + lua_rawgeti(L, -j, j); + + Vertex v; + + v.x = (float) luaL_checknumber(L, -8); + v.y = (float) luaL_checknumber(L, -7); + + v.s = (float) luaL_checknumber(L, -6); + v.t = (float) luaL_checknumber(L, -5); + + v.r = (unsigned char) luaL_optinteger(L, -4, 255); + v.g = (unsigned char) luaL_optinteger(L, -3, 255); + v.b = (unsigned char) luaL_optinteger(L, -2, 255); + v.a = (unsigned char) luaL_optinteger(L, -1, 255); + + // Enable per-vertex coloring if any color is not the default. + if (!use_colors && (v.r != 255 || v.g != 255 || v.b != 255 || v.a != 255)) + use_colors = true; + + lua_pop(L, 9); + vertices.push_back(v); + } + + EXCEPT_GUARD(t = instance->newMesh(vertices, mode);) + t->setVertexColors(use_colors); + } + else + { + int count = luaL_checkint(L, 1); + EXCEPT_GUARD(t = instance->newMesh(count, mode);) + } if (tex) t->setTexture(tex); - t->setVertexColors(use_colors); - luax_pushtype(L, "Mesh", GRAPHICS_MESH_T, t); return 1; } @@ -1014,6 +1024,10 @@ int w_isSupported(lua_State *L) if (!Image::hasCompressedTextureSupport(image::CompressedData::FORMAT_BC5)) supported = false; break; + case Graphics::SUPPORT_INSTANCING: + if (!GLAD_ARB_draw_instanced) + supported = false; + break; default: supported = false; } diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp index 1ea57e75..4548030a 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.cpp @@ -236,6 +236,20 @@ int w_Mesh_getVertexMap(lua_State *L) return 1; } +int w_Mesh_setInstanceCount(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + t->setInstanceCount(luaL_checkint(L, 2)); + return 0; +} + +int w_Mesh_getInstanceCount(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + lua_pushinteger(L, t->getInstanceCount()); + return 1; +} + int w_Mesh_setTexture(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -301,6 +315,38 @@ int w_Mesh_getDrawMode(lua_State *L) return 1; } +int w_Mesh_setDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + if (lua_isnoneornil(L, 2)) + t->setDrawRange(); + else + { + int rangemin = luaL_checkint(L, 2) - 1; + int rangemax = luaL_checkint(L, 3) - 1; + EXCEPT_GUARD(t->setDrawRange(rangemin, rangemax);) + } + + return 0; +} + +int w_Mesh_getDrawRange(lua_State *L) +{ + Mesh *t = luax_checkmesh(L, 1); + + int rangemin = -1; + int rangemax = -1; + t->getDrawRange(rangemin, rangemax); + + if (rangemin < 0 || rangemax < 0) + return 0; + + lua_pushinteger(L, rangemin + 1); + lua_pushinteger(L, rangemax + 1); + return 2; +} + int w_Mesh_setVertexColors(lua_State *L) { Mesh *t = luax_checkmesh(L, 1); @@ -338,10 +384,14 @@ static const luaL_Reg functions[] = { "getVertexCount", w_Mesh_getVertexCount }, { "setVertexMap", w_Mesh_setVertexMap }, { "getVertexMap", w_Mesh_getVertexMap }, + { "setInstanceCount", w_Mesh_setInstanceCount }, + { "getInstanceCount", w_Mesh_getInstanceCount }, { "setTexture", w_Mesh_setTexture }, { "getTexture", w_Mesh_getTexture }, { "setDrawMode", w_Mesh_setDrawMode }, { "getDrawMode", w_Mesh_getDrawMode }, + { "setDrawRange", w_Mesh_setDrawRange }, + { "getDrawRange", w_Mesh_getDrawRange }, { "setVertexColors", w_Mesh_setVertexColors }, { "hasVertexColors", w_Mesh_hasVertexColors }, { "setWireframe", w_Mesh_setWireframe }, diff --git a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h index efae413d..9b4cdc77 100644 --- a/jni/love/src/modules/graphics/opengl/wrap_Mesh.h +++ b/jni/love/src/modules/graphics/opengl/wrap_Mesh.h @@ -41,10 +41,14 @@ int w_Mesh_getVertices(lua_State *L); int w_Mesh_getVertexCount(lua_State *L); int w_Mesh_setVertexMap(lua_State *L); int w_Mesh_getVertexMap(lua_State *L); +int w_Mesh_setInstanceCount(lua_State *L); +int w_Mesh_getInstanceCount(lua_State *L); int w_Mesh_setTexture(lua_State *L); int w_Mesh_getTexture(lua_State *L); int w_Mesh_setDrawMode(lua_State *L); int w_Mesh_getDrawMode(lua_State *L); +int w_Mesh_setDrawRange(lua_State *L); +int w_Mesh_getDrawRange(lua_State *L); int w_Mesh_setVertexColors(lua_State *L); int w_Mesh_hasVertexColors(lua_State *L); int w_Mesh_setWireframe(lua_State *L); diff --git a/jni/love/src/scripts/boot.lua.h b/jni/love/src/scripts/boot.lua.h index 0f2a4b80..2a8bf28f 100644 --- a/jni/love/src/scripts/boot.lua.h +++ b/jni/love/src/scripts/boot.lua.h @@ -319,6 +319,27 @@ const unsigned char boot_lua[] = 0x76, 0x65, 0x2e, 0x74, 0x6f, 0x75, 0x63, 0x68, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x28, 0x69, 0x64, 0x2c, 0x78, 0x2c, 0x79, 0x2c, 0x70, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, + 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, + 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, + 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, + 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, + 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, + 0x09, 0x09, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d, + 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, + 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a, 0x09, 0x09, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, diff --git a/jni/love/src/scripts/graphics.lua b/jni/love/src/scripts/graphics.lua index b4ebe9ee..faafd805 100644 --- a/jni/love/src/scripts/graphics.lua +++ b/jni/love/src/scripts/graphics.lua @@ -1330,7 +1330,15 @@ uniform vec2 love_ScreenParams;]] #define VertexColor gl_Color #define VaryingTexCoord gl_TexCoord[0] -#define VaryingColor gl_FrontColor]], +#define VaryingColor gl_FrontColor + +#if defined(GL_ARB_draw_instanced) + #extension GL_ARB_draw_instanced : enable + #define love_InstanceID gl_InstanceIDARB +#else + attribute float love_PseudoInstanceID; + int love_InstanceID = int(love_PseudoInstanceID); +#endif]], FOOTER = [[ void main() { @@ -1349,7 +1357,16 @@ attribute vec4 VertexTexCoord; attribute vec4 VertexColor; varying vec4 VaryingTexCoord; -varying lowp vec4 VaryingColor;]], +varying lowp vec4 VaryingColor; + +#if defined(GL_EXT_draw_instanced) + #extension GL_EXT_draw_instanced : enable + #define love_InstanceID gl_InstanceIDEXT +#else + attribute float love_PseudoInstanceID; + int love_InstanceID = int(love_PseudoInstanceID); +#endif +]], FOOTER = [[ void main() { diff --git a/jni/love/src/scripts/graphics.lua.h b/jni/love/src/scripts/graphics.lua.h index 0414ab0e..f3f6b445 100644 --- a/jni/love/src/scripts/graphics.lua.h +++ b/jni/love/src/scripts/graphics.lua.h @@ -6332,8 +6332,23 @@ const unsigned char graphics_lua[] = 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x67, 0x6c, 0x5f, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x5b, 0x30, 0x5d, 0x0a, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, - 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x5d, 0x5d, - 0x2c, 0x0a, + 0x6f, 0x72, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x6f, 0x6e, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x0a, + 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a, + 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x3a, 0x20, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x41, 0x52, 0x42, 0x0a, + 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6c, + 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x3b, 0x0a, + 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, + 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a, + 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x5d, 0x5d, 0x2c, 0x0a, 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d, @@ -6359,7 +6374,24 @@ const unsigned char graphics_lua[] = 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x3b, 0x0a, 0x76, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x6c, 0x6f, 0x77, 0x70, 0x20, 0x76, 0x65, 0x63, 0x34, 0x20, - 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x5d, 0x5d, 0x2c, 0x0a, + 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x3b, 0x0a, + 0x23, 0x69, 0x66, 0x20, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x28, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x29, 0x0a, + 0x09, 0x23, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x47, 0x4c, 0x5f, 0x45, 0x58, 0x54, + 0x5f, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x64, 0x20, 0x3a, 0x20, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x0a, + 0x09, 0x23, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x20, 0x67, 0x6c, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x45, 0x58, 0x54, 0x0a, + 0x23, 0x65, 0x6c, 0x73, 0x65, 0x0a, + 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x20, 0x6c, + 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x3b, 0x0a, + 0x09, 0x69, 0x6e, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x44, 0x20, 0x3d, 0x20, 0x69, 0x6e, 0x74, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x5f, 0x50, 0x73, 0x65, 0x75, + 0x64, 0x6f, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, 0x29, 0x3b, 0x0a, + 0x23, 0x65, 0x6e, 0x64, 0x69, 0x66, 0x0a, + 0x5d, 0x5d, 0x2c, 0x0a, 0x09, 0x09, 0x46, 0x4f, 0x4f, 0x54, 0x45, 0x52, 0x20, 0x3d, 0x20, 0x5b, 0x5b, 0x0a, 0x76, 0x6f, 0x69, 0x64, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x28, 0x29, 0x20, 0x7b, 0x0a, 0x09, 0x56, 0x61, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x78, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x20, 0x3d,