diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 1a82fc021..5001e4842 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -191,6 +191,13 @@ public: template void transformXY(Vdst *dst, const Vsrc *src, int size) const; + /** + * Transforms an array of 2-component vertices by this Matrix, and stores + * them in an array of 3-component vertices. + **/ + template + void transformXY0(Vdst *dst, const Vsrc *src, int size) const; + /** * Transforms an array of 3-component vertices by this Matrix. The source * and destination arrays may be the same. @@ -320,6 +327,22 @@ void Matrix4::transformXY(Vdst *dst, const Vsrc *src, int size) const } } +template +void Matrix4::transformXY0(Vdst *dst, const Vsrc *src, int size) const +{ + for (int i = 0; i < size; i++) + { + // Store in temp variables in case src = dst + float x = (e[0]*src[i].x) + (e[4]*src[i].y) + (0) + (e[12]); + float y = (e[1]*src[i].x) + (e[5]*src[i].y) + (0) + (e[13]); + float z = (e[2]*src[i].x) + (e[6]*src[i].y) + (0) + (e[14]); + + dst[i].x = x; + dst[i].y = y; + dst[i].z = z; + } +} + // | x | // | y | // | z | diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 6393b44dc..f6e2ceff6 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -616,16 +616,6 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest & if (state.vertexCount == 0 && Shader::current != nullptr && req.texture != nullptr) Shader::current->checkMainTexture(req.texture); - if (!getTransform().isAffine2DTransform()) - { - for (CommonFormat fmt : req.formats) - { - int components = getFormatPositionComponents(fmt); - if (components > 0 && components < 3) - throw love::Exception("Only affine 2D transforms are supported with auto-batched draws."); - } - } - bool shouldflush = false; bool shouldresize = false; @@ -811,16 +801,21 @@ void Graphics::printf(const std::vector &str, Font *font, f void Graphics::points(const float *coords, const Colorf *colors, size_t numpoints) { + const Matrix4 &t = getTransform(); + bool is2D = t.isAffine2DTransform(); + StreamDrawRequest req; req.primitiveMode = vertex::PrimitiveMode::POINTS; - req.formats[0] = vertex::CommonFormat::XYf; + req.formats[0] = vertex::getSinglePositionFormat(is2D); req.formats[1] = vertex::CommonFormat::RGBAub; req.vertexCount = (int) numpoints; StreamVertexData data = requestStreamDraw(req); - const Matrix4 &t = getTransform(); - t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + if (is2D) + t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + else + t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); Color *colordata = (Color *) data.stream[1]; @@ -1095,16 +1090,21 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count) } else { + const Matrix4 &t = getTransform(); + bool is2D = t.isAffine2DTransform(); + StreamDrawRequest req; - req.formats[0] = vertex::CommonFormat::XYf; + req.formats[0] = vertex::getSinglePositionFormat(is2D); req.formats[1] = vertex::CommonFormat::RGBAub; req.indexMode = vertex::TriangleIndexMode::FAN; req.vertexCount = (int)count/2 - 1; StreamVertexData data = requestStreamDraw(req); - - const Matrix4 &t = getTransform(); - t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + + if (is2D) + t.transformXY((Vector2 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); + else + t.transformXY0((Vector3 *) data.stream[0], (const Vector2 *) coords, req.vertexCount); Color c = toColor(getColor()); Color *colordata = (Color *) data.stream[1]; diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index b6f7c23b8..e049fabee 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -1057,7 +1057,9 @@ bool ParticleSystem::prepareDraw(Graphics *gfx) gfx->flushStreamDraws(); - const vertex::XYf_STf *textureVerts = texture->getQuad()->getVertices(); + const Vector2 *positions = texture->getQuad()->getVertexPositions(); + const Vector2 *texcoords = texture->getQuad()->getVertexTexCoords(); + Vertex *pVerts = (Vertex *) buffer->map(); Particle *p = pHead; @@ -1069,11 +1071,14 @@ bool ParticleSystem::prepareDraw(Graphics *gfx) while (p) { if (useQuads) - textureVerts = quads[p->quadIndex]->getVertices(); + { + positions = quads[p->quadIndex]->getVertexPositions(); + texcoords = quads[p->quadIndex]->getVertexTexCoords(); + } // particle vertices are image vertices transformed by particle info t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f); - t.transformXY(pVerts, textureVerts, 4); + t.transformXY(pVerts, positions, 4); // Particle colors are stored as floats (0-1) but vertex colors are // unsigned bytes (0-255). @@ -1082,8 +1087,8 @@ bool ParticleSystem::prepareDraw(Graphics *gfx) // set the texture coordinate and color data for particle vertices for (int v = 0; v < 4; v++) { - pVerts[v].s = textureVerts[v].s; - pVerts[v].t = textureVerts[v].t; + pVerts[v].s = texcoords[v].x; + pVerts[v].t = texcoords[v].y; pVerts[v].color = c; } diff --git a/src/modules/graphics/Polyline.cpp b/src/modules/graphics/Polyline.cpp index c87d2ce77..ebf651ef5 100644 --- a/src/modules/graphics/Polyline.cpp +++ b/src/modules/graphics/Polyline.cpp @@ -371,16 +371,21 @@ void Polyline::draw(love::graphics::Graphics *gfx) if (overdraw) total_vertex_count = (int) (overdraw_vertex_start + overdraw_vertex_count); + const Matrix4 &t = gfx->getTransform(); + bool is2D = t.isAffine2DTransform(); + Graphics::StreamDrawRequest req; - req.formats[0] = vertex::CommonFormat::XYf; + req.formats[0] = vertex::getSinglePositionFormat(is2D); req.formats[1] = vertex::CommonFormat::RGBAub; req.indexMode = triangle_mode; req.vertexCount = total_vertex_count; Graphics::StreamVertexData data = gfx->requestStreamDraw(req); - const Matrix4 &t = gfx->getTransform(); - t.transformXY((Vector2 *) data.stream[0], vertices, total_vertex_count); + if (is2D) + t.transformXY((Vector2 *) data.stream[0], vertices, total_vertex_count); + else + t.transformXY0((Vector3 *) data.stream[0], vertices, total_vertex_count); Color curcolor = toColor(gfx->getColor()); Color *colordata = (Color *) data.stream[1]; diff --git a/src/modules/graphics/Quad.cpp b/src/modules/graphics/Quad.cpp index 30e8a79fd..616b099ff 100644 --- a/src/modules/graphics/Quad.cpp +++ b/src/modules/graphics/Quad.cpp @@ -53,23 +53,15 @@ void Quad::refresh(const Quad::Viewport &v, double sw, double sh) // 0---2 // | / | // 1---3 - vertices[0].x = 0.0f; - vertices[0].y = 0.0f; - vertices[1].x = 0.0f; - vertices[1].y = (float) v.h; - vertices[2].x = (float) v.w; - vertices[2].y = 0.0f; - vertices[3].x = (float) v.w; - vertices[3].y = (float) v.h; + vertexPositions[0] = Vector2(0.0f, 0.0f); + vertexPositions[1] = Vector2(0.0f, (float) v.h); + vertexPositions[2] = Vector2((float) v.w, 0.0f); + vertexPositions[3] = Vector2((float) v.w, (float) v.h); - vertices[0].s = (float) (v.x / sw); - vertices[0].t = (float) (v.y / sh); - vertices[1].s = (float) (v.x / sw); - vertices[1].t = (float) ((v.y + v.h) / sh); - vertices[2].s = (float) ((v.x + v.w) / sw); - vertices[2].t = (float) (v.y / sh); - vertices[3].s = (float) ((v.x + v.w) / sw); - vertices[3].t = (float) ((v.y + v.h) / sh); + vertexTexCoords[0] = Vector2((float) (v.x / sw), (float) (v.y / sh)); + vertexTexCoords[1] = Vector2((float) (v.x / sw), (float) ((v.y + v.h) / sh)); + vertexTexCoords[2] = Vector2((float) ((v.x + v.w) / sw), (float) (v.y / sh)); + vertexTexCoords[3] = Vector2((float) ((v.x + v.w) / sw), (float) ((v.y + v.h) / sh)); } void Quad::setViewport(const Quad::Viewport &v) @@ -92,11 +84,6 @@ double Quad::getTextureHeight() const return sh; } -const vertex::XYf_STf *Quad::getVertices() const -{ - return vertices; -} - void Quad::setLayer(int layer) { arrayLayer = layer; diff --git a/src/modules/graphics/Quad.h b/src/modules/graphics/Quad.h index 13b6d392a..5b9051d7e 100644 --- a/src/modules/graphics/Quad.h +++ b/src/modules/graphics/Quad.h @@ -24,7 +24,7 @@ // LOVE #include "common/Object.h" #include "common/math.h" -#include "vertex.h" +#include "common/Vector.h" namespace love { @@ -53,14 +53,16 @@ public: double getTextureWidth() const; double getTextureHeight() const; - const vertex::XYf_STf *getVertices() const; + const Vector2 *getVertexPositions() const { return vertexPositions; } + const Vector2 *getVertexTexCoords() const { return vertexTexCoords; } void setLayer(int layer); int getLayer() const; private: - vertex::XYf_STf vertices[4]; + Vector2 vertexPositions[4]; + Vector2 vertexTexCoords[4]; int arrayLayer; diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 302f63013..780d46650 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -91,18 +91,19 @@ int SpriteBatch::add(Quad *quad, const Matrix4 &m, int index /*= -1*/) if (index == -1 && next >= size) setBufferSize(size * 2); - const XYf_STf *quadverts = quad->getVertices(); + const Vector2 *quadpositions = quad->getVertexPositions(); + const Vector2 *quadtexcoords = quad->getVertexTexCoords(); // 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.transformXY(verts, quadverts, 4); + m.transformXY(verts, quadpositions, 4); for (int i = 0; i < 4; i++) { - verts[i].s = quadverts[i].s; - verts[i].t = quadverts[i].t; + verts[i].s = quadtexcoords[i].x; + verts[i].t = quadtexcoords[i].y; verts[i].color = color; } @@ -136,18 +137,19 @@ int SpriteBatch::addLayer(int layer, Quad *quad, const Matrix4 &m, int index) if (index == -1 && next >= size) setBufferSize(size * 2); - const XYf_STf *quadverts = quad->getVertices(); + const Vector2 *quadpositions = quad->getVertexPositions(); + const Vector2 *quadtexcoords = quad->getVertexTexCoords(); // 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.transformXY(verts, quadverts, 4); + m.transformXY(verts, quadpositions, 4); for (int i = 0; i < 4; i++) { - verts[i].s = quadverts[i].s; - verts[i].t = quadverts[i].t; + verts[i].s = quadtexcoords[i].x; + verts[i].t = quadtexcoords[i].y; verts[i].p = (float) layer; verts[i].color = color; } diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index d35e98b5d..a98672f2d 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -122,25 +122,33 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) Color c = toColor(gfx->getColor()); + const Matrix4 &tm = gfx->getTransform(); + bool is2D = tm.isAffine2DTransform(); + + Matrix4 t(tm, localTransform); + Graphics::StreamDrawRequest req; - req.formats[0] = CommonFormat::XYf_STf_RGBAub; + req.formats[0] = vertex::getSinglePositionFormat(is2D); + req.formats[1] = CommonFormat::STf_RGBAub; req.indexMode = TriangleIndexMode::QUADS; req.vertexCount = 4; req.texture = this; Graphics::StreamVertexData data = gfx->requestStreamDraw(req); - XYf_STf_RGBAub *verts = (XYf_STf_RGBAub *) data.stream[0]; - const XYf_STf *quadverts = q->getVertices(); + if (is2D) + t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4); + else + t.transformXY0((Vector3 *) data.stream[0], q->getVertexPositions(), 4); - Matrix4 t(gfx->getTransform(), localTransform); - t.transformXY(verts, quadverts, 4); + const Vector2 *texcoords = q->getVertexTexCoords(); + vertex::STf_RGBAub *vertexdata = (vertex::STf_RGBAub *) data.stream[1]; for (int i = 0; i < 4; i++) { - verts[i].s = quadverts[i].s; - verts[i].t = quadverts[i].t; - verts[i].color = c; + vertexdata[i].s = texcoords[i].x; + vertexdata[i].t = texcoords[i].y; + vertexdata[i].color = c; } } @@ -164,26 +172,34 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m) Color c = toColor(gfx->getColor()); + const Matrix4 &tm = gfx->getTransform(); + bool is2D = tm.isAffine2DTransform(); + + Matrix4 t(tm, m); + Graphics::StreamDrawRequest req; - req.formats[0] = CommonFormat::XYf_STPf_RGBAub; + req.formats[0] = vertex::getSinglePositionFormat(is2D); + req.formats[1] = CommonFormat::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(); + if (is2D) + t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4); + else + t.transformXY0((Vector3 *) data.stream[0], q->getVertexPositions(), 4); - Matrix4 t(gfx->getTransform(), m); - t.transformXY(verts, quadverts, 4); + const Vector2 *texcoords = q->getVertexTexCoords(); + vertex::STPf_RGBAub *vertexdata = (vertex::STPf_RGBAub *) data.stream[1]; 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; + vertexdata[i].s = texcoords[i].x; + vertexdata[i].t = texcoords[i].y; + vertexdata[i].p = (float) layer; + vertexdata[i].color = c; } } diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index bece39873..bd9d67584 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -122,16 +122,25 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) if (Shader::current != nullptr) Shader::current->setVideoTextures(images[0], images[1], images[2]); + const Matrix4 &tm = gfx->getTransform(); + bool is2D = tm.isAffine2DTransform(); + + Matrix4 t(tm, m); + Graphics::StreamDrawRequest req; - req.formats[0] = vertex::CommonFormat::XYf_STf_RGBAub; + req.formats[0] = vertex::getSinglePositionFormat(is2D); + req.formats[1] = vertex::CommonFormat::STf_RGBAub; req.indexMode = vertex::TriangleIndexMode::QUADS; req.vertexCount = 4; Graphics::StreamVertexData data = gfx->requestStreamDraw(req); - Vertex *verts = (Vertex *) data.stream[0]; - Matrix4 t(gfx->getTransform(), m); - t.transformXY(verts, vertices, 4); + if (is2D) + t.transformXY((Vector2 *) data.stream[0], vertices, 4); + else + t.transformXY0((Vector3 *) data.stream[0], vertices, 4); + + vertex::STf_RGBAub *verts = (vertex::STf_RGBAub *) data.stream[1]; Color c = toColor(gfx->getColor()); diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 158a124d2..96a2caa22 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -653,9 +653,20 @@ void OpenGL::setVertexPointers(vertex::CommonFormat format, size_t stride, size_ case CommonFormat::XYf: glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset)); break; + case CommonFormat::XYZf: + glVertexAttribPointer(ATTRIB_POS, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset)); + break; case CommonFormat::RGBAub: glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset)); break; + case CommonFormat::STf_RGBAub: + glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(STf_RGBAub, s))); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(STf_RGBAub, color.r))); + break; + case CommonFormat::STPf_RGBAub: + glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(STPf_RGBAub, s))); + glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(STPf_RGBAub, color.r))); + break; case CommonFormat::XYf_STf: 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))); diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index 39fef1926..36fd84146 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -29,6 +29,8 @@ namespace vertex { static_assert(sizeof(Color) == 4, "sizeof(Color) incorrect!"); +static_assert(sizeof(STf_RGBAub) == sizeof(float)*2 + sizeof(Color), "sizeof(STf_RGBAub) incorrect!"); +static_assert(sizeof(STPf_RGBAub) == sizeof(float)*3 + sizeof(Color), "sizeof(STPf_RGBAub) 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!"); @@ -43,8 +45,14 @@ size_t getFormatStride(CommonFormat format) return 0; case CommonFormat::XYf: return sizeof(float) * 2; + case CommonFormat::XYZf: + return sizeof(float) * 3; case CommonFormat::RGBAub: return sizeof(uint8) * 4; + case CommonFormat::STf_RGBAub: + return sizeof(STf_RGBAub); + case CommonFormat::STPf_RGBAub: + return sizeof(STPf_RGBAub); case CommonFormat::XYf_STf: return sizeof(XYf_STf); case CommonFormat::XYf_STPf: @@ -65,9 +73,13 @@ uint32 getFormatFlags(CommonFormat format) case CommonFormat::NONE: return 0; case CommonFormat::XYf: + case CommonFormat::XYZf: return ATTRIBFLAG_POS; case CommonFormat::RGBAub: return ATTRIBFLAG_COLOR; + case CommonFormat::STf_RGBAub: + case CommonFormat::STPf_RGBAub: + return ATTRIBFLAG_TEXCOORD | ATTRIB_COLOR; case CommonFormat::XYf_STf: case CommonFormat::XYf_STPf: return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD; @@ -75,7 +87,6 @@ uint32 getFormatFlags(CommonFormat format) case CommonFormat::XYf_STus_RGBAub: case CommonFormat::XYf_STPf_RGBAub: return ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR; - } } @@ -85,6 +96,8 @@ int getFormatPositionComponents(CommonFormat format) { case CommonFormat::NONE: case CommonFormat::RGBAub: + case CommonFormat::STf_RGBAub: + case CommonFormat::STPf_RGBAub: return 0; case CommonFormat::XYf: case CommonFormat::XYf_STf: @@ -93,6 +106,8 @@ int getFormatPositionComponents(CommonFormat format) case CommonFormat::XYf_STus_RGBAub: case CommonFormat::XYf_STPf_RGBAub: return 2; + case CommonFormat::XYZf: + return 3; } } diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 061efd84d..ff8e43a1e 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -95,7 +95,10 @@ enum class CommonFormat { NONE, XYf, + XYZf, RGBAub, + STf_RGBAub, + STPf_RGBAub, XYf_STf, XYf_STPf, XYf_STf_RGBAub, @@ -103,6 +106,18 @@ enum class CommonFormat XYf_STPf_RGBAub, }; +struct STf_RGBAub +{ + float s, t; + Color color; +}; + +struct STPf_RGBAub +{ + float s, t, p; + Color color; +}; + struct XYf_STf { float x, y; @@ -142,6 +157,11 @@ uint32 getFormatFlags(CommonFormat format); int getFormatPositionComponents(CommonFormat format); +inline CommonFormat getSinglePositionFormat(bool is2D) +{ + return is2D ? CommonFormat::XYf : CommonFormat::XYZf; +} + size_t getIndexDataSize(IndexDataType type); IndexDataType getIndexDataTypeFromMax(size_t maxvalue);