From 66b299822a2d1b0a06080f2dbc7ba91ec5f2768e Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 26 Feb 2017 17:11:22 -0400 Subject: [PATCH] Array textures can be easily drawn without a shader (resolves issue #1111). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added love.graphics.drawLayer(texture, layerindex, …). ‘texture’ must be an array texture. Added SpriteBatch:add/setLayer. Added Quad:get/setLayer. This applies to array textures that are drawn without specifying an explicit layer index in the draw call. Added love.graphics.newQuad variants which have layer arguments. --HG-- branch : minor --- src/common/Matrix.h | 16 +-- src/modules/graphics/Canvas.cpp | 4 +- src/modules/graphics/Canvas.h | 6 +- src/modules/graphics/Graphics.cpp | 62 +++++---- src/modules/graphics/Graphics.h | 5 +- src/modules/graphics/ParticleSystem.cpp | 8 +- src/modules/graphics/Quad.cpp | 16 ++- src/modules/graphics/Quad.h | 9 +- src/modules/graphics/Shader.cpp | 40 ++++-- src/modules/graphics/Shader.h | 20 ++- src/modules/graphics/SpriteBatch.cpp | 116 +++++++++++----- src/modules/graphics/SpriteBatch.h | 18 ++- src/modules/graphics/Texture.cpp | 115 +++++++++------- src/modules/graphics/Texture.h | 14 +- src/modules/graphics/Video.cpp | 18 +-- src/modules/graphics/opengl/Canvas.cpp | 2 +- src/modules/graphics/opengl/Graphics.cpp | 36 +++-- src/modules/graphics/opengl/Image.cpp | 2 +- src/modules/graphics/opengl/OpenGL.cpp | 9 ++ src/modules/graphics/opengl/SpriteBatch.cpp | 34 ++++- src/modules/graphics/vertex.cpp | 8 ++ src/modules/graphics/vertex.h | 15 +++ src/modules/graphics/wrap_Graphics.cpp | 141 ++++++++++---------- src/modules/graphics/wrap_Graphics.lua | 6 + src/modules/graphics/wrap_Quad.cpp | 17 +++ src/modules/graphics/wrap_SpriteBatch.cpp | 93 ++++++++----- src/modules/graphics/wrap_SpriteBatch.h | 24 ++++ 27 files changed, 559 insertions(+), 295 deletions(-) diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 88e0fb45d..83f0edce6 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -192,8 +192,8 @@ public: * @param src The source vertices. * @param size The number of vertices. **/ - template - void transform(V *dst, const V *src, int size) const; + template + void transform(Vdst *dst, const Vsrc *src, int size) const; /** * Computes and returns the inverse of the matrix. @@ -273,8 +273,8 @@ public: /** * Transforms an array of vertices by this matrix. **/ - template - void transform(V *dst, const V *src, int size) const; + template + void transform(Vdst *dst, const Vsrc *src, int size) const; private: @@ -296,8 +296,8 @@ private: // | e2 e6 e10 e14 | // | e3 e7 e11 e15 | -template -void Matrix4::transform(V *dst, const V *src, int size) const +template +void Matrix4::transform(Vdst *dst, const Vsrc *src, int size) const { for (int i = 0; i < size; i++) { @@ -316,8 +316,8 @@ void Matrix4::transform(V *dst, const V *src, int size) const // | e0 e3 e6 | // | e1 e4 e7 | // | e2 e5 e8 | -template -void Matrix3::transform(V *dst, const V *src, int size) const +template +void Matrix3::transform(Vdst *dst, const Vsrc *src, int size) const { for (int i = 0; i < size; i++) { diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index 09f5d0f41..711de0032 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -40,12 +40,12 @@ Canvas::~Canvas() canvasCount--; } -void Canvas::drawv(love::graphics::Graphics *gfx, const love::Matrix4 &t, const Vertex *v) +void Canvas::draw(Graphics *gfx, Quad *q, const Matrix4 &t) { if (gfx->isCanvasActive(this)) throw love::Exception("Cannot render a Canvas to itself!"); - Texture::drawv(gfx, t, v); + Texture::draw(gfx, q, t); } } // graphics diff --git a/src/modules/graphics/Canvas.h b/src/modules/graphics/Canvas.h index 377d2651c..49ac879d8 100644 --- a/src/modules/graphics/Canvas.h +++ b/src/modules/graphics/Canvas.h @@ -57,11 +57,9 @@ public: virtual int getRequestedMSAA() const = 0; virtual ptrdiff_t getMSAAHandle() const = 0; + void draw(Graphics *gfx, Quad *q, const Matrix4 &t) override; + static int canvasCount; - -private: - - void drawv(Graphics *gfx, const Matrix4 &t, const Vertex *v) override; }; // Canvas diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index d1e4c172f..92020285d 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -99,8 +99,7 @@ bool isDebugEnabled() love::Type Graphics::type("graphics", &Module::type); -Shader::ShaderSource Graphics::defaultShaderCode[Shader::LANGUAGE_MAX_ENUM][2]; -Shader::ShaderSource Graphics::defaultVideoShaderCode[Shader::LANGUAGE_MAX_ENUM][2]; +Shader::ShaderSource Graphics::defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; Graphics::Graphics() : width(0) @@ -130,16 +129,13 @@ Graphics::~Graphics() defaultFont.set(nullptr); - if (Shader::defaultShader) + for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) { - Shader::defaultShader->release(); - Shader::defaultShader = nullptr; - } - - if (Shader::defaultVideoShader) - { - Shader::defaultVideoShader->release(); - Shader::defaultVideoShader = nullptr; + if (Shader::standardShaders[i]) + { + Shader::standardShaders[i]->release(); + Shader::standardShaders[i] = nullptr; + } } delete streamBufferState.vb[0]; @@ -390,7 +386,7 @@ void Graphics::setShader() { flushStreamDraws(); - Shader::attachDefault(); + Shader::attachDefault(Shader::STANDARD_DEFAULT); states.back().shader.set(nullptr); } @@ -692,6 +688,31 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest & * Drawing **/ +void Graphics::draw(Drawable *drawable, const Matrix4 &m) +{ + drawable->draw(this, m); +} + +void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m) +{ + texture->draw(this, quad, m); +} + +void Graphics::drawLayer(Texture *texture, int layer, const Matrix4 &m) +{ + texture->drawLayer(this, layer, m); +} + +void Graphics::drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m) +{ + texture->drawLayer(this, layer, quad, m); +} + +void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount) +{ + mesh->drawInstanced(this, m, instancecount); +} + void Graphics::print(const std::vector &str, const Matrix4 &m) { checkSetDefaultFont(); @@ -712,21 +733,6 @@ void Graphics::printf(const std::vector &str, float wrap, F state.font->printf(this, str, wrap, align, m, state.color); } -void Graphics::draw(Drawable *drawable, const Matrix4 &m) -{ - drawable->draw(this, m); -} - -void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m) -{ - texture->drawq(this, quad, m); -} - -void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount) -{ - mesh->drawInstanced(this, m, instancecount); -} - /** * Primitives (points, shapes, lines). **/ @@ -1165,7 +1171,7 @@ Vector Graphics::inverseTransformPoint(Vector point) const Shader::ShaderSource &Graphics::getCurrentDefaultShaderCode() const { - return defaultShaderCode[getShaderLanguageTarget()][isGammaCorrect() ? 1 : 0]; + return defaultShaderCode[Shader::STANDARD_DEFAULT][getShaderLanguageTarget()][isGammaCorrect() ? 1 : 0]; } /** diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 509a62736..9c3acef05 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -585,6 +585,8 @@ public: void draw(Drawable *drawable, const Matrix4 &m); void draw(Texture *texture, Quad *quad, const Matrix4 &m); + void drawLayer(Texture *texture, int layer, const Matrix4 &m); + void drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m); void drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount); /** @@ -782,8 +784,7 @@ public: static bool getConstant(StackType in, const char *&out); // Default shader code (a shader is always required internally.) - static Shader::ShaderSource defaultShaderCode[Shader::LANGUAGE_MAX_ENUM][2]; - static Shader::ShaderSource defaultVideoShaderCode[Shader::LANGUAGE_MAX_ENUM][2]; + static Shader::ShaderSource defaultShaderCode[Shader::STANDARD_MAX_ENUM][Shader::LANGUAGE_MAX_ENUM][2]; protected: diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index 6bd28208d..0da05f0d0 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -97,6 +97,9 @@ ParticleSystem::ParticleSystem(Graphics *gfx, Texture *texture, uint32 size) if (size == 0 || size > MAX_PARTICLES) throw love::Exception("Invalid ParticleSystem size."); + if (texture->getTextureType() != TEXTURE_2D) + throw love::Exception("Only 2D textures can be used with ParticleSystems."); + sizes.push_back(1.0f); colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); @@ -434,6 +437,9 @@ ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p) void ParticleSystem::setTexture(Texture *tex) { + if (texture->getTextureType() != TEXTURE_2D) + throw love::Exception("Only 2D textures can be used with ParticleSystems."); + texture.set(tex); if (defaultOffset) @@ -958,7 +964,7 @@ bool ParticleSystem::prepareDraw(Graphics *gfx, const Matrix4 &m) Graphics::TempTransform transform(gfx, m); - const Vertex *textureVerts = texture->getVertices(); + const vertex::XYf_STf *textureVerts = texture->getQuad()->getVertices(); Vertex *pVerts = (Vertex *) buffer->map(); Particle *p = pHead; diff --git a/src/modules/graphics/Quad.cpp b/src/modules/graphics/Quad.cpp index 66d196c45..30e8a79fd 100644 --- a/src/modules/graphics/Quad.cpp +++ b/src/modules/graphics/Quad.cpp @@ -35,7 +35,7 @@ Quad::Quad(const Quad::Viewport &v, double sw, double sh) : sw(sw) , sh(sh) { - memset(vertices, 255, sizeof(Vertex) * 4); + arrayLayer = 0; refresh(v, sw, sh); } @@ -45,7 +45,7 @@ Quad::~Quad() void Quad::refresh(const Quad::Viewport &v, double sw, double sh) { - viewport = v; + this->viewport = v; this->sw = sw; this->sh = sh; @@ -92,10 +92,20 @@ double Quad::getTextureHeight() const return sh; } -const Vertex *Quad::getVertices() const +const vertex::XYf_STf *Quad::getVertices() const { return vertices; } +void Quad::setLayer(int layer) +{ + arrayLayer = layer; +} + +int Quad::getLayer() const +{ + return arrayLayer; +} + } // graphics } // love diff --git a/src/modules/graphics/Quad.h b/src/modules/graphics/Quad.h index abb7a8425..13b6d392a 100644 --- a/src/modules/graphics/Quad.h +++ b/src/modules/graphics/Quad.h @@ -53,11 +53,16 @@ public: double getTextureWidth() const; double getTextureHeight() const; - const Vertex *getVertices() const; + const vertex::XYf_STf *getVertices() const; + + void setLayer(int layer); + int getLayer() const; private: - Vertex vertices[4]; + vertex::XYf_STf vertices[4]; + + int arrayLayer; Viewport viewport; double sw; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index ed67ef263..bc5dd8cf5 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -132,9 +132,9 @@ namespace graphics { love::Type Shader::type("Shader", &Object::type); + Shader *Shader::current = nullptr; -Shader *Shader::defaultShader = nullptr; -Shader *Shader::defaultVideoShader = nullptr; +Shader *Shader::standardShaders[Shader::STANDARD_MAX_ENUM] = {nullptr}; Shader::Shader(const ShaderSource &source) : shaderSource(source) @@ -151,27 +151,39 @@ Shader::Shader(const ShaderSource &source) Shader::~Shader() { - if (defaultShader == this) - defaultShader = nullptr; - - if (defaultVideoShader == this) - defaultVideoShader = nullptr; + for (int i = 0; i < STANDARD_MAX_ENUM; i++) + { + if (this == standardShaders[i]) + standardShaders[i] = nullptr; + } if (current == this) - attachDefault(); + attachDefault(STANDARD_DEFAULT); } -void Shader::attachDefault() +void Shader::attachDefault(StandardShader defaultType) { - if (defaultShader) - { - if (current != defaultShader) - defaultShader->attach(); + Shader *defaultshader = standardShaders[defaultType]; + if (defaultshader == nullptr) + { + current = nullptr; return; } - current = nullptr; + if (current != defaultshader) + defaultshader->attach(); +} + +bool Shader::isDefaultActive() +{ + for (int i = 0; i < STANDARD_MAX_ENUM; i++) + { + if (current == standardShaders[i]) + return true; + } + + return false; } TextureType Shader::getMainTextureType() const diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 37905eeae..001a90b20 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -95,6 +95,14 @@ public: UNIFORM_MAX_ENUM }; + enum StandardShader + { + STANDARD_DEFAULT, + STANDARD_VIDEO, + STANDARD_ARRAY, + STANDARD_MAX_ENUM + }; + struct ShaderSource { std::string vertex; @@ -137,8 +145,7 @@ public: static Shader *current; // Pointer to the default Shader. - static Shader *defaultShader; - static Shader *defaultVideoShader; + static Shader *standardShaders[STANDARD_MAX_ENUM]; Shader(const ShaderSource &source); virtual ~Shader(); @@ -149,9 +156,14 @@ public: virtual void attach() = 0; /** - * Attach the default shader. + * Attach a default shader. **/ - static void attachDefault(); + static void attachDefault(StandardShader defaultType); + + /** + * Gets whether any of the default shaders are currently active. + **/ + static bool isDefaultActive(); /** * Returns any warnings this Shader may have generated. diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 0b5cc3ce2..30cd34a4b 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -44,7 +44,8 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usag : texture(texture) , size(size) , next(0) - , color(0) + , color(255, 255, 255, 255) + , color_active(false) , array_buf(nullptr) , quad_indices(gfx, size) , range_start(-1) @@ -53,26 +54,59 @@ SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usag if (size <= 0) throw love::Exception("Invalid SpriteBatch size."); - size_t vertex_size = sizeof(Vertex) * 4 * size; + if (texture == nullptr) + throw love::Exception("A texture must be used when creating a SpriteBatch."); + if (texture->getTextureType() == TEXTURE_2D_ARRAY) + vertex_format = vertex::CommonFormat::XYf_STPf_RGBAub; + else + vertex_format = vertex::CommonFormat::XYf_STf_RGBAub; + + format_stride = vertex::getFormatStride(vertex_format); + + size_t vertex_size = format_stride * 4 * size; array_buf = gfx->newBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY); } SpriteBatch::~SpriteBatch() { - delete color; delete array_buf; } int SpriteBatch::add(const Matrix4 &m, int index /*= -1*/) { + return add(texture->getQuad(), m, index); +} + +int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) +{ + using namespace vertex; + + if (vertex_format == CommonFormat::XYf_STPf_RGBAub) + return addLayer(quad->getLayer(), quad, m, index); + if (index < -1 || index >= size) throw love::Exception("Invalid sprite index: %d", index + 1); if (index == -1 && next >= size) setBufferSize(size * 2); - addv(texture->getVertices(), m, (index == -1) ? next : index); + const XYf_STf *quadverts = quad->getVertices(); + + // Always keep the VBO mapped when adding data (it'll be unmapped on draw.) + size_t offset = (index == -1 ? next : index) * format_stride * 4; + auto verts = (XYf_STf_RGBAub *) ((uint8 *) array_buf->map() + offset); + + m.transform(verts, quadverts, 4); + + for (int i = 0; i < 4; i++) + { + verts[i].s = quadverts[i].s; + verts[i].t = quadverts[i].t; + verts[i].color = color; + } + + array_buf->setMappedRangeModified(offset, format_stride * 4); // Increment counter. if (index == -1) @@ -81,15 +115,44 @@ int SpriteBatch::add(const Matrix4 &m, int index /*= -1*/) return index; } -int SpriteBatch::addq(Quad *quad, const Matrix4 &m, int index /*= -1*/) +int SpriteBatch::addLayer(int layer, const Matrix4 &m, int index) { + return addLayer(layer, texture->getQuad(), m, index); +} + +int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) +{ + using namespace vertex; + + if (vertex_format != CommonFormat::XYf_STPf_RGBAub) + throw love::Exception("addLayer can only be called on a SpriteBatch that uses an Array Texture!"); + if (index < -1 || index >= size) throw love::Exception("Invalid sprite index: %d", index + 1); + if (layer < 0 || layer >= texture->getLayerCount()) + throw love::Exception("Invalid layer: %d (Texture has %d layers)", layer + 1, texture->getLayerCount()); + if (index == -1 && next >= size) setBufferSize(size * 2); - addv(quad->getVertices(), m, (index == -1) ? next : index); + const XYf_STf *quadverts = quad->getVertices(); + + // Always keep the VBO mapped when adding data (it'll be unmapped on draw.) + size_t offset = (index == -1 ? next : index) * format_stride * 4; + auto verts = (XYf_STPf_RGBAub *) ((uint8 *) array_buf->map() + offset); + + m.transform(verts, quadverts, 4); + + for (int i = 0; i < 4; i++) + { + verts[i].s = quadverts[i].s; + verts[i].t = quadverts[i].t; + verts[i].p = (float) layer; + verts[i].color = color; + } + + array_buf->setMappedRangeModified(offset, format_stride * 4); // Increment counter. if (index == -1) @@ -111,6 +174,9 @@ void SpriteBatch::flush() void SpriteBatch::setTexture(Texture *newtexture) { + if (texture->getTextureType() != newtexture->getTextureType()) + throw love::Exception("Texture must have the same texture type as the SpriteBatch's previous texture."); + texture.set(newtexture); } @@ -121,20 +187,19 @@ Texture *SpriteBatch::getTexture() const void SpriteBatch::setColor(const Color &color) { - if (!this->color) - this->color = new Color(color); - else - *(this->color) = color; + color_active = true; + this->color = color; } void SpriteBatch::setColor() { - delete color; - color = nullptr; + color_active = false; + color = Color(255, 255, 255, 255); } -const Color *SpriteBatch::getColor() const +const Color &SpriteBatch::getColor(bool &active) const { + active = color_active; return color; } @@ -151,7 +216,7 @@ void SpriteBatch::setBufferSize(int newsize) if (newsize == size) return; - size_t vertex_size = sizeof(Vertex) * 4 * newsize; + size_t vertex_size = format_stride * 4 * newsize; love::graphics::Buffer *new_array_buf = nullptr; int new_next = std::min(next, newsize); @@ -162,7 +227,7 @@ void SpriteBatch::setBufferSize(int newsize) new_array_buf = gfx->newBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags()); // Copy as much of the old data into the new GLBuffer as can fit. - size_t copy_size = sizeof(Vertex) * 4 * new_next; + size_t copy_size = format_stride * 4 * new_next; array_buf->copyTo(0, copy_size, new_array_buf, 0); quad_indices = QuadIndices(gfx, newsize); @@ -233,26 +298,5 @@ bool SpriteBatch::getDrawRange(int &start, int &count) const return true; } -void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index) -{ - // Needed for colors. - Vertex sprite[4] = {v[0], v[1], v[2], v[3]}; - const size_t sprite_size = 4 * sizeof(Vertex); // bytecount - - m.transform(sprite, sprite, 4); - - if (color != nullptr) - { - for (int i = 0; i < 4; i++) - sprite[i].color = *color; - } - - // Always keep the VBO mapped when adding data for now (it'll be unmapped - // on draw.) - array_buf->map(); - - array_buf->fill(index * sprite_size, sprite_size, sprite); -} - } // graphics } // love diff --git a/src/modules/graphics/SpriteBatch.h b/src/modules/graphics/SpriteBatch.h index 7590af7ae..d3a4b62f5 100644 --- a/src/modules/graphics/SpriteBatch.h +++ b/src/modules/graphics/SpriteBatch.h @@ -54,7 +54,10 @@ public: virtual ~SpriteBatch(); int add(const Matrix4 &m, int index = -1); - int addq(Quad *quad, const Matrix4 &m, int index = -1); + int add(Quad *quad, const Matrix4 &m, int index = -1); + int addLayer(int layer, const Matrix4 &m, int index = -1); + int addLayer(int layer, Quad *quad, const Matrix4 &m, int index = -1); + void clear(); void flush(); @@ -78,10 +81,9 @@ public: void setColor(); /** - * Get the current color for this SpriteBatch. Returns NULL if no color is - * set. + * Get the current color for this SpriteBatch. **/ - const Color *getColor() const; + const Color &getColor(bool &active) const; /** * Get the number of sprites currently in this SpriteBatch. @@ -117,8 +119,6 @@ protected: **/ void setBufferSize(int newsize); - void addv(const Vertex *v, const Matrix4 &m, int index); - StrongRef texture; // Max number of sprites in the batch. @@ -129,7 +129,11 @@ protected: // Current color. This color, if present, will be applied to the next // added sprite. - Color *color; + Color color; + bool color_active; + + vertex::CommonFormat vertex_format; + size_t format_stride; love::graphics::Buffer *array_buf; QuadIndices quad_indices; diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index 9bde3ab59..ff91966b1 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -61,7 +61,6 @@ Texture::Texture(TextureType texType) , filter(defaultFilter) , wrap() , mipmapSharpness(defaultMipmapSharpness) - , vertices() { } @@ -69,32 +68,10 @@ Texture::~Texture() { } -void Texture::initVertices() +void Texture::initQuad() { - for (int i = 0; i < 4; i++) - vertices[i].color = Color(255, 255, 255, 255); - - // Vertices are ordered for use with triangle strips: - // 0---2 - // | / | - // 1---3 - vertices[0].x = 0.0f; - vertices[0].y = 0.0f; - vertices[1].x = 0.0f; - vertices[1].y = (float) height; - vertices[2].x = (float) width; - vertices[2].y = 0.0f; - vertices[3].x = (float) width; - vertices[3].y = (float) height; - - vertices[0].s = 0.0f; - vertices[0].t = 0.0f; - vertices[1].s = 0.0f; - vertices[1].t = 1.0f; - vertices[2].s = 1.0f; - vertices[2].t = 0.0f; - vertices[3].s = 1.0f; - vertices[3].t = 1.0f; + Quad::Viewport v = {0, 0, (double) width, (double) height}; + quad.set(new Quad(v, width, height), Acquire::NORETAIN); } TextureType Texture::getTextureType() const @@ -109,37 +86,81 @@ PixelFormat Texture::getPixelFormat() const void Texture::draw(Graphics *gfx, const Matrix4 &m) { - drawv(gfx, m, vertices); + draw(gfx, quad, m); } -void Texture::drawq(Graphics *gfx, Quad *quad, const Matrix4 &m) +void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) { - drawv(gfx, m, quad->getVertices()); -} + using namespace vertex; -void Texture::drawv(Graphics *gfx, const Matrix4 &localTransform, const Vertex *v) -{ - if (Shader::current) - Shader::current->checkMainTextureType(texType); - - Matrix4 t(gfx->getTransform(), localTransform); - - Vertex verts[4] = {v[0], v[1], v[2], v[3]}; - t.transform(verts, v, 4); + if (texType == TEXTURE_2D_ARRAY) + { + drawLayer(gfx, q->getLayer(), q, localTransform); + return; + } Color c = toColor(gfx->getColor()); - for (int i = 0; i < 4; i++) - verts[i].color = c; - Graphics::StreamDrawRequest req; - req.formats[0] = vertex::CommonFormat::XYf_STf_RGBAub; - req.indexMode = vertex::TriangleIndexMode::QUADS; + req.formats[0] = CommonFormat::XYf_STf_RGBAub; + req.indexMode = TriangleIndexMode::QUADS; req.vertexCount = 4; req.texture = this; Graphics::StreamVertexData data = gfx->requestStreamDraw(req); - memcpy(data.stream[0], verts, sizeof(Vertex) * 4); + + XYf_STf_RGBAub *verts = (XYf_STf_RGBAub *) data.stream[0]; + const XYf_STf *quadverts = q->getVertices(); + + Matrix4 t(gfx->getTransform(), localTransform); + t.transform(verts, quadverts, 4); + + for (int i = 0; i < 4; i++) + { + verts[i].s = quadverts[i].s; + verts[i].t = quadverts[i].t; + verts[i].color = c; + } +} + +void Texture::drawLayer(Graphics *gfx, int layer, const Matrix4 &m) +{ + drawLayer(gfx, layer, quad, m); +} + +void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m) +{ + using namespace vertex; + + if (texType != TEXTURE_2D_ARRAY) + throw love::Exception("drawLayer can only be used with Array Textures!"); + + if (layer < 0 || layer >= layers) + throw love::Exception("Invalid layer: %d (Texture has %d layers)", layer + 1, layers); + + Color c = toColor(gfx->getColor()); + + Graphics::StreamDrawRequest req; + req.formats[0] = CommonFormat::XYf_STPf_RGBAub; + req.indexMode = TriangleIndexMode::QUADS; + req.vertexCount = 4; + req.texture = this; + + Graphics::StreamVertexData data = gfx->requestStreamDraw(req); + + XYf_STPf_RGBAub *verts = (XYf_STPf_RGBAub *) data.stream[0]; + const XYf_STf *quadverts = q->getVertices(); + + Matrix4 t(gfx->getTransform(), m); + t.transform(verts, quadverts, 4); + + for (int i = 0; i < 4; i++) + { + verts[i].s = quadverts[i].s; + verts[i].t = quadverts[i].t; + verts[i].p = (float) layer; + verts[i].color = c; + } } int Texture::getWidth() const @@ -197,9 +218,9 @@ float Texture::getMipmapSharpness() const return mipmapSharpness; } -const Vertex *Texture::getVertices() const +Quad *Texture::getQuad() const { - return vertices; + return quad; } bool Texture::validateFilter(const Filter &f, bool mipmapsAllowed) diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 69a8b6c91..944d58563 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -112,7 +112,10 @@ public: /** * Draws the texture using the specified transformation with a Quad applied. **/ - void drawq(Graphics *gfx, Quad *quad, const Matrix4 &m); + virtual void draw(Graphics *gfx, Quad *quad, const Matrix4 &m); + + void drawLayer(Graphics *gfx, int layer, const Matrix4 &m); + virtual void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); TextureType getTextureType() const; PixelFormat getPixelFormat() const; @@ -138,7 +141,7 @@ public: virtual bool setMipmapSharpness(float sharpness) = 0; float getMipmapSharpness() const; - virtual const Vertex *getVertices() const; + Quad *getQuad() const; virtual ptrdiff_t getHandle() const = 0; @@ -158,8 +161,7 @@ public: protected: - void initVertices(); - virtual void drawv(Graphics *gfx, const Matrix4 &localTransform, const Vertex *v); + void initQuad(); TextureType texType; @@ -167,6 +169,7 @@ protected: int width; int height; + int depth; int layers; int mipmapCount; @@ -174,13 +177,12 @@ protected: int pixelWidth; int pixelHeight; - Filter filter; Wrap wrap; float mipmapSharpness; - Vertex vertices[4]; + StrongRef quad; private: diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 63ea5e35a..7766f1766 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -109,16 +109,18 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) gfx->flushStreamDraws(); - love::graphics::Shader *shader = Shader::current; - bool usingdefaultshader = (shader == Shader::defaultShader); + bool usingdefaultshader = Shader::isDefaultActive(); + Shader *prevdefaultshader = nullptr; + + // If we're using the default shader, substitute the video version. if (usingdefaultshader) { - // If we're using the default shader, substitute the video version. - Shader::defaultVideoShader->attach(); - shader = Shader::defaultVideoShader; + prevdefaultshader = Shader::current; + Shader::standardShaders[Shader::STANDARD_VIDEO]->attach(); } - shader->setVideoTextures(images[0], images[1], images[2]); + if (Shader::current != nullptr) + Shader::current->setVideoTextures(images[0], images[1], images[2]); Graphics::StreamDrawRequest req; req.formats[0] = vertex::CommonFormat::XYf_STf_RGBAub; @@ -142,8 +144,8 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) gfx->flushStreamDraws(); - if (usingdefaultshader) - Shader::defaultShader->attach(); + if (usingdefaultshader && prevdefaultshader != nullptr) + prevdefaultshader->attach(); } void Video::update() diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 1d3fc955c..88e245bb8 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -140,7 +140,7 @@ Canvas::Canvas(const Settings &settings) this->format = getSizedFormat(settings.format); - initVertices(); + initQuad(); loadVolatile(); if (status != GL_FRAMEBUFFER_COMPLETE) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index bece3b942..a4c4288e7 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -268,25 +268,19 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b restoreState(states.back()); int gammacorrect = isGammaCorrect() ? 1 : 0; + Shader::Language target = getShaderLanguageTarget(); // We always need a default shader. - if (!Shader::defaultShader) + for (int i = 0; i < Shader::STANDARD_MAX_ENUM; i++) { - Shader::Language target = getShaderLanguageTarget(); - Shader::defaultShader = newShader(defaultShaderCode[target][gammacorrect]); - } - - // and a default video shader. - if (!Shader::defaultVideoShader) - { - Shader::Language target = getShaderLanguageTarget(); - Shader::defaultVideoShader = newShader(defaultVideoShaderCode[target][gammacorrect]); + if (!Shader::standardShaders[i]) + Shader::standardShaders[i] = newShader(defaultShaderCode[i][target][gammacorrect]); } // A shader should always be active, but the default shader shouldn't be // returned by getShader(), so we don't do setShader(defaultShader). if (!Shader::current) - Shader::defaultShader->attach(); + Shader::standardShaders[Shader::STANDARD_DEFAULT]->attach(); return true; } @@ -343,8 +337,21 @@ void Graphics::flushStreamDraws() if (sbstate.vertexCount == 0 && sbstate.indexCount == 0) return; - if (Shader::current && sbstate.texture.get()) - Shader::current->checkMainTextureType(sbstate.texture->getTextureType()); + love::graphics::Shader *prevdefaultshader = nullptr; + + if (sbstate.texture.get()) + { + TextureType textype = sbstate.texture->getTextureType(); + + if (textype == TEXTURE_2D_ARRAY && Shader::isDefaultActive()) + { + prevdefaultshader = Shader::current; + Shader::standardShaders[Shader::STANDARD_ARRAY]->attach(); + } + + if (Shader::current) + Shader::current->checkMainTextureType(textype); + } OpenGL::TempDebugGroup debuggroup("Stream vertices flush and draw"); @@ -425,6 +432,9 @@ void Graphics::flushStreamDraws() streamBufferState.vertexCount = 0; streamBufferState.indexCount = 0; + + if (prevdefaultshader != nullptr) + prevdefaultshader->attach(); } static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index ab56fdae5..b56762a3b 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -92,8 +92,8 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) if (getMipmapCount() > 1) filter.mipmap = defaultMipmapFilter; + initQuad(); loadVolatile(); - initVertices(); } void Image::generateMipmaps() diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 553ede222..afdf3b1bc 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -650,6 +650,10 @@ void OpenGL::setVertexPointers(vertex::CommonFormat format, size_t stride, size_ glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf, x))); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf, s))); break; + case CommonFormat::XYf_STPf: + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf, x))); + glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf, s))); + break; case CommonFormat::XYf_STf_RGBAub: glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, x))); glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, s))); @@ -660,6 +664,11 @@ void OpenGL::setVertexPointers(vertex::CommonFormat format, size_t stride, size_ glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, s))); glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, color.r))); break; + case CommonFormat::XYf_STPf_RGBAub: + glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, x))); + glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, s))); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, color.r))); + break; } } diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp index 220283287..f81a03b64 100644 --- a/src/modules/graphics/opengl/SpriteBatch.cpp +++ b/src/modules/graphics/opengl/SpriteBatch.cpp @@ -60,8 +60,21 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) gfx->flushStreamDraws(); - if (Shader::current && texture.get()) - Shader::current->checkMainTextureType(texture->getTextureType()); + Shader *prevdefaultshader = nullptr; + + if (texture.get()) + { + TextureType textype = texture->getTextureType(); + + if (textype == TEXTURE_2D_ARRAY && Shader::isDefaultActive()) + { + prevdefaultshader = Shader::current; + Shader::standardShaders[Shader::STANDARD_ARRAY]->attach(); + } + + if (Shader::current) + Shader::current->checkMainTextureType(texture->getTextureType()); + } OpenGL::TempDebugGroup debuggroup("SpriteBatch draw"); @@ -72,13 +85,19 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) // Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.) array_buf->unmap(); - CommonFormat format = CommonFormat::XYf_STf_RGBAub; - if (color == nullptr) - format = CommonFormat::XYf_STf; + CommonFormat format = vertex_format; + + if (!color_active) + { + if (format == CommonFormat::XYf_STPf_RGBAub) + format = CommonFormat::XYf_STPf; + else + format = CommonFormat::XYf_STf; + } uint32 enabledattribs = getFormatFlags(format); - gl.setVertexPointers(format, array_buf, getFormatStride(CommonFormat::XYf_STf_RGBAub), 0); + gl.setVertexPointers(format, array_buf, format_stride, 0); for (const auto &it : attached_attributes) { @@ -116,6 +135,9 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(count), gltype, indices); } + + if (prevdefaultshader != nullptr) + prevdefaultshader->attach(); } } // opengl diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index 8c343217d..249bedac4 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -30,8 +30,10 @@ namespace vertex static_assert(sizeof(Color) == 4, "sizeof(Color) incorrect!"); static_assert(sizeof(XYf_STf) == sizeof(float)*2 + sizeof(float)*2, "sizeof(XYf_STf) incorrect!"); +static_assert(sizeof(XYf_STPf) == sizeof(float)*2 + sizeof(float)*3, "sizeof(XYf_STPf) incorrect!"); static_assert(sizeof(XYf_STf_RGBAub) == sizeof(float)*2 + sizeof(float)*2 + sizeof(Color), "sizeof(XYf_STf_RGBAub) incorrect!"); static_assert(sizeof(XYf_STus_RGBAub) == sizeof(float)*2 + sizeof(uint16)*2 + sizeof(Color), "sizeof(XYf_STus_RGBAub) incorrect!"); +static_assert(sizeof(XYf_STPf_RGBAub) == sizeof(float)*2 + sizeof(float)*3 + sizeof(Color), "sizeof(XYf_STPf_RGBAub) incorrect!"); size_t getFormatStride(CommonFormat format) { @@ -45,10 +47,14 @@ size_t getFormatStride(CommonFormat format) return sizeof(uint8) * 4; case CommonFormat::XYf_STf: return sizeof(XYf_STf); + case CommonFormat::XYf_STPf: + return sizeof(XYf_STPf); case CommonFormat::XYf_STf_RGBAub: return sizeof(XYf_STf_RGBAub); case CommonFormat::XYf_STus_RGBAub: return sizeof(XYf_STus_RGBAub); + case CommonFormat::XYf_STPf_RGBAub: + return sizeof(XYf_STPf_RGBAub); } } @@ -63,9 +69,11 @@ uint32 getFormatFlags(CommonFormat format) case CommonFormat::RGBAub: return ATTRIBFLAG_COLOR; case CommonFormat::XYf_STf: + case CommonFormat::XYf_STPf: return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; case CommonFormat::XYf_STf_RGBAub: case CommonFormat::XYf_STus_RGBAub: + case CommonFormat::XYf_STPf_RGBAub: return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR; } diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 986663b80..a86ee34aa 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -97,8 +97,10 @@ enum class CommonFormat XYf, RGBAub, XYf_STf, + XYf_STPf, XYf_STf_RGBAub, XYf_STus_RGBAub, + XYf_STPf_RGBAub, }; struct XYf_STf @@ -107,6 +109,12 @@ struct XYf_STf float s, t; }; +struct XYf_STPf +{ + float x, y; + float s, t, p; +}; + struct XYf_STf_RGBAub { float x, y; @@ -121,6 +129,13 @@ struct XYf_STus_RGBAub Color color; }; +struct XYf_STPf_RGBAub +{ + float x, y; + float s, t, p; + Color color; +}; + size_t getFormatStride(CommonFormat format); uint32 getFormatFlags(CommonFormat format); size_t getIndexDataSize(IndexDataType type); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index fd2bc4a01..0a66c76ee 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -828,6 +828,7 @@ int w_newQuad(lua_State *L) double sw = 0.0f; double sh = 0.0f; + int layer = 0; if (luax_istype(L, 5, Texture::type)) { @@ -835,6 +836,19 @@ int w_newQuad(lua_State *L) sw = texture->getWidth(); sh = texture->getHeight(); } + else if (luax_istype(L, 6, Texture::type)) + { + layer = (int) luaL_checknumber(L, 5) - 1; + Texture *texture = luax_checktexture(L, 6); + sw = texture->getWidth(); + sh = texture->getHeight(); + } + else if (!lua_isnoneornil(L, 7)) + { + layer = (int) luaL_checknumber(L, 5) - 1; + sw = luaL_checknumber(L, 6); + sh = luaL_checknumber(L, 7); + } else { sw = luaL_checknumber(L, 5); @@ -842,6 +856,8 @@ int w_newQuad(lua_State *L) } Quad *quad = instance()->newQuad(v, sw, sh); + quad->setLayer(layer); + luax_pushtype(L, quad); quad->release(); return 1; @@ -1761,19 +1777,25 @@ int w_setDefaultShaderCode(lua_State *L) lua_getfield(L, -1, "vertex"); lua_getfield(L, -2, "pixel"); lua_getfield(L, -3, "videopixel"); + lua_getfield(L, -4, "arraypixel"); Shader::ShaderSource code; - code.vertex = luax_checkstring(L, -3); - code.pixel = luax_checkstring(L, -2); + code.vertex = luax_checkstring(L, -4); + code.pixel = luax_checkstring(L, -3); Shader::ShaderSource videocode; - videocode.vertex = luax_checkstring(L, -3); - videocode.pixel = luax_checkstring(L, -1); + videocode.vertex = luax_checkstring(L, -4); + videocode.pixel = luax_checkstring(L, -2); - lua_pop(L, 4); + Shader::ShaderSource arraycode; + arraycode.vertex = luax_checkstring(L, -4); + arraycode.pixel = luax_checkstring(L, -1); - Graphics::defaultShaderCode[lang][i] = code; - Graphics::defaultVideoShaderCode[lang][i] = videocode; + lua_pop(L, 5); + + Graphics::defaultShaderCode[Shader::STANDARD_DEFAULT][lang][i] = code; + Graphics::defaultShaderCode[Shader::STANDARD_VIDEO][lang][i] = videocode; + Graphics::defaultShaderCode[Shader::STANDARD_ARRAY][lang][i] = arraycode; } } @@ -1927,37 +1949,48 @@ int w_draw(lua_State *L) startidx = 2; } - if (luax_istype(L, startidx, math::Transform::type)) + luax_checkstandardtransform(L, startidx, [&](const Matrix4 &m) { - math::Transform *tf = luax_totype(L, startidx); - luax_catchexcept(L, [&]() { - if (texture && quad) - instance()->draw(texture, quad, tf->getMatrix()); - else - instance()->draw(drawable, tf->getMatrix()); - }); - } - else - { - float x = (float) luaL_optnumber(L, startidx + 0, 0.0); - float y = (float) luaL_optnumber(L, startidx + 1, 0.0); - float a = (float) luaL_optnumber(L, startidx + 2, 0.0); - float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); - float sy = (float) luaL_optnumber(L, startidx + 4, sx); - float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); - float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); - float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); - float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); - - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - - luax_catchexcept(L, [&]() { + luax_catchexcept(L, [&]() + { if (texture && quad) instance()->draw(texture, quad, m); - else if (drawable) + else instance()->draw(drawable, m); }); + }); + + return 0; +} + +int w_drawLayer(lua_State *L) +{ + Texture *texture = luax_checktexture(L, 1); + Quad *quad = nullptr; + int layer = (int) luaL_checknumber(L, 2) - 1; + int startidx = 3; + + if (luax_istype(L, startidx, Quad::type)) + { + texture = luax_checktexture(L, 1); + quad = luax_totype(L, startidx); + startidx++; } + else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) + { + return luax_typerror(L, startidx, "Quad"); + } + + luax_checkstandardtransform(L, startidx, [&](const Matrix4 &m) + { + luax_catchexcept(L, [&]() + { + if (quad) + instance()->drawLayer(texture, layer, quad, m); + else + instance()->drawLayer(texture, layer, m); + }); + }); return 0; } @@ -1967,27 +2000,10 @@ int w_drawInstanced(lua_State *L) Mesh *t = luax_checkmesh(L, 1); int instancecount = (int) luaL_checkinteger(L, 2); - if (luax_istype(L, 3, math::Transform::type)) + luax_checkstandardtransform(L, 3, [&](const Matrix4 &m) { - math::Transform *tf = luax_totype(L, 3); - luax_catchexcept(L, [&]() { instance()->drawInstanced(t, tf->getMatrix(), instancecount); }); - } - else - { - float x = (float) luaL_optnumber(L, 3, 0.0); - float y = (float) luaL_optnumber(L, 4, 0.0); - float a = (float) luaL_optnumber(L, 5, 0.0); - float sx = (float) luaL_optnumber(L, 6, 1.0); - float sy = (float) luaL_optnumber(L, 7, sx); - float ox = (float) luaL_optnumber(L, 8, 0.0); - float oy = (float) luaL_optnumber(L, 9, 0.0); - float kx = (float) luaL_optnumber(L, 10, 0.0); - float ky = (float) luaL_optnumber(L, 11, 0.0); - - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - luax_catchexcept(L, [&]() { instance()->drawInstanced(t, m, instancecount); }); - } + }); return 0; } @@ -1997,27 +2013,11 @@ int w_print(lua_State *L) std::vector str; luax_checkcoloredstring(L, 1, str); - if (luax_istype(L, 2, math::Transform::type)) + luax_checkstandardtransform(L, 2, [&](const Matrix4 &m) { - math::Transform *tf = luax_totype(L, 2); - luax_catchexcept(L, [&](){ instance()->print(str, tf->getMatrix()); }); - } - else - { - float x = (float)luaL_optnumber(L, 2, 0.0); - float y = (float)luaL_optnumber(L, 3, 0.0); - float angle = (float)luaL_optnumber(L, 4, 0.0f); - float sx = (float)luaL_optnumber(L, 5, 1.0f); - float sy = (float)luaL_optnumber(L, 6, sx); - float ox = (float)luaL_optnumber(L, 7, 0.0f); - float oy = (float)luaL_optnumber(L, 8, 0.0f); - float kx = (float)luaL_optnumber(L, 9, 0.0f); - float ky = (float)luaL_optnumber(L, 10, 0.0f); - - Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky); - luax_catchexcept(L, [&](){ instance()->print(str, m); }); - } + }); + return 0; } @@ -2519,6 +2519,7 @@ static const luaL_Reg functions[] = { "captureScreenshot", w_captureScreenshot }, { "draw", w_draw }, + { "drawLayer", w_drawLayer }, { "drawInstanced", w_drawInstanced }, { "print", w_print }, diff --git a/src/modules/graphics/wrap_Graphics.lua b/src/modules/graphics/wrap_Graphics.lua index fe94d2da4..86bb0cabf 100644 --- a/src/modules/graphics/wrap_Graphics.lua +++ b/src/modules/graphics/wrap_Graphics.lua @@ -412,6 +412,11 @@ vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) { videopixel = [[ vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord) { return VideoTexel(texcoord) * vcolor; +}]], + arraypixel = [[ +uniform ArrayImage MainTex; +void effect() { + love_PixelColor = Texel(MainTex, VaryingTexCoord.xyz) * VaryingColor; }]], } @@ -432,6 +437,7 @@ for lang, info in pairs(langs) do vertex = createShaderStageCode("VERTEX", defaultcode.vertex, info.target, info.gles, false, gammacorrect), pixel = createShaderStageCode("PIXEL", defaultcode.pixel, info.target, info.gles, false, gammacorrect, false), videopixel = createShaderStageCode("PIXEL", defaultcode.videopixel, info.target, info.gles, false, gammacorrect, false), + arraypixel = createShaderStageCode("PIXEL", defaultcode.arraypixel, info.target, info.gles, false, gammacorrect, true), } end end diff --git a/src/modules/graphics/wrap_Quad.cpp b/src/modules/graphics/wrap_Quad.cpp index 1cbabfa62..db2584ba3 100644 --- a/src/modules/graphics/wrap_Quad.cpp +++ b/src/modules/graphics/wrap_Quad.cpp @@ -74,11 +74,28 @@ int w_Quad_getTextureDimensions(lua_State *L) return 2; } +int w_Quad_setLayer(lua_State *L) +{ + Quad *quad = luax_checkquad(L, 1); + int layer = (int) luaL_checknumber(L, 2) - 1; + quad->setLayer(layer); + return 0; +} + +int w_Quad_getLayer(lua_State *L) +{ + Quad *quad = luax_checkquad(L, 1); + lua_pushnumber(L, quad->getLayer() + 1); + return 1; +} + static const luaL_Reg w_Quad_functions[] = { { "setViewport", w_Quad_setViewport }, { "getViewport", w_Quad_getViewport }, { "getTextureDimensions", w_Quad_getTextureDimensions }, + { "setLayer", w_Quad_setLayer }, + { "getLayer", w_Quad_getLayer }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_SpriteBatch.cpp b/src/modules/graphics/wrap_SpriteBatch.cpp index fa30a221c..dd546a82b 100644 --- a/src/modules/graphics/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/wrap_SpriteBatch.cpp @@ -23,7 +23,6 @@ #include "Image.h" #include "Canvas.h" #include "wrap_Texture.h" -#include "math/wrap_Transform.h" namespace love { @@ -47,37 +46,44 @@ static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int sta else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) return luax_typerror(L, startidx, "Quad"); - if (luax_istype(L, startidx, math::Transform::type)) + luax_checkstandardtransform(L, startidx, [&](const Matrix4 &m) { - math::Transform *tf = luax_totype(L, startidx); - luax_catchexcept(L, [&]() { + luax_catchexcept(L, [&]() + { if (quad) - index = t->addq(quad, tf->getMatrix(), index); - else - index = t->add(tf->getMatrix(), index); - }); - } - else - { - float x = (float) luaL_optnumber(L, startidx + 0, 0.0); - float y = (float) luaL_optnumber(L, startidx + 1, 0.0); - float a = (float) luaL_optnumber(L, startidx + 2, 0.0); - float sx = (float) luaL_optnumber(L, startidx + 3, 1.0); - float sy = (float) luaL_optnumber(L, startidx + 4, sx); - float ox = (float) luaL_optnumber(L, startidx + 5, 0.0); - float oy = (float) luaL_optnumber(L, startidx + 6, 0.0); - float kx = (float) luaL_optnumber(L, startidx + 7, 0.0); - float ky = (float) luaL_optnumber(L, startidx + 8, 0.0); - - Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky); - - luax_catchexcept(L, [&]() { - if (quad) - index = t->addq(quad, m, index); + index = t->add(quad, m, index); else index = t->add(m, index); }); + }); + + return index; +} + +static int w_SpriteBatch_addLayer_or_setLayer(lua_State *L, SpriteBatch *t, int startidx, int index) +{ + Quad *quad = nullptr; + int layer = (int) luaL_checknumber(L, startidx) - 1; + startidx++; + + if (luax_istype(L, startidx, Quad::type)) + { + quad = luax_totype(L, startidx); + startidx++; } + else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) + return luax_typerror(L, startidx, "Quad"); + + luax_checkstandardtransform(L, startidx, [&](const Matrix4 &m) + { + luax_catchexcept(L, [&]() + { + if (quad) + index = t->addLayer(layer, quad, m, index); + else + index = t->addLayer(layer, m, index); + }); + }); return index; } @@ -102,6 +108,26 @@ int w_SpriteBatch_set(lua_State *L) return 0; } +int w_SpriteBatch_addLayer(lua_State *L) +{ + SpriteBatch *t = luax_checkspritebatch(L, 1); + + int index = w_SpriteBatch_addLayer_or_setLayer(L, t, 2, -1); + lua_pushinteger(L, index + 1); + + return 1; +} + +int w_SpriteBatch_setLayer(lua_State *L) +{ + SpriteBatch *t = luax_checkspritebatch(L, 1); + int index = (int) luaL_checknumber(L, 2) - 1; + + w_SpriteBatch_addLayer_or_setLayer(L, t, 3, index); + + return 0; +} + int w_SpriteBatch_clear(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); @@ -178,16 +204,17 @@ int w_SpriteBatch_setColor(lua_State *L) int w_SpriteBatch_getColor(lua_State *L) { SpriteBatch *t = luax_checkspritebatch(L, 1); - const Color *color = t->getColor(); + bool active = false; + const Color &color = t->getColor(active); // getColor returns null if no color is set. - if (!color) + if (!active) return 0; - lua_pushnumber(L, (lua_Number) color->r / 255.0); - lua_pushnumber(L, (lua_Number) color->g / 255.0); - lua_pushnumber(L, (lua_Number) color->b / 255.0); - lua_pushnumber(L, (lua_Number) color->a / 255.0); + lua_pushnumber(L, (lua_Number) color.r / 255.0); + lua_pushnumber(L, (lua_Number) color.g / 255.0); + lua_pushnumber(L, (lua_Number) color.b / 255.0); + lua_pushnumber(L, (lua_Number) color.a / 255.0); return 4; } @@ -250,6 +277,8 @@ static const luaL_Reg w_SpriteBatch_functions[] = { { "add", w_SpriteBatch_add }, { "set", w_SpriteBatch_set }, + { "addLayer", w_SpriteBatch_addLayer }, + { "setLayer", w_SpriteBatch_setLayer }, { "clear", w_SpriteBatch_clear }, { "flush", w_SpriteBatch_flush }, { "setTexture", w_SpriteBatch_setTexture }, diff --git a/src/modules/graphics/wrap_SpriteBatch.h b/src/modules/graphics/wrap_SpriteBatch.h index 7e234104a..cf24d434a 100644 --- a/src/modules/graphics/wrap_SpriteBatch.h +++ b/src/modules/graphics/wrap_SpriteBatch.h @@ -22,12 +22,36 @@ #include "common/runtime.h" #include "SpriteBatch.h" +#include "math/wrap_Transform.h" namespace love { namespace graphics { +template +static void luax_checkstandardtransform(lua_State *L, int idx, const T &func) +{ + if (luax_istype(L, idx, math::Transform::type)) + { + math::Transform *tf = luax_totype(L, idx); + func(tf->getMatrix()); + } + else + { + float x = (float) luaL_optnumber(L, idx + 0, 0.0); + float y = (float) luaL_optnumber(L, idx + 1, 0.0); + float a = (float) luaL_optnumber(L, idx + 2, 0.0); + float sx = (float) luaL_optnumber(L, idx + 3, 1.0); + float sy = (float) luaL_optnumber(L, idx + 4, sx); + float ox = (float) luaL_optnumber(L, idx + 5, 0.0); + float oy = (float) luaL_optnumber(L, idx + 6, 0.0); + float kx = (float) luaL_optnumber(L, idx + 7, 0.0); + float ky = (float) luaL_optnumber(L, idx + 8, 0.0); + func(Matrix4(x, y, a, sx, sy, ox, oy, kx, ky)); + } +} + SpriteBatch *luax_checkspritebatch(lua_State *L, int idx); extern "C" int luaopen_spritebatch(lua_State *L);