Implement automatic batching for points, lines, shapes, and images/quads.

The above are batched together into a single draw call when called without other drawing calls in between, as long as the following criteria are met:

- The texture is the same.
- The primitive type is the same (points cannot be batched with non-points).
- The love.graphics state is the same (aside from the current color - i.e. setColor - and the transform state).
- The active shader’s uniform values are the same.

You can examine the ‘drawcalls’ field of love.graphics.getStats() to help determine if your code is allowing for optimum batching.

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2016-12-27 21:02:58 -04:00
parent f98b7ce1ed
commit 0d2e08baff
43 changed files with 1245 additions and 511 deletions
+2
View File
@@ -474,6 +474,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
src/modules/graphics/ParticleSystem.h
src/modules/graphics/Quad.cpp
src/modules/graphics/Quad.h
src/modules/graphics/StreamBuffer.cpp
src/modules/graphics/StreamBuffer.h
src/modules/graphics/Texture.cpp
src/modules/graphics/Texture.h
src/modules/graphics/Volatile.cpp
@@ -876,6 +876,10 @@
FA27B3C61B4985D8008A9DCE /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3C31B4985D8008A9DCE /* Video.cpp */; };
FA27B3C71B4985D8008A9DCE /* Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3C41B4985D8008A9DCE /* Video.h */; };
FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3C81B498623008A9DCE /* Theora.framework */; };
FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */; };
FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; };
FA2AF6751DAD64970032B62C /* vertex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA2AF6731DAD64970032B62C /* vertex.cpp */; };
FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA317EB918F28B6D00B0BCD7 /* libz.dylib */; };
FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
@@ -1311,13 +1315,13 @@
FA0B7B861A95902C000E1D17 /* wrap_Rasterizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Rasterizer.h; sourceTree = "<group>"; };
FA0B7B881A95902C000E1D17 /* Color.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Color.h; sourceTree = "<group>"; };
FA0B7B891A95902C000E1D17 /* Drawable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Drawable.h; sourceTree = "<group>"; };
FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Graphics.cpp; sourceTree = "<group>"; };
FA0B7B8A1A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
FA0B7B8B1A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
FA0B7B8D1A95902C000E1D17 /* Canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Canvas.cpp; sourceTree = "<group>"; };
FA0B7B8E1A95902C000E1D17 /* Canvas.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Canvas.h; sourceTree = "<group>"; };
FA0B7B8F1A95902C000E1D17 /* Font.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Font.cpp; sourceTree = "<group>"; };
FA0B7B901A95902C000E1D17 /* Font.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Font.h; sourceTree = "<group>"; };
FA0B7B911A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Graphics.cpp; sourceTree = "<group>"; };
FA0B7B911A95902C000E1D17 /* Graphics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Graphics.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
FA0B7B921A95902C000E1D17 /* Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Graphics.h; sourceTree = "<group>"; };
FA0B7B931A95902C000E1D17 /* Image.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Image.cpp; sourceTree = "<group>"; };
FA0B7B941A95902C000E1D17 /* Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Image.h; sourceTree = "<group>"; };
@@ -1357,7 +1361,7 @@
FA0B7BB91A95902C000E1D17 /* wrap_Text.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Text.h; sourceTree = "<group>"; };
FA0B7BBC1A95902C000E1D17 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = "<group>"; };
FA0B7BBD1A95902C000E1D17 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = "<group>"; };
FA0B7BBE1A95902C000E1D17 /* Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Texture.cpp; sourceTree = "<group>"; };
FA0B7BBE1A95902C000E1D17 /* Texture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = Texture.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
FA0B7BBF1A95902C000E1D17 /* Texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Texture.h; sourceTree = "<group>"; };
FA0B7BC01A95902C000E1D17 /* Volatile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Volatile.cpp; sourceTree = "<group>"; };
FA0B7BC11A95902C000E1D17 /* Volatile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Volatile.h; sourceTree = "<group>"; };
@@ -1626,6 +1630,10 @@
FA27B3C81B498623008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StreamBuffer.cpp; sourceTree = "<group>"; };
FA2AF6711DAC76FF0032B62C /* vertex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vertex.h; sourceTree = "<group>"; };
FA2AF6721DAD62710032B62C /* StreamBuffer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StreamBuffer.h; sourceTree = "<group>"; };
FA2AF6731DAD64970032B62C /* vertex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vertex.cpp; sourceTree = "<group>"; };
FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_RandomGenerator.lua; sourceTree = "<group>"; };
FA317EB918F28B6D00B0BCD7 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTCHandler.cpp; sourceTree = "<group>"; };
@@ -2431,8 +2439,12 @@
FAE272511C05A15B00A67640 /* ParticleSystem.h */,
FA0B7BBC1A95902C000E1D17 /* Quad.cpp */,
FA0B7BBD1A95902C000E1D17 /* Quad.h */,
FA29C0041E12355B00268CD8 /* StreamBuffer.cpp */,
FA2AF6721DAD62710032B62C /* StreamBuffer.h */,
FA0B7BBE1A95902C000E1D17 /* Texture.cpp */,
FA0B7BBF1A95902C000E1D17 /* Texture.h */,
FA2AF6731DAD64970032B62C /* vertex.cpp */,
FA2AF6711DAC76FF0032B62C /* vertex.h */,
FA0B7BC01A95902C000E1D17 /* Volatile.cpp */,
FA0B7BC11A95902C000E1D17 /* Volatile.h */,
FA620A2E1AA2F8DB005DB4C2 /* wrap_Quad.cpp */,
@@ -3675,6 +3687,7 @@
FA0B7DAC1A95902C000E1D17 /* STBHandler.cpp in Sources */,
FA0B79301A958E3B000E1D17 /* Module.cpp in Sources */,
FA0B7DDA1A95902C000E1D17 /* RandomGenerator.cpp in Sources */,
FA2AF6751DAD64970032B62C /* vertex.cpp in Sources */,
FA0B7D801A95902C000E1D17 /* Volatile.cpp in Sources */,
FA0B792D1A958E3B000E1D17 /* Memoizer.cpp in Sources */,
FA0B7EBC1A95902C000E1D17 /* LuaThread.cpp in Sources */,
@@ -3778,6 +3791,7 @@
FAB17BF61ABFC4B100F9BA27 /* lz4hc.c in Sources */,
FA0B7EA71A95902C000E1D17 /* wrap_Decoder.cpp in Sources */,
FA0B7E1C1A95902C000E1D17 /* MouseJoint.cpp in Sources */,
FA29C0061E12355B00268CD8 /* StreamBuffer.cpp in Sources */,
FA0B7CF51A95902C000E1D17 /* File.cpp in Sources */,
FA0B7E341A95902C000E1D17 /* WeldJoint.cpp in Sources */,
FA4F2C091DE936E200CA37D7 /* luasocket.c in Sources */,
@@ -3989,6 +4003,7 @@
FA0B7AB81A958EA3000E1D17 /* enet.cpp in Sources */,
FA0B7DD91A95902C000E1D17 /* RandomGenerator.cpp in Sources */,
FA0B7A9B1A958EA3000E1D17 /* b2MouseJoint.cpp in Sources */,
FA2AF6741DAD64970032B62C /* vertex.cpp in Sources */,
FA0B7D7F1A95902C000E1D17 /* Volatile.cpp in Sources */,
FA0B7A3B1A958EA3000E1D17 /* b2TimeOfImpact.cpp in Sources */,
217DFBED1D9F6D490055D849 /* luasocket.c in Sources */,
@@ -4092,6 +4107,7 @@
FA0B7D5B1A95902C000E1D17 /* wrap_Font.cpp in Sources */,
FA0B7D301A95902C000E1D17 /* Graphics.cpp in Sources */,
FA0B7E9D1A95902C000E1D17 /* WaveDecoder.cpp in Sources */,
FA29C0051E12355B00268CD8 /* StreamBuffer.cpp in Sources */,
FA0B7EB21A95902C000E1D17 /* System.cpp in Sources */,
FA0B7D1B1A95902C000E1D17 /* GlyphData.cpp in Sources */,
FA0B7AD11A958EA3000E1D17 /* protocol.c in Sources */,
+1 -1
View File
@@ -97,7 +97,7 @@ Matrix4::~Matrix4()
Matrix4 Matrix4::operator * (const Matrix4 &m) const
{
Matrix4 t;
multiply(*this, m, t);
multiply(*this, m, t.e);
return t;
}
+8 -1
View File
@@ -86,6 +86,8 @@ public:
**/
Vector getNormal(float scale) const;
float cross(const Vector &v) const;
/**
* Adds a Vector to this Vector.
* @param v The Vector we want to add to this Vector.
@@ -200,6 +202,11 @@ inline Vector Vector::getNormal(float scale) const
return Vector(-y * scale, x * scale);
}
inline float Vector::cross(const Vector &v) const
{
return x * v.getY() - y * v.getX();
}
inline float Vector::normalize(float length)
{
@@ -283,7 +290,7 @@ inline float Vector::operator * (const Vector &v) const
inline float Vector::operator ^ (const Vector &v) const
{
return x * v.getY() - y * v.getX();
return cross(v);
}
inline bool Vector::operator == (const Vector &v) const
-7
View File
@@ -72,13 +72,6 @@ struct Rect
}
};
struct Vertex
{
float x, y;
float s, t;
unsigned char r, g, b, a;
};
inline int nextP2(int x)
{
x += (x == 0);
+35
View File
@@ -48,6 +48,7 @@ struct ColorT
bool operator!=(const ColorT<T> &other) const;
ColorT<T> operator+=(const ColorT<T> &other);
ColorT<T> operator*=(const ColorT<T> &other);
ColorT<T> operator*=(T s);
ColorT<T> operator/=(T s);
};
@@ -74,6 +75,16 @@ ColorT<T> ColorT<T>::operator+=(const ColorT<T> &other)
return *this;
}
template <typename T>
ColorT<T> ColorT<T>::operator*=(const ColorT<T> &other)
{
r *= other.r;
g *= other.g;
b *= other.b;
a *= other.a;
return *this;
}
template <typename T>
ColorT<T> ColorT<T>::operator*=(T s)
{
@@ -101,6 +112,17 @@ ColorT<T> operator+(const ColorT<T> &a, const ColorT<T> &b)
return tmp += b;
}
template <typename T>
ColorT<T> operator*(const ColorT<T> &a, const ColorT<T> &b)
{
ColorT<T> res;
res.r = a.r * b.r;
res.g = a.g * b.g;
res.b = a.b * b.b;
res.a = a.a * b.a;
return res;
}
template <typename T>
ColorT<T> operator*(const ColorT<T> &a, T s)
{
@@ -118,6 +140,19 @@ ColorT<T> operator/(const ColorT<T> &a, T s)
typedef ColorT<unsigned char> Color;
typedef ColorT<float> Colorf;
inline Color toColor(Colorf cf)
{
return Color((unsigned char) (cf.r * 255.0f),
(unsigned char) (cf.g * 255.0f),
(unsigned char) (cf.b * 255.0f),
(unsigned char) (cf.a * 255.0f));
}
inline Colorf toColorf(Color c)
{
return Colorf(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f);
}
} // graphics
} // love
+3 -1
View File
@@ -30,6 +30,8 @@ namespace love
namespace graphics
{
class Graphics;
/**
* A Drawable is anything that can be drawn on screen with a
* position, scale and orientation.
@@ -48,7 +50,7 @@ public:
/**
* Draws the object with the specified transformation matrix.
**/
virtual void draw(const Matrix4 &m) = 0;
virtual void draw(Graphics *gfx, const Matrix4 &m) = 0;
};
} // graphics
+153 -7
View File
@@ -60,8 +60,154 @@ void unGammaCorrectColor(Colorf &c)
love::Type Graphics::type("graphics", &Module::type);
Graphics::Graphics()
: streamBufferState()
, projectionMatrix()
{
transformStack.reserve(16);
transformStack.push_back(Matrix4());
}
Graphics::~Graphics()
{
delete streamBufferState.vb[0];
delete streamBufferState.vb[1];
delete streamBufferState.indexBuffer;
}
Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &req)
{
using namespace vertex;
StreamBufferState &state = streamBufferState;
bool shouldflush = false;
bool shouldresize = false;
if (req.primitiveMode != state.primitiveMode
|| req.formats[0] != state.formats[0] || req.formats[1] != state.formats[1]
|| ((req.indexMode != TriangleIndexMode::NONE) != (state.indexCount > 0))
|| req.texture != state.texture)
{
shouldflush = true;
}
int totalvertices = state.vertexCount + req.vertexCount;
if (totalvertices > LOVE_UINT16_MAX && req.indexMode != TriangleIndexMode::NONE)
shouldflush = true;
int reqIndexCount = getIndexCount(req.indexMode, req.vertexCount);
size_t reqIndexSize = reqIndexCount * sizeof(uint16);
size_t newdatasizes[2] = {0, 0};
size_t buffersizes[3] = {0, 0, 0};
for (int i = 0; i < 2; i++)
{
if (req.formats[i] != CommonFormat::NONE)
{
size_t stride = getFormatStride(req.formats[i]);
size_t datasize = stride * totalvertices;
size_t cursize = state.vb[i]->getSize();
if (datasize > cursize)
{
shouldflush = true;
if (stride * req.vertexCount > cursize)
{
buffersizes[i] = std::max(datasize, cursize * 2);
shouldresize = true;
}
}
newdatasizes[i] = stride * req.vertexCount;
}
}
{
size_t datasize = (state.indexCount + reqIndexCount) * sizeof(uint16);
size_t cursize = state.indexBuffer->getSize();
if (datasize > cursize)
{
shouldflush = true;
if (reqIndexSize > cursize)
{
buffersizes[2] = std::max(datasize, cursize * 2);
shouldresize = true;
}
}
}
if (shouldflush)
{
flushStreamDraws();
state.primitiveMode = req.primitiveMode;
state.formats[0] = req.formats[0];
state.formats[1] = req.formats[1];
state.texture = req.texture;
}
if (shouldresize)
{
for (int i = 0; i < 2; i++)
{
if (state.vb[i]->getSize() < buffersizes[i])
state.vb[i]->setSize(buffersizes[i]);
}
if (state.indexBuffer->getSize() < buffersizes[2])
state.indexBuffer->setSize(buffersizes[2]);
}
if (req.indexMode != TriangleIndexMode::NONE)
{
uint16 *indices = (uint16 *) state.indexBuffer->getOffsetData();
fillIndices(req.indexMode, state.vertexCount, req.vertexCount, indices);
state.indexBuffer->incrementOffset(reqIndexSize);
}
StreamVertexData d;
d.stream[0] = state.vb[0]->getOffsetData();
d.stream[1] = state.vb[1]->getOffsetData();
state.vertexCount += req.vertexCount;
state.indexCount += reqIndexCount;
state.vb[0]->incrementOffset(newdatasizes[0]);
state.vb[1]->incrementOffset(newdatasizes[1]);
return d;
}
const Matrix4 &Graphics::getTransform() const
{
return transformStack.back();
}
const Matrix4 &Graphics::getProjection() const
{
return projectionMatrix;
}
void Graphics::pushTransform()
{
transformStack.push_back(transformStack.back());
}
void Graphics::pushIdentityTransform()
{
transformStack.push_back(Matrix4());
}
void Graphics::popTransform()
{
transformStack.pop_back();
}
bool Graphics::getConstant(const char *in, DrawMode &out)
@@ -232,12 +378,12 @@ StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(
StringMap<Graphics::StencilAction, Graphics::STENCIL_MAX_ENUM>::Entry Graphics::stencilActionEntries[] =
{
{ "replace", STENCIL_REPLACE },
{ "increment", STENCIL_INCREMENT },
{ "decrement", STENCIL_DECREMENT },
{ "replace", STENCIL_REPLACE },
{ "increment", STENCIL_INCREMENT },
{ "decrement", STENCIL_DECREMENT },
{ "incrementwrap", STENCIL_INCREMENT_WRAP },
{ "decrementwrap", STENCIL_DECREMENT_WRAP },
{ "invert", STENCIL_INVERT },
{ "invert", STENCIL_INVERT },
};
StringMap<Graphics::StencilAction, Graphics::STENCIL_MAX_ENUM> Graphics::stencilActions(Graphics::stencilActionEntries, sizeof(Graphics::stencilActionEntries));
@@ -258,8 +404,8 @@ StringMap<Graphics::CompareMode, Graphics::COMPARE_MAX_ENUM> Graphics::compareMo
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featureEntries[] =
{
{ "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS },
{ "clampzero", FEATURE_CLAMP_ZERO },
{ "lighten", FEATURE_LIGHTEN },
{ "clampzero", FEATURE_CLAMP_ZERO },
{ "lighten", FEATURE_LIGHTEN },
{ "fullnpot", FEATURE_FULL_NPOT },
{ "pixelshaderhighp", FEATURE_PIXEL_SHADER_HIGHP },
};
@@ -279,7 +425,7 @@ StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM> Graphics::systemLimit
StringMap<Graphics::StackType, Graphics::STACK_MAX_ENUM>::Entry Graphics::stackTypeEntries[] =
{
{ "all", STACK_ALL },
{ "all", STACK_ALL },
{ "transform", STACK_TRANSFORM },
};
+88
View File
@@ -24,10 +24,14 @@
// LOVE
#include "common/Module.h"
#include "common/StringMap.h"
#include "StreamBuffer.h"
#include "vertex.h"
#include "Color.h"
#include "Texture.h"
// C++
#include <string>
#include <vector>
namespace love
{
@@ -222,6 +226,47 @@ public:
bool enabled;
};
struct StreamDrawRequest
{
vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES;
vertex::CommonFormat formats[2] = {vertex::CommonFormat::NONE, vertex::CommonFormat::NONE};
vertex::TriangleIndexMode indexMode = vertex::TriangleIndexMode::NONE;
int vertexCount = 0;
Texture *texture = nullptr;
};
struct StreamVertexData
{
void *stream[2];
};
class TempTransform
{
public:
TempTransform(Graphics *gfx)
: gfx(gfx)
{
gfx->pushTransform();
}
TempTransform(Graphics *gfx, const Matrix4 &t)
: gfx(gfx)
{
gfx->pushTransform();
gfx->transformStack.back() *= t;
}
~TempTransform()
{
gfx->popTransform();
}
private:
Graphics *gfx;
};
Graphics();
virtual ~Graphics();
// Implements Module.
@@ -261,6 +306,25 @@ public:
virtual bool isCanvasActive() const = 0;
virtual void flushStreamDraws() = 0;
StreamVertexData requestStreamDraw(const StreamDrawRequest &request);
virtual Colorf getColor() const = 0;
const Matrix4 &getTransform() const;
const Matrix4 &getProjection() const;
template <typename T>
T *getScratchBuffer(size_t count)
{
size_t bytes = sizeof(T) * count;
if (scratchBuffer.size() < bytes)
scratchBuffer.resize(bytes);
return (T *) scratchBuffer.data();
}
static bool getConstant(const char *in, DrawMode &out);
static bool getConstant(DrawMode in, const char *&out);
@@ -294,8 +358,32 @@ public:
static bool getConstant(const char *in, StackType &out);
static bool getConstant(StackType in, const char *&out);
protected:
struct StreamBufferState
{
StreamBuffer *vb[2];
StreamBuffer *indexBuffer;
vertex::PrimitiveMode primitiveMode;
vertex::CommonFormat formats[2];
StrongRef<Texture> texture;
int vertexCount;
int indexCount;
};
void pushTransform();
void pushIdentityTransform();
void popTransform();
StreamBufferState streamBufferState;
std::vector<Matrix4> transformStack;
Matrix4 projectionMatrix;
private:
std::vector<uint8> scratchBuffer;
static StringMap<DrawMode, DRAW_MAX_ENUM>::Entry drawModeEntries[];
static StringMap<DrawMode, DRAW_MAX_ENUM> drawModes;
+1
View File
@@ -24,6 +24,7 @@
// LOVE
#include "common/Object.h"
#include "common/math.h"
#include "vertex.h"
namespace love
{
+80
View File
@@ -0,0 +1,80 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "StreamBuffer.h"
#include "common/Exception.h"
namespace love
{
namespace graphics
{
StreamBuffer::StreamBuffer(Mode mode, size_t size)
: data(nullptr)
, offset(0)
, totalSize(size)
, mode(mode)
{
setSize(size);
}
StreamBuffer::~StreamBuffer()
{
delete[] data;
}
void *StreamBuffer::getData() const
{
return data;
}
void *StreamBuffer::getOffsetData() const
{
return data + offset;
}
void StreamBuffer::incrementOffset(size_t amount)
{
offset += amount;
}
void StreamBuffer::resetOffset()
{
offset = 0;
}
void StreamBuffer::setSize(size_t size)
{
delete[] data;
try
{
data = new uint8[size];
}
catch (std::exception &)
{
throw love::Exception("Out of memory.");
}
this->totalSize = size;
}
} // graphics
} // love
+77
View File
@@ -0,0 +1,77 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#pragma once
// LOVE
#include "common/int.h"
// C
#include <cstddef>
namespace love
{
namespace graphics
{
// TODO: This class will need to be changed significantly in the future to
// accomodate non-client-side vertex/index data.
class StreamBuffer
{
public:
enum Mode
{
MODE_VERTEX,
MODE_INDEX,
};
StreamBuffer(Mode mode, size_t size);
~StreamBuffer();
void *getData() const;
void *getOffsetData() const;
void incrementOffset(size_t amount);
void resetOffset();
void setSize(size_t size);
size_t getSize() const
{
return totalSize;
}
Mode getMode() const
{
return mode;
}
private:
uint8 *data;
size_t offset;
size_t totalSize;
Mode mode;
}; // StreamBuffer
} // graphics
} // love
+33
View File
@@ -19,6 +19,7 @@
**/
#include "Texture.h"
#include "Graphics.h"
namespace love
{
@@ -47,6 +48,38 @@ PixelFormat Texture::getPixelFormat() const
return format;
}
void Texture::draw(Graphics *gfx, const Matrix4 &m)
{
drawv(gfx, m, vertices);
}
void Texture::drawq(Graphics *gfx, Quad *quad, const Matrix4 &m)
{
drawv(gfx, m, quad->getVertices());
}
void Texture::drawv(Graphics *gfx, const Matrix4 &localTransform, const Vertex *v)
{
Matrix4 t = gfx->getTransform() * localTransform;
Vertex verts[4] = {v[0], v[1], v[2], v[3]};
t.transform(verts, v, 4);
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.vertexCount = 4;
req.texture = this;
Graphics::StreamVertexData data = gfx->requestStreamDraw(req);
memcpy(data.stream[0], verts, sizeof(Vertex) * 4);
}
int Texture::getWidth() const
{
return width;
+11 -2
View File
@@ -27,6 +27,10 @@
#include "common/pixelformat.h"
#include "Drawable.h"
#include "Quad.h"
#include "vertex.h"
// C
#include <stddef.h>
namespace love
{
@@ -77,10 +81,13 @@ public:
Texture();
virtual ~Texture();
// Drawable.
void draw(Graphics *gfx, const Matrix4 &m) override;
/**
* Draws the texture using the specified transformation with a Quad applied.
**/
virtual void drawq(Quad *quad, const Matrix4 &m) = 0;
void drawq(Graphics *gfx, Quad *quad, const Matrix4 &m);
PixelFormat getPixelFormat() const;
@@ -95,7 +102,7 @@ public:
virtual const Vertex *getVertices() const;
virtual const void *getHandle() const = 0;
virtual ptrdiff_t getHandle() const = 0;
// The default filter.
static void setDefaultFilter(const Filter &f);
@@ -111,6 +118,8 @@ public:
protected:
virtual void drawv(Graphics *gfx, const Matrix4 &localTransform, const Vertex *v);
PixelFormat format;
int width;
+7 -30
View File
@@ -250,37 +250,14 @@ void Canvas::unloadVolatile()
texture_memory = 0;
}
void Canvas::drawv(const Matrix4 &t, const Vertex *v)
void Canvas::drawv(love::graphics::Graphics *gfx, const Matrix4 &localTransform, const Vertex *v)
{
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && gfx->isCanvasActive(this))
Graphics *glgfx = (Graphics *) gfx;
if (glgfx != nullptr && glgfx->isCanvasActive(this))
throw love::Exception("Cannot render a Canvas to itself!");
OpenGL::TempDebugGroup debuggroup("Canvas draw");
OpenGL::TempTransform transform(gl);
transform.get() *= t;
gl.bindTextureToUnit(texture, 0, false);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
gl.bindBuffer(BUFFER_VERTEX, 0);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s);
gl.prepareDraw();
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void Canvas::draw(const Matrix4 &m)
{
drawv(m, vertices);
}
void Canvas::drawq(Quad *quad, const Matrix4 &m)
{
drawv(m, quad->getVertices());
Texture::drawv(gfx, localTransform, v);
}
void Canvas::setFilter(const Texture::Filter &f)
@@ -322,9 +299,9 @@ bool Canvas::setWrap(const Texture::Wrap &w)
return success;
}
const void *Canvas::getHandle() const
ptrdiff_t Canvas::getHandle() const
{
return &texture;
return texture;
}
love::image::ImageData *Canvas::newImageData(love::image::Image *module, int x, int y, int w, int h)
+2 -6
View File
@@ -52,14 +52,10 @@ public:
bool loadVolatile() override;
void unloadVolatile() override;
// Implements Drawable.
void draw(const Matrix4 &m) override;
// Implements Texture.
void drawq(Quad *quad, const Matrix4 &m) override;
void setFilter(const Texture::Filter &f) override;
bool setWrap(const Texture::Wrap &w) override;
const void *getHandle() const override;
ptrdiff_t getHandle() const override;
love::image::ImageData *newImageData(love::image::Image *module, int x, int y, int w, int h);
@@ -97,7 +93,7 @@ public:
private:
void drawv(const Matrix4 &t, const Vertex *v);
void drawv(Graphics *gfx, const Matrix4 &t, const Vertex *v) override;
GLuint fbo;
+10 -9
View File
@@ -431,7 +431,9 @@ std::vector<Font::DrawCommand> Font::generateVertices(const ColoredCodepoints &c
uint32 prevglyph = 0;
Color curcolor(255, 255, 255, 255);
Color initialcolor(255, 255, 255, 255);
Color curcolor = initialcolor;
int curcolori = -1;
int ncolors = (int) codepoints.colors.size();
@@ -441,11 +443,7 @@ std::vector<Font::DrawCommand> Font::generateVertices(const ColoredCodepoints &c
if (curcolori + 1 < ncolors && codepoints.colors[curcolori + 1].index == i)
{
const Colorf &c = codepoints.colors[++curcolori].color;
curcolor.r = (unsigned char) (c.r * 255.0f);
curcolor.g = (unsigned char) (c.g * 255.0f);
curcolor.b = (unsigned char) (c.b * 255.0f);
curcolor.a = (unsigned char) (c.a * 255.0f);
curcolor = toColor(codepoints.colors[++curcolori].color);
}
if (g == '\n')
@@ -478,7 +476,7 @@ std::vector<Font::DrawCommand> Font::generateVertices(const ColoredCodepoints &c
vertices.resize(vertstartsize);
prevglyph = 0;
curcolori = -1;
curcolor = Color(255, 255, 255, 255);
curcolor = initialcolor;
continue;
}
@@ -689,10 +687,13 @@ void Font::printv(const Matrix4 &t, const std::vector<DrawCommand> &drawcommands
if (vertices.empty() || drawcommands.empty())
return;
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
gfx->flushStreamDraws();
OpenGL::TempDebugGroup debuggroup("Font print");
OpenGL::TempTransform transform(gl);
transform.get() *= t;
Graphics::TempTransform transform(gfx, t);
gl.bindBuffer(BUFFER_VERTEX, 0);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(GlyphVertex), &vertices[0].x);
+3 -15
View File
@@ -21,6 +21,7 @@
#include "GLBuffer.h"
#include "common/Exception.h"
#include "graphics/vertex.h"
#include <cstdlib>
#include <cstring>
@@ -362,22 +363,9 @@ const void *QuadIndices::getIndices(size_t offset) const
template <typename T>
void QuadIndices::fill()
{
T *inds = (T *) indices;
using namespace love::graphics::vertex;
// 0----2
// | / |
// | / |
// 1----3
for (size_t i = 0; i < maxSize; ++i)
{
inds[i*6+0] = T(i * 4 + 0);
inds[i*6+1] = T(i * 4 + 1);
inds[i*6+2] = T(i * 4 + 2);
inds[i*6+3] = T(i * 4 + 2);
inds[i*6+4] = T(i * 4 + 1);
inds[i*6+5] = T(i * 4 + 3);
}
fillIndices(TriangleIndexMode::QUADS, 0, maxSize * 4, (T *) indices);
indexBuffer->fill(0, indexBuffer->getSize(), indices);
}
+236 -55
View File
@@ -232,7 +232,7 @@ void Graphics::setViewportSize(int width, int height)
gl.setViewport({0, 0, width, height}, false);
// Set up the projection matrix
gl.matrices.projection = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
}
}
@@ -289,6 +289,15 @@ bool Graphics::setMode(int width, int height)
setDebug(enabledebug);
if (streamBufferState.vb[0] == nullptr)
{
// Initial sizes that should be good enough for most cases. It will
// resize to fit if needed, later.
streamBufferState.vb[0] = new StreamBuffer(StreamBuffer::MODE_VERTEX, 1024 * 1024 * 1);
streamBufferState.vb[1] = new StreamBuffer(StreamBuffer::MODE_VERTEX, 256 * 1024 * 1);
streamBufferState.indexBuffer = new StreamBuffer(StreamBuffer::MODE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
}
// Reload all volatile objects.
if (!Volatile::loadAll())
::printf("Could not reload all volatile objects.\n");
@@ -339,6 +348,8 @@ void Graphics::unSetMode()
if (!isCreated())
return;
flushStreamDraws();
// Unload all volatile objects. These must be reloaded after the display
// mode change.
Volatile::unloadAll();
@@ -359,6 +370,8 @@ void Graphics::unSetMode()
void Graphics::setActive(bool enable)
{
flushStreamDraws();
// Make sure all pending OpenGL commands have fully executed before
// returning, when going from active to inactive. This is required on iOS.
if (isCreated() && this->active && !enable)
@@ -375,6 +388,113 @@ bool Graphics::isActive() const
return active && isCreated() && window != nullptr && window->isOpen();
}
void Graphics::flushStreamDraws()
{
using namespace vertex;
const auto &sbstate = streamBufferState;
if (sbstate.vertexCount == 0 && sbstate.indexCount == 0)
return;
OpenGL::TempDebugGroup debuggroup("Stream vertices flush and draw");
uint32 attribs = 0;
for (int i = 0; i < 2; i++)
{
if (sbstate.formats[i] == CommonFormat::NONE)
continue;
StreamBuffer *buffer = sbstate.vb[i];
buffer->resetOffset();
ptrdiff_t offset = (ptrdiff_t) buffer->getData();
GLsizei stride = (GLsizei) getFormatStride(sbstate.formats[i]);
gl.bindBuffer(BUFFER_VERTEX, 0);
switch (sbstate.formats[i])
{
case CommonFormat::NONE:
break;
case CommonFormat::XYf:
attribs |= ATTRIBFLAG_POS;
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset));
break;
case CommonFormat::RGBAub:
attribs |= ATTRIBFLAG_COLOR;
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset));
break;
case CommonFormat::XYf_STf:
attribs |= ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
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_STf_RGBAub:
attribs |= ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR;
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)));
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, color.r)));
break;
case CommonFormat::XYf_STus_RGBAub:
attribs |= ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR;
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, x)));
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;
}
}
if (attribs == 0)
return;
GLenum glmode = GL_ZERO;
switch (sbstate.primitiveMode)
{
case PrimitiveMode::TRIANGLES:
glmode = GL_TRIANGLES;
break;
case PrimitiveMode::POINTS:
glmode = GL_POINTS;
break;
}
if (attribs & ATTRIBFLAG_COLOR)
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, 1.0f, 1.0f, 1.0f, 1.0f);
pushIdentityTransform();
gl.prepareDraw();
gl.bindTextureToUnit(sbstate.texture, 0, false);
gl.useVertexAttribArrays(attribs);
if (sbstate.indexCount > 0)
{
sbstate.indexBuffer->resetOffset();
ptrdiff_t offset = (ptrdiff_t) sbstate.indexBuffer->getData();
gl.bindBuffer(BUFFER_INDEX, 0);
gl.drawElements(glmode, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset));
}
else
gl.drawArrays(glmode, 0, sbstate.vertexCount);
popTransform();
if (attribs & ATTRIB_CONSTANTCOLOR)
{
Colorf nc = states.back().gammaCorrectedColor;
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, nc.r, nc.g, nc.b, nc.a);
}
streamBufferState.vertexCount = 0;
streamBufferState.indexCount = 0;
}
static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/)
{
// Human-readable strings for the debug info.
@@ -513,7 +633,7 @@ void Graphics::setCanvas(const std::vector<Canvas *> &canvases)
int h = firstcanvas->getHeight();
gl.setViewport({0, 0, w, h}, true);
gl.matrices.projection = Matrix4::ortho(0.0, (float) w, 0.0, (float) h);
projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h);
// Make sure the correct sRGB setting is used when drawing to the canvases.
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
@@ -564,7 +684,7 @@ void Graphics::setCanvas()
// The projection matrix is flipped compared to rendering to a canvas, due
// to OpenGL considering (0,0) bottom-left instead of top-left.
gl.matrices.projection = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0);
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
{
@@ -590,6 +710,8 @@ std::vector<Canvas *> Graphics::getCanvas() const
void Graphics::endPass()
{
flushStreamDraws();
// Discard the stencil buffer.
discard({}, true);
@@ -617,6 +739,8 @@ void Graphics::endPass()
void Graphics::clear(Colorf c)
{
flushStreamDraws();
gammaCorrectColor(c);
glClearColor(c.r, c.g, c.b, c.a);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -646,6 +770,8 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors)
return;
}
flushStreamDraws();
bool drawbuffersmodified = false;
for (int i = 0; i < ncolors; i++)
@@ -712,6 +838,7 @@ bool Graphics::isCanvasActive(Canvas *canvas) const
void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
{
flushStreamDraws();
discard(OpenGL::FRAMEBUFFER_ALL, colorbuffers, depthstencil);
}
@@ -799,7 +926,7 @@ void Graphics::bindCachedFBO(const std::vector<Canvas *> &canvases)
}
else
{
GLuint tex = *(GLuint *) canvases[i]->getHandle();
GLuint tex = (GLuint) canvases[i]->getHandle();
glFramebufferTexture2D(GL_FRAMEBUFFER, drawbuffers[i], GL_TEXTURE_2D, tex, 0);
}
}
@@ -1047,6 +1174,8 @@ bool Graphics::isCreated() const
void Graphics::setScissor(const Rect &rect)
{
flushStreamDraws();
DisplayState &state = states.back();
glEnable(GL_SCISSOR_TEST);
@@ -1081,6 +1210,7 @@ void Graphics::intersectScissor(const Rect &rect)
void Graphics::setScissor()
{
flushStreamDraws();
states.back().scissor = false;
glDisable(GL_SCISSOR_TEST);
}
@@ -1135,6 +1265,8 @@ void Graphics::stopDrawToStencilBuffer()
if (!writingToStencil)
return;
flushStreamDraws();
writingToStencil = false;
const DisplayState &state = states.back();
@@ -1324,11 +1456,17 @@ bool Graphics::isGammaCorrect() const
void Graphics::setColor(Colorf c)
{
c.r = std::min(std::max(c.r, 0.0f), 1.0f);
c.g = std::min(std::max(c.g, 0.0f), 1.0f);
c.b = std::min(std::max(c.b, 0.0f), 1.0f);
c.a = std::min(std::max(c.a, 0.0f), 1.0f);
Colorf nc = c;
gammaCorrectColor(nc);
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, nc.r, nc.g, nc.b, nc.a);
states.back().color = c;
states.back().gammaCorrectedColor = nc;
}
Colorf Graphics::getColor() const
@@ -1350,7 +1488,6 @@ void Graphics::setFont(Font *font)
{
// We don't need to set a default font here if null is passed in, since we
// only care about the default font in getFont and print.
DisplayState &state = states.back();
state.font.set(font);
}
@@ -1366,6 +1503,8 @@ void Graphics::setShader(Shader *shader)
if (shader == nullptr)
return setShader();
flushStreamDraws();
DisplayState &state = states.back();
shader->attach();
@@ -1375,6 +1514,8 @@ void Graphics::setShader(Shader *shader)
void Graphics::setShader()
{
flushStreamDraws();
DisplayState &state = states.back();
// This will activate the default shader.
@@ -1390,6 +1531,8 @@ Shader *Graphics::getShader() const
void Graphics::setColorMask(ColorMask mask)
{
flushStreamDraws();
glColorMask(mask.r, mask.g, mask.b, mask.a);
states.back().colorMask = mask;
}
@@ -1401,6 +1544,8 @@ Graphics::ColorMask Graphics::getColorMask() const
void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
{
flushStreamDraws();
GLenum func = GL_FUNC_ADD;
GLenum srcRGB = GL_ONE;
GLenum srcA = GL_ONE;
@@ -1538,6 +1683,9 @@ Graphics::LineJoin Graphics::getLineJoin() const
void Graphics::setPointSize(float size)
{
if (streamBufferState.primitiveMode == vertex::PrimitiveMode::POINTS)
flushStreamDraws();
gl.setPointSize(size);
states.back().pointSize = size;
}
@@ -1553,6 +1701,8 @@ void Graphics::setWireframe(bool enable)
if (GLAD_ES_VERSION_2_0)
return;
flushStreamDraws();
glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
states.back().wireframe = enable;
}
@@ -1564,12 +1714,12 @@ bool Graphics::isWireframe() const
void Graphics::draw(Drawable *drawable, const Matrix4 &m)
{
drawable->draw(m);
drawable->draw(this, m);
}
void Graphics::drawq(Texture *texture, Quad *quad, const Matrix4 &m)
void Graphics::draw(Texture *texture, Quad *quad, const Matrix4 &m)
{
texture->drawq(quad, m);
texture->drawq(this, quad, m);
}
void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
@@ -1596,25 +1746,51 @@ void Graphics::printf(const std::vector<Font::ColoredString> &str, float wrap, F
* Primitives
**/
void Graphics::points(const float *coords, const uint8 *colors, size_t numpoints)
void Graphics::points(const float *coords, const Colorf *colors, size_t numpoints)
{
OpenGL::TempDebugGroup debuggroup("Graphics points draw");
StreamDrawRequest req;
req.primitiveMode = vertex::PrimitiveMode::POINTS;
req.formats[0] = vertex::CommonFormat::XYf;
if (colors)
req.formats[1] = vertex::CommonFormat::RGBAub;
req.vertexCount = (int) numpoints;
gl.prepareDraw();
gl.bindTextureToUnit(gl.getDefaultTexture(), 0, false);
gl.bindBuffer(BUFFER_VERTEX, 0);
StreamVertexData data = requestStreamDraw(req);
uint32 attribflags = ATTRIBFLAG_POS;
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords);
const Matrix4 &t = getTransform();
t.transform((Vector *) data.stream[0], (const Vector *) coords, req.vertexCount);
Color *colordata = (Color *) data.stream[1];
if (colors)
{
attribflags |= ATTRIBFLAG_COLOR;
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
}
Colorf nc = getColor();
gammaCorrectColor(nc);
gl.useVertexAttribArrays(attribflags);
gl.drawArrays(GL_POINTS, 0, (GLsizei) numpoints);
if (isGammaCorrect())
{
for (int i = 0; i < req.vertexCount; i++)
{
Colorf ci = colors[i];
gammaCorrectColor(ci);
ci *= nc;
unGammaCorrectColor(ci);
colordata[i] = toColor(ci);
}
}
else
{
for (int i = 0; i < req.vertexCount; i++)
colordata[i] = toColor(nc * colors[i]);
}
}
else
{
Color c = toColor(getColor());
for (int i = 0; i < req.vertexCount; i++)
colordata[i] = c;
}
}
void Graphics::polyline(const float *coords, size_t count)
@@ -1626,19 +1802,19 @@ void Graphics::polyline(const float *coords, size_t count)
{
NoneJoinPolyline line;
line.render(coords, count, state.lineWidth * .5f, pixelsize, state.lineStyle == LINE_SMOOTH);
line.draw();
line.draw(this);
}
else if (state.lineJoin == LINE_JOIN_BEVEL)
{
BevelJoinPolyline line;
line.render(coords, count, state.lineWidth * .5f, pixelsize, state.lineStyle == LINE_SMOOTH);
line.draw();
line.draw(this);
}
else // LINE_JOIN_MITER
{
MiterJoinPolyline line;
line.render(coords, count, state.lineWidth * .5f, pixelsize, state.lineStyle == LINE_SMOOTH);
line.draw();
line.draw(this);
}
}
@@ -1669,7 +1845,7 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, floa
float angle_shift = half_pi / ((float) points + 1.0f);
int num_coords = (points + 2) * 8;
float *coords = new float[num_coords + 2];
float *coords = getScratchBuffer<float>(num_coords + 2);
float phi = .0f;
for (int i = 0; i <= points + 2; ++i, phi += angle_shift)
@@ -1706,8 +1882,6 @@ void Graphics::rectangle(DrawMode mode, float x, float y, float w, float h, floa
coords[num_coords + 1] = coords[1];
polygon(mode, coords, num_coords + 2);
delete[] coords;
}
int Graphics::calculateEllipsePoints(float rx, float ry) const
@@ -1733,12 +1907,12 @@ void Graphics::circle(DrawMode mode, float x, float y, float radius)
void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int points)
{
float two_pi = static_cast<float>(LOVE_M_PI * 2);
float two_pi = (float) (LOVE_M_PI * 2);
if (points <= 0) points = 1;
float angle_shift = (two_pi / points);
float phi = .0f;
float *coords = new float[2 * (points + 1)];
float *coords = getScratchBuffer<float>(2 * (points + 1));
for (int i = 0; i < points; ++i, phi += angle_shift)
{
coords[2*i+0] = x + a * cosf(phi);
@@ -1749,8 +1923,6 @@ void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b, int po
coords[2*points+1] = coords[1];
polygon(mode, coords, (points + 1) * 2);
delete[] coords;
}
void Graphics::ellipse(DrawMode mode, float x, float y, float a, float b)
@@ -1804,7 +1976,7 @@ void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float r
if (arcmode == ARC_PIE)
{
num_coords = (points + 3) * 2;
coords = new float[num_coords];
coords = getScratchBuffer<float>(num_coords);
coords[0] = coords[num_coords - 2] = x;
coords[1] = coords[num_coords - 1] = y;
@@ -1814,14 +1986,14 @@ void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float r
else if (arcmode == ARC_OPEN)
{
num_coords = (points + 1) * 2;
coords = new float[num_coords];
coords = getScratchBuffer<float>(num_coords);
createPoints(coords);
}
else // ARC_CLOSED
{
num_coords = (points + 2) * 2;
coords = new float[num_coords];
coords = getScratchBuffer<float>(num_coords);
createPoints(coords);
@@ -1830,10 +2002,7 @@ void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float r
coords[num_coords - 1] = coords[1];
}
// NOTE: We rely on polygon() using GL_TRIANGLE_FAN, when fill mode is used.
polygon(drawmode, coords, num_coords);
delete[] coords;
}
void Graphics::arc(DrawMode drawmode, ArcMode arcmode, float x, float y, float radius, float angle1, float angle2)
@@ -1861,14 +2030,21 @@ void Graphics::polygon(DrawMode mode, const float *coords, size_t count)
}
else
{
OpenGL::TempDebugGroup debuggroup("Filled polygon draw");
StreamDrawRequest req;
req.formats[0] = vertex::CommonFormat::XYf;
req.formats[1] = vertex::CommonFormat::RGBAub;
req.indexMode = vertex::TriangleIndexMode::FAN;
req.vertexCount = (int)count/2 - 1;
gl.prepareDraw();
gl.bindTextureToUnit(gl.getDefaultTexture(), 0, false);
gl.bindBuffer(BUFFER_VERTEX, 0);
gl.useVertexAttribArrays(ATTRIBFLAG_POS);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, coords);
gl.drawArrays(GL_TRIANGLE_FAN, 0, (int)count/2-1); // opengl will close the polygon for us
StreamVertexData data = requestStreamDraw(req);
const Matrix4 &t = getTransform();
t.transform((Vector *) data.stream[0], (const Vector *) coords, req.vertexCount);
Color c = toColor(getColor());
Color *colordata = (Color *) data.stream[1];
for (int i = 0; i < req.vertexCount; i++)
colordata[i] = c;
}
}
@@ -1904,9 +2080,14 @@ Graphics::RendererInfo Graphics::getRendererInfo() const
Graphics::Stats Graphics::getStats() const
{
int drawcalls = gl.stats.drawCalls;
if (streamBufferState.vertexCount > 0)
drawcalls++;
Stats stats;
stats.drawCalls = gl.stats.drawCalls;
stats.drawCalls = drawcalls;
stats.canvasSwitches = canvasSwitchCount;
stats.shaderSwitches = gl.stats.shaderSwitches;
stats.canvases = Canvas::canvasCount;
@@ -1960,7 +2141,7 @@ void Graphics::push(StackType type)
if (stackTypes.size() == MAX_USER_STACK_DEPTH)
throw Exception("Maximum stack depth reached (more pushes than pops?)");
gl.pushTransform();
pushTransform();
pixelScaleStack.push_back(pixelScaleStack.back());
@@ -1975,7 +2156,7 @@ void Graphics::pop()
if (stackTypes.size() < 1)
throw Exception("Minimum stack depth reached (more pops than pushes?)");
gl.popTransform();
popTransform();
pixelScaleStack.pop_back();
if (stackTypes.back() == STACK_ALL)
@@ -1993,34 +2174,34 @@ void Graphics::pop()
void Graphics::rotate(float r)
{
gl.getTransform().rotate(r);
transformStack.back().rotate(r);
}
void Graphics::scale(float x, float y)
{
gl.getTransform().scale(x, y);
transformStack.back().scale(x, y);
pixelScaleStack.back() *= (fabs(x) + fabs(y)) / 2.0;
}
void Graphics::translate(float x, float y)
{
gl.getTransform().translate(x, y);
transformStack.back().translate(x, y);
}
void Graphics::shear(float kx, float ky)
{
gl.getTransform().shear(kx, ky);
transformStack.back().shear(kx, ky);
}
void Graphics::origin()
{
gl.getTransform().setIdentity();
transformStack.back().setIdentity();
pixelScaleStack.back() = 1;
}
void Graphics::applyTransform(love::math::Transform *transform)
{
Matrix4 &m = gl.getTransform();
Matrix4 &m = transformStack.back();
m *= transform->getMatrix();
float sx, sy;
@@ -2031,7 +2212,7 @@ void Graphics::applyTransform(love::math::Transform *transform)
void Graphics::replaceTransform(love::math::Transform *transform)
{
const Matrix4 &m = transform->getMatrix();
gl.getTransform() = m;
transformStack.back() = m;
float sx, sy;
m.getApproximateScale(sx, sy);
@@ -2041,7 +2222,7 @@ void Graphics::replaceTransform(love::math::Transform *transform)
Vector Graphics::transformPoint(Vector point)
{
Vector p;
gl.getTransform().transform(&p, &point, 1);
transformStack.back().transform(&p, &point, 1);
return p;
}
@@ -2050,7 +2231,7 @@ Vector Graphics::inverseTransformPoint(Vector point)
Vector p;
// TODO: We should probably cache the inverse transform so we don't have to
// re-calculate it every time this is called.
gl.getTransform().inverse().transform(&p, &point, 1);
transformStack.back().inverse().transform(&p, &point, 1);
return p;
}
+16 -14
View File
@@ -62,7 +62,7 @@ namespace graphics
namespace opengl
{
class Graphics : public love::graphics::Graphics
class Graphics final : public love::graphics::Graphics
{
public:
@@ -78,16 +78,16 @@ public:
virtual ~Graphics();
// Implements Module.
const char *getName() const;
const char *getName() const override;
virtual void setViewportSize(int width, int height);
virtual bool setMode(int width, int height);
virtual void unSetMode();
void setViewportSize(int width, int height) override;
bool setMode(int width, int height) override;
void unSetMode() override;
virtual void setActive(bool active);
virtual bool isActive() const;
void setActive(bool active) override;
bool isActive() const override;
void setDebug(bool enable);
void flushStreamDraws() override;
/**
* Resets the current color, background color,
@@ -101,7 +101,7 @@ public:
void discard(const std::vector<bool> &colorbuffers, bool depthstencil);
virtual bool isCanvasActive() const;
bool isCanvasActive() const override;
bool isCanvasActive(Canvas *canvas) const;
/**
@@ -203,15 +203,14 @@ public:
bool isGammaCorrect() const;
/**
* Sets the foreground color.
* @param c The new foreground color.
* Sets the current constant color.
**/
void setColor(Colorf c);
/**
* Gets current color.
**/
Colorf getColor() const;
Colorf getColor() const override;
/**
* Sets the background Color.
@@ -324,7 +323,7 @@ public:
bool isWireframe() const;
void draw(Drawable *drawable, const Matrix4 &m);
void drawq(Texture *texture, Quad *quad, const Matrix4 &m);
void draw(Texture *texture, Quad *quad, const Matrix4 &m);
/**
* Draws text at the specified coordinates
@@ -341,7 +340,7 @@ public:
* @param x Point along x-axis.
* @param y Point along y-axis.
**/
void points(const float *coords, const uint8 *colors, size_t numpoints);
void points(const float *coords, const Colorf *colors, size_t numpoints);
/**
* Draws a series of lines connecting the given vertices.
@@ -462,6 +461,7 @@ private:
struct DisplayState
{
Colorf color = Colorf(1.0, 1.0, 1.0, 1.0);
Colorf gammaCorrectedColor = Colorf(1.0f, 1.0f, 1.0f, 1.0f);
Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 1.0);
BlendMode blendMode = BLEND_ALPHA;
@@ -512,6 +512,8 @@ private:
void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
GLuint attachCachedStencilBuffer(int w, int h, int samples);
void setDebug(bool enable);
void checkSetDefaultFont();
int calculateEllipsePoints(float rx, float ry) const;
+3 -32
View File
@@ -169,7 +169,7 @@ Image::~Image()
void Image::preload()
{
for (int i = 0; i < 4; i++)
vertices[i].r = vertices[i].g = vertices[i].b = vertices[i].a = 255;
vertices[i].color = Color(255, 255, 255, 255);
// Vertices are ordered for use with triangle strips:
// 0----2
@@ -448,38 +448,9 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
return true;
}
void Image::drawv(const Matrix4 &t, const Vertex *v)
ptrdiff_t Image::getHandle() const
{
OpenGL::TempDebugGroup debuggroup("Image draw");
OpenGL::TempTransform transform(gl);
transform.get() *= t;
gl.bindTextureToUnit(texture, 0, false);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
gl.bindBuffer(BUFFER_VERTEX, 0);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &v[0].s);
gl.prepareDraw();
gl.drawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
void Image::draw(const Matrix4 &m)
{
drawv(m, vertices);
}
void Image::drawq(Quad *quad, const Matrix4 &m)
{
drawv(m, quad->getVertices());
}
const void *Image::getHandle() const
{
return &texture;
return texture;
}
const std::vector<StrongRef<love::image::ImageData>> &Image::getImageData() const
+1 -13
View File
@@ -90,17 +90,7 @@ public:
bool loadVolatile() override;
void unloadVolatile() override;
/**
* @copydoc Drawable::draw()
**/
void draw(const Matrix4 &m) override;
/**
* @copydoc Texture::drawq()
**/
void drawq(Quad *quad, const Matrix4 &m) override;
const void *getHandle() const override;
ptrdiff_t getHandle() const override;
const std::vector<StrongRef<love::image::ImageData>> &getImageData() const;
const std::vector<StrongRef<love::image::CompressedImageData>> &getCompressedData() const;
@@ -139,8 +129,6 @@ public:
private:
void drawv(const Matrix4 &t, const Vertex *v);
void preload();
void generateMipmaps();
+7 -8
View File
@@ -23,6 +23,7 @@
#include "common/Matrix.h"
#include "common/Exception.h"
#include "Shader.h"
#include "graphics/Graphics.h"
// C++
#include <algorithm>
@@ -44,7 +45,7 @@ static const char *getBuiltinAttribName(VertexAttribID attribid)
static_assert(offsetof(Vertex, x) == sizeof(float) * 0, "Incorrect position offset in Vertex struct");
static_assert(offsetof(Vertex, s) == sizeof(float) * 2, "Incorrect texture coordinate offset in Vertex struct");
static_assert(offsetof(Vertex, r) == sizeof(float) * 4, "Incorrect color offset in Vertex struct");
static_assert(offsetof(Vertex, color.r) == sizeof(float) * 4, "Incorrect color offset in Vertex struct");
static std::vector<Mesh::AttribFormat> getDefaultVertexFormat()
{
@@ -574,11 +575,13 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu
return attriblocation;
}
void Mesh::draw(const Matrix4 &m)
void Mesh::draw(Graphics *gfx, const Matrix4 &m)
{
if (vertexCount <= 0)
return;
gfx->flushStreamDraws();
OpenGL::TempDebugGroup debuggroup("Mesh draw");
uint32 enabledattribs = 0;
@@ -601,13 +604,9 @@ void Mesh::draw(const Matrix4 &m)
gl.useVertexAttribArrays(enabledattribs);
if (texture.get())
gl.bindTextureToUnit(*(GLuint *) texture->getHandle(), 0, false);
else
gl.bindTextureToUnit(gl.getDefaultTexture(), 0, false);
gl.bindTextureToUnit(texture, 0, false);
OpenGL::TempTransform transform(gl);
transform.get() *= m;
Graphics::TempTransform transform(gfx, m);
gl.prepareDraw();
+1 -1
View File
@@ -200,7 +200,7 @@ public:
int bindAttributeToShaderInput(int attributeindex, const std::string &inputname);
// Implements Drawable.
void draw(const Matrix4 &m) override;
void draw(Graphics *gfx, const Matrix4 &m) override;
static GLenum getGLBufferUsage(Usage usage);
+14 -30
View File
@@ -25,6 +25,8 @@
#include "Shader.h"
#include "common/Exception.h"
#include "graphics/Graphics.h"
// C++
#include <algorithm>
#include <limits>
@@ -74,7 +76,6 @@ OpenGL::OpenGL()
, vendor(VENDOR_UNKNOWN)
, state()
{
matrices.transform.reserve(10);
}
bool OpenGL::initContext()
@@ -87,7 +88,6 @@ bool OpenGL::initContext()
initOpenGLFunctions();
initVendor();
initMatrices();
bugs = {};
@@ -314,14 +314,6 @@ void OpenGL::initMaxValues()
maxPointSize = limits[1];
}
void OpenGL::initMatrices()
{
matrices.transform.clear();
matrices.transform.push_back(Matrix4());
matrices.projection = Matrix4();
}
void OpenGL::createDefaultTexture()
{
// Set the 'default' texture (id 0) as a repeating white pixel. Otherwise,
@@ -346,21 +338,6 @@ void OpenGL::createDefaultTexture()
bindTextureToUnit(curtexture, 0, false);
}
void OpenGL::pushTransform()
{
matrices.transform.push_back(matrices.transform.back());
}
void OpenGL::popTransform()
{
matrices.transform.pop_back();
}
Matrix4 &OpenGL::getTransform()
{
return matrices.transform.back();
}
void OpenGL::prepareDraw()
{
TempDebugGroup debuggroup("Prepare OpenGL draw");
@@ -373,8 +350,9 @@ void OpenGL::prepareDraw()
// because uniform uploads can be significantly slower than glLoadMatrix.
if (GLAD_VERSION_1_0)
{
const Matrix4 &curproj = matrices.projection;
const Matrix4 &curxform = matrices.transform.back();
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
const Matrix4 &curxform = gfx->getTransform();
const Matrix4 &curproj = gfx->getProjection();
const Matrix4 &lastproj = state.lastProjectionMatrix;
const Matrix4 &lastxform = state.lastTransformMatrix;
@@ -386,14 +364,14 @@ void OpenGL::prepareDraw()
glLoadMatrixf(curproj.getElements());
glMatrixMode(GL_MODELVIEW);
state.lastProjectionMatrix = matrices.projection;
state.lastProjectionMatrix = curproj;
}
// Same with the transform matrix.
if (memcmp(curxform.getElements(), lastxform.getElements(), sizeof(float) * 16) != 0)
{
glLoadMatrixf(curxform.getElements());
state.lastTransformMatrix = matrices.transform.back();
state.lastTransformMatrix = curxform;
}
}
}
@@ -454,7 +432,7 @@ void OpenGL::useVertexAttribArrays(uint32 arraybits)
// than 32. Lets hope that doesn't change...
for (uint32 i = 0; i < 32; i++)
{
uint32 bit = 1 << i;
uint32 bit = 1u << i;
if (diff & bit)
{
@@ -637,6 +615,12 @@ void OpenGL::bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev
}
}
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev)
{
GLuint handle = texture != nullptr ? (GLuint) texture->getHandle() : getDefaultTexture();
bindTextureToUnit(handle, textureunit, restoreprev);
}
void OpenGL::deleteTexture(GLuint texture)
{
// glDeleteTextures binds texture 0 to all texture units the deleted texture
+2 -42
View File
@@ -27,6 +27,7 @@
#include "common/math.h"
#include "graphics/Color.h"
#include "graphics/Texture.h"
#include "graphics/vertex.h"
#include "common/Matrix.h"
// GLAD
@@ -70,13 +71,6 @@ enum VertexAttribFlags
ATTRIBFLAG_CONSTANTCOLOR = 1 << ATTRIB_CONSTANTCOLOR
};
enum BufferType
{
BUFFER_VERTEX = 0,
BUFFER_INDEX,
BUFFER_MAX_ENUM
};
/**
* Thin layer between OpenGL and the rest of the program.
* Internally shadows some OpenGL context state for improved efficiency and
@@ -119,36 +113,6 @@ public:
GLenum type = 0;
};
struct
{
std::vector<Matrix4> transform;
Matrix4 projection;
} matrices;
class TempTransform
{
public:
TempTransform(OpenGL &gl)
: gl(gl)
{
gl.pushTransform();
}
~TempTransform()
{
gl.popTransform();
}
Matrix4 &get()
{
return gl.getTransform();
}
private:
OpenGL &gl;
};
class TempDebugGroup
{
public:
@@ -242,10 +206,6 @@ public:
**/
void deInitContext();
void pushTransform();
void popTransform();
Matrix4 &getTransform();
/**
* Set up necessary state (LOVE-provided shader uniforms, etc.) for drawing.
* This *MUST* be called directly before OpenGL drawing functions.
@@ -359,6 +319,7 @@ public:
* @param restoreprev Restore previously bound texture unit when done.
**/
void bindTextureToUnit(GLuint texture, int textureunit, bool restoreprev);
void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev);
/**
* Helper for deleting an OpenGL texture.
@@ -440,7 +401,6 @@ private:
void initVendor();
void initOpenGLFunctions();
void initMaxValues();
void initMatrices();
void createDefaultTexture();
bool contextInitialized;
+13 -13
View File
@@ -21,6 +21,7 @@
//LOVE
#include "common/config.h"
#include "ParticleSystem.h"
#include "graphics/Graphics.h"
#include "OpenGL.h"
@@ -61,7 +62,7 @@ void ParticleSystem::createVertices(size_t numparticles)
{
try
{
love::Vertex *pverts = new love::Vertex[numparticles * 4];
Vertex *pverts = new Vertex[numparticles * 4];
delete[] particleVerts;
particleVerts = pverts;
}
@@ -84,17 +85,18 @@ void ParticleSystem::setBufferSize(uint32 size)
createVertices(size);
}
void ParticleSystem::draw(const Matrix4 &m)
void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
{
uint32 pCount = getCount();
if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || particleVerts == nullptr)
return;
gfx->flushStreamDraws();
OpenGL::TempDebugGroup debuggroup("ParticleSystem draw");
OpenGL::TempTransform transform(gl);
transform.get() *= m;
Graphics::TempTransform transform(gfx, m);
const Vertex *textureVerts = texture->getVertices();
Vertex *pVerts = particleVerts;
@@ -114,31 +116,29 @@ void ParticleSystem::draw(const Matrix4 &m)
t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f);
t.transform(pVerts, textureVerts, 4);
// Particle colors are stored as floats (0-1) but vertex colors are
// unsigned bytes (0-255).
Color c = toColor(p->color);
// 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;
// Particle colors are stored as floats (0-1) but vertex colors are
// unsigned bytes (0-255).
pVerts[v].r = (unsigned char) (p->color.r*255);
pVerts[v].g = (unsigned char) (p->color.g*255);
pVerts[v].b = (unsigned char) (p->color.b*255);
pVerts[v].a = (unsigned char) (p->color.a*255);
pVerts[v].color = c;
}
pVerts += 4;
p = p->next;
}
gl.bindTextureToUnit(*(GLuint *) texture->getHandle(), 0, false);
gl.bindTextureToUnit(texture, 0, false);
gl.prepareDraw();
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
gl.bindBuffer(BUFFER_VERTEX, 0);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &particleVerts[0].r);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), &particleVerts[0].color.r);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].x);
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), &particleVerts[0].s);
+1 -1
View File
@@ -43,7 +43,7 @@ public:
ParticleSystem *clone() override;
void setBufferSize(uint32 size) override;
void draw(const Matrix4 &m) override;
void draw(Graphics *gfx, const Matrix4 &m) override;
private:
+55 -100
View File
@@ -20,9 +20,7 @@
// LOVE
#include "Polyline.h"
// OpenGL
#include "OpenGL.h"
#include "graphics/Graphics.h"
// C++
#include <algorithm>
@@ -86,7 +84,7 @@ void Polyline::render(const float *coords, size_t count, size_t size_hint, float
// extra degenerate triangle in between the core line and the overdraw
// line in order to break up the strip into two. This will let us draw
// everything in one draw call.
if (draw_mode == GL_TRIANGLE_STRIP)
if (triangle_mode == vertex::TriangleIndexMode::STRIP)
extra_vertices = 2;
}
@@ -115,6 +113,12 @@ void NoneJoinPolyline::renderEdge(std::vector<Vector> &anchors, std::vector<Vect
Vector &s, float &len_s, Vector &ns,
const Vector &q, const Vector &r, float hw)
{
// ns1------ns2
// | |
// q ------ r
// | |
// (-ns1)----(-ns2)
anchors.push_back(q);
anchors.push_back(q);
normals.push_back(ns);
@@ -126,8 +130,8 @@ void NoneJoinPolyline::renderEdge(std::vector<Vector> &anchors, std::vector<Vect
anchors.push_back(q);
anchors.push_back(q);
normals.push_back(-ns);
normals.push_back(ns);
normals.push_back(-ns);
}
@@ -324,31 +328,36 @@ void NoneJoinPolyline::render_overdraw(const std::vector<Vector> &/*normals*/, f
{
for (size_t i = 2; i + 3 < vertex_count; i += 4)
{
Vector s = vertices[i] - vertices[i+3];
Vector t = vertices[i] - vertices[i+1];
// v0-v2
// | / | <- main quad line
// v1-v3
Vector s = vertices[i+0] - vertices[i+2];
Vector t = vertices[i+0] - vertices[i+1];
s.normalize(pixel_size);
t.normalize(pixel_size);
const size_t k = 4 * (i - 2);
overdraw[k ] = vertices[i];
overdraw[k+1] = vertices[i] + s + t;
overdraw[k+2] = vertices[i+1] + s - t;
overdraw[k+3] = vertices[i+1];
overdraw[k+0] = vertices[i+0];
overdraw[k+1] = vertices[i+1];
overdraw[k+2] = vertices[i+0] + s + t;
overdraw[k+3] = vertices[i+1] + s - t;
overdraw[k+4] = vertices[i+1];
overdraw[k+5] = vertices[i+1] + s - t;
overdraw[k+6] = vertices[i+2] - s - t;
overdraw[k+7] = vertices[i+2];
overdraw[k+5] = vertices[i+3];
overdraw[k+6] = vertices[i+1] + s - t;
overdraw[k+7] = vertices[i+3] - s - t;
overdraw[k+8] = vertices[i+2];
overdraw[k+9] = vertices[i+2] - s - t;
overdraw[k+10] = vertices[i+3] - s + t;
overdraw[k+11] = vertices[i+3];
overdraw[k+ 8] = vertices[i+3];
overdraw[k+ 9] = vertices[i+2];
overdraw[k+10] = vertices[i+3] - s - t;
overdraw[k+11] = vertices[i+2] - s + t;
overdraw[k+12] = vertices[i+3];
overdraw[k+13] = vertices[i+3] - s + t;
overdraw[k+14] = vertices[i] + s + t;
overdraw[k+15] = vertices[i];
overdraw[k+12] = vertices[i+2];
overdraw[k+13] = vertices[i+0];
overdraw[k+14] = vertices[i+2] - s + t;
overdraw[k+15] = vertices[i+0] + s + t;
}
}
@@ -358,104 +367,50 @@ Polyline::~Polyline()
delete[] vertices;
}
void Polyline::draw()
void Polyline::draw(love::graphics::Graphics *gfx)
{
OpenGL::TempDebugGroup debuggroup("Line draw");
GLushort *indices = nullptr;
Color *colors = nullptr;
size_t total_vertex_count = vertex_count;
int total_vertex_count = (int) vertex_count;
if (overdraw)
total_vertex_count = overdraw_vertex_start + overdraw_vertex_count;
total_vertex_count = (int) (overdraw_vertex_start + overdraw_vertex_count);
// TODO: We should probably be using a reusable index buffer.
if (use_quad_indices)
{
size_t numindices = (total_vertex_count / 4) * 6;
Graphics::StreamDrawRequest req;
req.formats[0] = vertex::CommonFormat::XYf;
req.formats[1] = vertex::CommonFormat::RGBAub;
req.indexMode = triangle_mode;
req.vertexCount = total_vertex_count;
try
{
indices = new GLushort[numindices];
}
catch (std::bad_alloc &)
{
throw love::Exception("Out of memory.");
}
Graphics::StreamVertexData data = gfx->requestStreamDraw(req);
// Fill the index array to make 2 triangles from each quad.
// NOTE: The triangle vertex ordering here is important!
for (size_t i = 0; i < numindices / 6; i++)
{
// First triangle.
indices[i * 6 + 0] = GLushort(i * 4 + 0);
indices[i * 6 + 1] = GLushort(i * 4 + 1);
indices[i * 6 + 2] = GLushort(i * 4 + 2);
const Matrix4 &t = gfx->getTransform();
t.transform((Vector *) data.stream[0], vertices, total_vertex_count);
// Second triangle.
indices[i * 6 + 3] = GLushort(i * 4 + 0);
indices[i * 6 + 4] = GLushort(i * 4 + 2);
indices[i * 6 + 5] = GLushort(i * 4 + 3);
}
}
Color curcolor = toColor(gfx->getColor());
Color *colordata = (Color *) data.stream[1];
gl.prepareDraw();
gl.bindTextureToUnit(gl.getDefaultTexture(), 0, false);
gl.bindBuffer(BUFFER_VERTEX, 0);
uint32 enabledattribs = ATTRIBFLAG_POS;
for (int i = 0; i < (int) vertex_count; i++)
colordata[i] = curcolor;
if (overdraw)
{
// Prepare per-vertex colors. Set the core to white, and the overdraw
// line's colors to white on one side and transparent on the other.
colors = new Color[total_vertex_count];
memset(colors, 255, overdraw_vertex_start * sizeof(Color));
fill_color_array(colors + overdraw_vertex_start);
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colors);
enabledattribs |= ATTRIBFLAG_COLOR;
}
gl.useVertexAttribArrays(enabledattribs);
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, vertices);
// Draw the core line and the overdraw in a single draw call. We can do this
// because the vertex array contains both the core line and the overdraw
// vertices.
if (use_quad_indices)
{
gl.bindBuffer(BUFFER_INDEX, 0);
gl.drawElements(draw_mode, (int) (total_vertex_count / 4) * 6, GL_UNSIGNED_SHORT, indices);
}
else
gl.drawArrays(draw_mode, 0, (int) total_vertex_count);
if (overdraw)
delete[] colors;
if (indices)
delete[] indices;
fill_color_array(curcolor, colordata + overdraw_vertex_start);
}
void Polyline::fill_color_array(Color *colors)
void Polyline::fill_color_array(Color constant_color, Color *colors)
{
for (size_t i = 0; i < overdraw_vertex_count; ++i)
{
// avoids branching. equiv to if (i%2 == 1) colors[i].a = 0;
colors[i] = {255, 255, 255, GLubyte(255 * ((i+1) % 2))};
Color c = constant_color;
c.a *= (i+1) % 2; // avoids branching. equiv to if (i%2 == 1) c.a = 0;
colors[i] = c;
}
}
void NoneJoinPolyline::fill_color_array(Color *colors)
void NoneJoinPolyline::fill_color_array(Color constant_color, Color *colors)
{
for (size_t i = 0; i < overdraw_vertex_count; ++i)
{
// if (i % 4 == 1 || i % 4 == 2) colors[i].a = 0
colors[i] = {255, 255, 255, GLubyte(255 * ((i+1) % 4 < 2))};
Color c = constant_color;
c.a *= (i & 3) < 2; // if (i % 4 == 2 || i % 4 == 3) c.a = 0
colors[i] = c;
}
}
+26 -15
View File
@@ -24,9 +24,7 @@
// LOVE
#include "common/config.h"
#include "common/Vector.h"
// OpenGL
#include "OpenGL.h"
#include "graphics/vertex.h"
// C++
#include <vector>
@@ -36,6 +34,9 @@ namespace love
{
namespace graphics
{
class Graphics;
namespace opengl
{
@@ -46,15 +47,16 @@ namespace opengl
class Polyline
{
public:
Polyline(GLenum mode = GL_TRIANGLE_STRIP, bool quadindices = false)
Polyline(vertex::TriangleIndexMode mode = vertex::TriangleIndexMode::STRIP)
: vertices(nullptr)
, overdraw(nullptr)
, vertex_count(0)
, overdraw_vertex_count(0)
, draw_mode(mode)
, use_quad_indices(quadindices)
, triangle_mode(mode)
, overdraw_vertex_start(0)
{}
virtual ~Polyline();
/**
@@ -69,12 +71,13 @@ public:
/** Draws the line on the screen
*/
void draw();
void draw(love::graphics::Graphics *gfx);
protected:
virtual void calc_overdraw_vertex_count(bool is_looping);
virtual void render_overdraw(const std::vector<Vector> &normals, float pixel_size, bool is_looping);
virtual void fill_color_array(Color *colors);
virtual void fill_color_array(Color constant_color, Color *colors);
/** Calculate line boundary points.
*
@@ -95,8 +98,7 @@ protected:
Vector *overdraw;
size_t vertex_count;
size_t overdraw_vertex_count;
GLenum draw_mode;
bool use_quad_indices;
vertex::TriangleIndexMode triangle_mode;
size_t overdraw_vertex_start;
}; // Polyline
@@ -109,8 +111,9 @@ protected:
class NoneJoinPolyline : public Polyline
{
public:
NoneJoinPolyline()
: Polyline(GL_TRIANGLES, true)
: Polyline(vertex::TriangleIndexMode::QUADS)
{}
void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
@@ -131,13 +134,15 @@ public:
}
protected:
virtual void calc_overdraw_vertex_count(bool is_looping);
virtual void render_overdraw(const std::vector<Vector> &normals, float pixel_size, bool is_looping);
virtual void fill_color_array(Color *colors);
virtual void fill_color_array(Color constant_color, Color *colors);
virtual void renderEdge(std::vector<Vector> &anchors, std::vector<Vector> &normals,
Vector &s, float &len_s, Vector &ns,
const Vector &q, const Vector &r, float hw);
};
}; // NoneJoinPolyline
/**
@@ -147,16 +152,19 @@ protected:
class MiterJoinPolyline : public Polyline
{
public:
void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
{
Polyline::render(vertices, count, count, halfwidth, pixel_size, draw_overdraw);
}
protected:
virtual void renderEdge(std::vector<Vector> &anchors, std::vector<Vector> &normals,
Vector &s, float &len_s, Vector &ns,
const Vector &q, const Vector &r, float hw);
};
}; // MiterJoinPolyline
/**
@@ -166,16 +174,19 @@ protected:
class BevelJoinPolyline : public Polyline
{
public:
void render(const float *vertices, size_t count, float halfwidth, float pixel_size, bool draw_overdraw)
{
Polyline::render(vertices, count, 2 * count - 4, halfwidth, pixel_size, draw_overdraw);
}
protected:
virtual void renderEdge(std::vector<Vector> &anchors, std::vector<Vector> &normals,
Vector &s, float &len_s, Vector &ns,
const Vector &q, const Vector &r, float hw);
};
}; // BevelJoinPolyline
} // opengl
} // graphics
+21 -4
View File
@@ -587,6 +587,9 @@ const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
void Shader::updateUniform(const UniformInfo *info, int count, bool internalUpdate)
{
if (!internalUpdate)
flushStreamDraws();
TemporaryAttacher attacher(this, !internalUpdate);
int location = info->location;
@@ -679,6 +682,9 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count
if (info->baseType != UNIFORM_SAMPLER)
return;
if (!internalUpdate)
flushStreamDraws();
count = std::min(count, info->count);
bool updateuniform = false;
@@ -713,7 +719,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count
if (textures[i] != nullptr)
{
GLuint gltex = *(GLuint *) textures[i]->getHandle();
GLuint gltex = (GLuint) textures[i]->getHandle();
gl.bindTextureToUnit(gltex, texunit, false);
@@ -722,13 +728,23 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count
}
else
{
gl.bindTextureToUnit(0, texunit, false);
gl.bindTextureToUnit((GLuint) 0, texunit, false);
textureUnits[texunit].texture = 0;
textureUnits[texunit].active = false;
}
}
}
void Shader::flushStreamDraws() const
{
if (current == this)
{
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr)
gfx->flushStreamDraws();
}
}
bool Shader::hasUniform(const std::string &name) const
{
return uniforms.find(name) != uniforms.end();
@@ -871,9 +887,10 @@ void Shader::checkSetBuiltinUniforms()
{
checkSetPointSize(gl.getPointSize());
const Matrix4 &curxform = gl.matrices.transform.back();
const Matrix4 &curproj = gl.matrices.projection;
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
const Matrix4 &curproj = gfx->getProjection();
const Matrix4 &curxform = gfx->getTransform();
TemporaryAttacher attacher(this, true);
bool tpmatrixneedsupdate = false;
+2
View File
@@ -215,6 +215,8 @@ private:
int getFreeTextureUnits(int count);
void flushStreamDraws() const;
// Get any warnings or errors generated only by the shader program object.
std::string getProgramWarnings() const;
+12 -18
View File
@@ -27,6 +27,7 @@
// LOVE
#include "GLBuffer.h"
#include "graphics/Texture.h"
#include "graphics/Graphics.h"
// C++
#include <algorithm>
@@ -240,21 +241,22 @@ bool SpriteBatch::getDrawRange(int &start, int &count) const
return true;
}
void SpriteBatch::draw(const Matrix4 &m)
void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
{
const size_t pos_offset = offsetof(Vertex, x);
const size_t texel_offset = offsetof(Vertex, s);
const size_t color_offset = offsetof(Vertex, r);
const size_t color_offset = offsetof(Vertex, color.r);
if (next == 0)
return;
gfx->flushStreamDraws();
OpenGL::TempDebugGroup debuggroup("SpriteBatch draw");
OpenGL::TempTransform transform(gl);
transform.get() *= m;
Graphics::TempTransform transform(gfx, m);
gl.bindTextureToUnit(*(GLuint *) texture->getHandle(), 0, false);
gl.bindTextureToUnit(texture, 0, false);
uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
@@ -315,8 +317,11 @@ void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index)
m.transform(sprite, sprite, 4);
if (color)
setColorv(sprite, *color);
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.)
@@ -325,17 +330,6 @@ void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index)
array_buf->fill(index * sprite_size, sprite_size, sprite);
}
void SpriteBatch::setColorv(Vertex *v, const Color &color)
{
for (size_t i = 0; i < 4; ++i)
{
v[i].r = color.r;
v[i].g = color.g;
v[i].b = color.b;
v[i].a = color.a;
}
}
} // opengl
} // graphics
} // love
+1 -10
View File
@@ -108,7 +108,7 @@ public:
bool getDrawRange(int &start, int &count) const;
// Implements Drawable.
void draw(const Matrix4 &m) override;
void draw(Graphics *gfx, const Matrix4 &m) override;
private:
@@ -126,15 +126,6 @@ private:
void addv(const Vertex *v, const Matrix4 &m, int index);
/**
* Set the color for vertices.
*
* @param v The vertices to set the color for. Must be an array of
* of size 4.
* @param color The color to assign to each vertex.
*/
void setColorv(Vertex *v, const Color &color);
StrongRef<Texture> texture;
// Max number of sprites in the batch.
+11 -11
View File
@@ -20,6 +20,7 @@
#include "Text.h"
#include "common/Matrix.h"
#include "graphics/Graphics.h"
#include <algorithm>
@@ -207,11 +208,13 @@ void Text::clear()
vert_offset = 0;
}
void Text::draw(const Matrix4 &m)
void Text::draw(Graphics *gfx, const Matrix4 &m)
{
if (vbo == nullptr || draw_commands.empty())
return;
gfx->flushStreamDraws();
OpenGL::TempDebugGroup debuggroup("Text object draw");
// Re-generate the text if the Font's texture cache was invalidated.
@@ -223,18 +226,15 @@ void Text::draw(const Matrix4 &m)
const size_t color_offset = offsetof(Font::GlyphVertex, color.r);
const size_t stride = sizeof(Font::GlyphVertex);
OpenGL::TempTransform transform(gl);
transform.get() *= m;
Graphics::TempTransform transform(gfx, m);
{
vbo->bind();
vbo->unmap(); // Make sure all pending data is flushed to the GPU.
vbo->bind();
vbo->unmap(); // Make sure all pending data is flushed to the GPU.
// Font::drawVertices expects AttribPointer calls to be done already.
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(pos_offset));
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, vbo->getPointer(tex_offset));
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, vbo->getPointer(color_offset));
}
// Font::drawVertices expects AttribPointer calls to be done already.
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, vbo->getPointer(pos_offset));
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, vbo->getPointer(tex_offset));
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, vbo->getPointer(color_offset));
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR);
+1 -1
View File
@@ -52,7 +52,7 @@ public:
void clear();
// Implements Drawable.
void draw(const Matrix4 &m) override;
void draw(Graphics *gfx, const Matrix4 &m) override;
void setFont(Font *f);
Font *getFont() const;
+6 -4
View File
@@ -22,6 +22,7 @@
// LOVE
#include "Shader.h"
#include "graphics/Graphics.h"
namespace love
{
@@ -41,7 +42,7 @@ Video::Video(love::video::VideoStream *stream)
stream->fillBackBuffer();
for (int i = 0; i < 4; i++)
vertices[i].r = vertices[i].g = vertices[i].b = vertices[i].a = 255;
vertices[i].color = Color(255, 255, 255, 255);
// Vertices are ordered for use with triangle strips:
// 0----2
@@ -116,10 +117,12 @@ love::video::VideoStream *Video::getStream()
return stream;
}
void Video::draw(const Matrix4 &m)
void Video::draw(Graphics *gfx, const Matrix4 &m)
{
update();
gfx->flushStreamDraws();
Shader *shader = Shader::current;
bool defaultShader = (shader == Shader::defaultShader);
if (defaultShader)
@@ -131,8 +134,7 @@ void Video::draw(const Matrix4 &m)
shader->setVideoTextures(textures[0], textures[1], textures[2]);
OpenGL::TempTransform transform(gl);
transform.get() *= m;
Graphics::TempTransform transform(gfx, m);
gl.useVertexAttribArrays(ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD);
+1 -1
View File
@@ -50,7 +50,7 @@ public:
void unloadVolatile() override;
// Drawable
void draw(const Matrix4 &m) override;
void draw(Graphics *gfx, const Matrix4 &m) override;
love::video::VideoStream *getStream();
+31 -31
View File
@@ -826,10 +826,10 @@ static Mesh *newStandardMesh(lua_State *L)
v.s = (float) luaL_optnumber(L, -6, 0.0);
v.t = (float) luaL_optnumber(L, -5, 0.0);
v.r = (unsigned char) (luaL_optnumber(L, -4, 1.0) * 255.0);
v.g = (unsigned char) (luaL_optnumber(L, -3, 1.0) * 255.0);
v.b = (unsigned char) (luaL_optnumber(L, -2, 1.0) * 255.0);
v.a = (unsigned char) (luaL_optnumber(L, -1, 1.0) * 255.0);
v.color.r = (unsigned char) (luaL_optnumber(L, -4, 1.0) * 255.0);
v.color.g = (unsigned char) (luaL_optnumber(L, -3, 1.0) * 255.0);
v.color.b = (unsigned char) (luaL_optnumber(L, -2, 1.0) * 255.0);
v.color.a = (unsigned char) (luaL_optnumber(L, -1, 1.0) * 255.0);
lua_pop(L, 9);
vertices.push_back(v);
@@ -1544,7 +1544,7 @@ int w_draw(lua_State *L)
math::Transform *tf = luax_totype<math::Transform>(L, startidx);
luax_catchexcept(L, [&]() {
if (texture && quad)
instance()->drawq(texture, quad, tf->getMatrix());
instance()->draw(texture, quad, tf->getMatrix());
else
instance()->draw(drawable, tf->getMatrix());
});
@@ -1565,7 +1565,7 @@ int w_draw(lua_State *L)
luax_catchexcept(L, [&]() {
if (texture && quad)
instance()->drawq(texture, quad, m);
instance()->draw(texture, quad, m);
else if (drawable)
instance()->draw(drawable, m);
});
@@ -1673,12 +1673,18 @@ int w_points(lua_State *L)
numpoints = args;
float *coords = nullptr;
uint8 *colors = nullptr;
coords = new float[numpoints * 2];
Colorf *colors = nullptr;
if (is_table_of_tables)
colors = new uint8[numpoints * 4];
{
size_t datasize = (sizeof(float) * 2 + sizeof(Colorf)) * numpoints;
uint8 *data = instance()->getScratchBuffer<uint8>(datasize);
coords = (float *) data;
colors = (Colorf *) (data + sizeof(float) * numpoints * 2);
}
else
coords = instance()->getScratchBuffer<float>(numpoints * 2);
if (is_table)
{
@@ -1694,10 +1700,10 @@ int w_points(lua_State *L)
coords[i * 2 + 0] = luax_tofloat(L, -6);
coords[i * 2 + 1] = luax_tofloat(L, -5);
colors[i * 4 + 0] = (uint8) (luaL_optnumber(L, -4, 1.0) * 255.0);
colors[i * 4 + 1] = (uint8) (luaL_optnumber(L, -3, 1.0) * 255.0);
colors[i * 4 + 2] = (uint8) (luaL_optnumber(L, -2, 1.0) * 255.0);
colors[i * 4 + 3] = (uint8) (luaL_optnumber(L, -1, 1.0) * 255.0);
colors[i].r = luaL_optnumber(L, -4, 1.0);
colors[i].g = luaL_optnumber(L, -3, 1.0);
colors[i].b = luaL_optnumber(L, -2, 1.0);
colors[i].a = luaL_optnumber(L, -1, 1.0);
lua_pop(L, 7);
}
@@ -1719,15 +1725,7 @@ int w_points(lua_State *L)
coords[i] = luax_tofloat(L, i + 1);
}
luax_catchexcept(L,
[&](){ instance()->points(coords, colors, numpoints); },
[&](bool) {
delete[] coords;
if (colors)
delete[] colors;
}
);
luax_catchexcept(L, [&](){ instance()->points(coords, colors, numpoints); });
return 0;
}
@@ -1746,7 +1744,7 @@ int w_line(lua_State *L)
else if (args < 4)
return luaL_error(L, "Need at least two vertices to draw a line");
float *coords = new float[args];
float *coords = instance()->getScratchBuffer<float>(args);
if (is_table)
{
for (int i = 0; i < args; ++i)
@@ -1894,7 +1892,6 @@ int w_polygon(lua_State *L)
return luaL_error(L, "Invalid draw mode: %s", str);
bool is_table = false;
float *coords;
if (args == 1 && lua_istable(L, 2))
{
args = (int) luax_objlen(L, 2);
@@ -1907,7 +1904,7 @@ int w_polygon(lua_State *L)
return luaL_error(L, "Need at least three vertices to draw a polygon");
// fetch coords
coords = new float[args + 2];
float *coords = instance()->getScratchBuffer<float>(args + 2);
if (is_table)
{
for (int i = 0; i < args; ++i)
@@ -1927,11 +1924,13 @@ int w_polygon(lua_State *L)
coords[args] = coords[0];
coords[args+1] = coords[1];
luax_catchexcept(L,
[&](){ instance()->polygon(mode, coords, args+2); },
[&](bool) { delete[] coords; }
);
luax_catchexcept(L, [&](){ instance()->polygon(mode, coords, args+2); });
return 0;
}
int w_flush(lua_State *)
{
instance()->flushStreamDraws();
return 0;
}
@@ -2123,9 +2122,10 @@ static const luaL_Reg functions[] =
{ "circle", w_circle },
{ "ellipse", w_ellipse },
{ "arc", w_arc },
{ "polygon", w_polygon },
{ "flush", w_flush },
{ "push", w_push },
{ "pop", w_pop },
{ "rotate", w_rotate },
+134
View File
@@ -0,0 +1,134 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "vertex.h"
namespace love
{
namespace graphics
{
namespace vertex
{
static_assert(sizeof(Color) == 4, "sizeof(Color) incorrect!");
static_assert(sizeof(Vertex) == sizeof(float)*2 + sizeof(float)*2 + sizeof(Color), "sizeof(Vertex) incorrect!");
static_assert(sizeof(XYf_STf) == sizeof(float)*2 + sizeof(float)*2, "sizeof(XYf_STf) 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!");
size_t getFormatStride(CommonFormat format)
{
switch (format)
{
case CommonFormat::NONE:
return 0;
case CommonFormat::XYf:
return sizeof(float) * 2;
case CommonFormat::RGBAub:
return sizeof(uint8) * 4;
case CommonFormat::XYf_STf:
return sizeof(XYf_STf);
case CommonFormat::XYf_STf_RGBAub:
return sizeof(XYf_STf_RGBAub);
case CommonFormat::XYf_STus_RGBAub:
return sizeof(XYf_STus_RGBAub);
}
}
int getIndexCount(TriangleIndexMode mode, int vertexCount)
{
switch (mode)
{
case TriangleIndexMode::NONE:
return 0;
case TriangleIndexMode::STRIP:
case TriangleIndexMode::FAN:
return 3 * (vertexCount - 2);
case TriangleIndexMode::QUADS:
return vertexCount * 6 / 4;
}
}
template <typename T>
static void fillIndicesT(TriangleIndexMode mode, T vertexStart, T vertexCount, T *indices)
{
switch (mode)
{
case TriangleIndexMode::NONE:
break;
case TriangleIndexMode::STRIP:
{
int i = 0;
for (T index = 0; index < vertexCount - 2; index++)
{
indices[i++] = vertexStart + index;
indices[i++] = vertexStart + index + 1 + (index & 1);
indices[i++] = vertexStart + index + 2 - (index & 1);
}
}
break;
case TriangleIndexMode::FAN:
{
int i = 0;
for (T index = 2; index < vertexCount; index++)
{
indices[i++] = vertexStart;
indices[i++] = vertexStart + index - 1;
indices[i++] = vertexStart + index;
}
}
break;
case TriangleIndexMode::QUADS:
{
// 0---2
// | / |
// 1---3
int count = vertexCount / 4;
for (int i = 0; i < count; i++)
{
int ii = i * 6;
T vi = T(vertexStart + i * 4);
indices[ii + 0] = vi + 0;
indices[ii + 1] = vi + 1;
indices[ii + 2] = vi + 2;
indices[ii + 3] = vi + 2;
indices[ii + 4] = vi + 1;
indices[ii + 5] = vi + 3;
}
}
break;
}
}
void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices)
{
fillIndicesT(mode, vertexStart, vertexCount, indices);
}
void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices)
{
fillIndicesT(mode, vertexStart, vertexCount, indices);
}
} // vertex
} // graphics
} // love
+105
View File
@@ -0,0 +1,105 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#pragma once
// LOVE
#include "common/int.h"
#include "Color.h"
// C
#include <stddef.h>
namespace love
{
namespace graphics
{
enum BufferType
{
BUFFER_VERTEX = 0,
BUFFER_INDEX,
BUFFER_MAX_ENUM
};
struct Vertex
{
float x, y;
float s, t;
Color color;
};
namespace vertex
{
enum class PrimitiveMode
{
TRIANGLES,
POINTS,
};
enum class TriangleIndexMode
{
NONE,
STRIP,
FAN,
QUADS,
};
enum class CommonFormat
{
NONE,
XYf,
RGBAub,
XYf_STf,
XYf_STf_RGBAub,
XYf_STus_RGBAub,
};
struct XYf_STf
{
float x, y;
float s, t;
};
struct XYf_STf_RGBAub
{
float x, y;
float s, t;
Color color;
};
struct XYf_STus_RGBAub
{
float x, y;
uint16 s, t;
Color color;
};
size_t getFormatStride(CommonFormat format);
int getIndexCount(TriangleIndexMode mode, int vertexCount);
void fillIndices(TriangleIndexMode mode, uint16 vertexStart, uint16 vertexCount, uint16 *indices);
void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount, uint32 *indices);
} // vertex
} // graphics
} // love
+3 -6
View File
@@ -738,7 +738,7 @@ function love.nogame()
local SIZE_Y = math.floor(wh / 32 + 2)
local SIZE = SIZE_X * SIZE_Y
self.batch = love.graphics.newSpriteBatch(mosaic_image, SIZE, "stream")
self.image = mosaic_image
self.pieces = {}
self.color_t = 1
self.generation = 1
@@ -915,8 +915,6 @@ function love.nogame()
end
function Mosaic:draw()
self.batch:clear()
love.graphics.setColor(1, 1, 1, 0.25)
for idx,piece in ipairs(self.pieces) do
local ct = 1 - self.color_t
local c0 = piece.color.prev
@@ -925,11 +923,10 @@ function love.nogame()
local g = easeOut(ct, c0[2], c1[2] - c0[2], 1)
local b = easeOut(ct, c0[3], c1[3] - c0[3], 1)
self.batch:setColor(r, g, b)
self.batch:add(piece.quad, piece.x, piece.y, piece.r, 1, 1, 16, 16)
love.graphics.setColor(r, g, b)
love.graphics.draw(self.image, piece.quad, piece.x, piece.y, piece.r, 1, 1, 16, 16)
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(self.batch, 0, 0)
end
function love.load()
+9 -19
View File
@@ -3148,11 +3148,8 @@ const unsigned char nogame_lua[] =
0x2b, 0x20, 0x32, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x53, 0x49, 0x5a, 0x45, 0x20, 0x3d, 0x20, 0x53, 0x49, 0x5a,
0x45, 0x5f, 0x58, 0x20, 0x2a, 0x20, 0x53, 0x49, 0x5a, 0x45, 0x5f, 0x59, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76,
0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x53, 0x70, 0x72, 0x69,
0x74, 0x65, 0x42, 0x61, 0x74, 0x63, 0x68, 0x28, 0x6d, 0x6f, 0x73, 0x61, 0x69, 0x63, 0x5f, 0x69, 0x6d, 0x61,
0x67, 0x65, 0x2c, 0x20, 0x53, 0x49, 0x5a, 0x45, 0x2c, 0x20, 0x22, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22,
0x29, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x3d, 0x20, 0x6d, 0x6f, 0x73,
0x61, 0x69, 0x63, 0x5f, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x69, 0x65, 0x63, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x7d, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x5f, 0x74, 0x20, 0x3d, 0x20, 0x31, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20,
@@ -3527,11 +3524,6 @@ const unsigned char nogame_lua[] =
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x4d, 0x6f, 0x73, 0x61, 0x69, 0x63, 0x3a, 0x64,
0x72, 0x61, 0x77, 0x28, 0x29, 0x0a,
0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x63, 0x6c, 0x65, 0x61, 0x72,
0x28, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65,
0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x30, 0x2e,
0x32, 0x35, 0x29, 0x0a,
0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x69, 0x64, 0x78, 0x2c, 0x70, 0x69, 0x65, 0x63, 0x65, 0x20, 0x69, 0x6e,
0x20, 0x69, 0x70, 0x61, 0x69, 0x72, 0x73, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x70, 0x69, 0x65, 0x63, 0x65,
0x73, 0x29, 0x20, 0x64, 0x6f, 0x0a,
@@ -3550,18 +3542,16 @@ const unsigned char nogame_lua[] =
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x65, 0x61, 0x73, 0x65, 0x4f,
0x75, 0x74, 0x28, 0x63, 0x74, 0x2c, 0x20, 0x63, 0x30, 0x5b, 0x33, 0x5d, 0x2c, 0x20, 0x63, 0x31, 0x5b, 0x33,
0x5d, 0x20, 0x2d, 0x20, 0x63, 0x30, 0x5b, 0x33, 0x5d, 0x2c, 0x20, 0x31, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x73, 0x65, 0x74, 0x43,
0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x72, 0x2c, 0x20, 0x67, 0x2c, 0x20, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x3a, 0x61, 0x64, 0x64, 0x28,
0x70, 0x69, 0x65, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x61, 0x64, 0x2c, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e,
0x78, 0x2c, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e, 0x79, 0x2c, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e,
0x72, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x36, 0x2c, 0x20, 0x31, 0x36, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73,
0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x72, 0x2c, 0x20, 0x67, 0x2c, 0x20, 0x62, 0x29, 0x0a,
0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x64,
0x72, 0x61, 0x77, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x70, 0x69,
0x65, 0x63, 0x65, 0x2e, 0x71, 0x75, 0x61, 0x64, 0x2c, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e, 0x78, 0x2c,
0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e, 0x79, 0x2c, 0x20, 0x70, 0x69, 0x65, 0x63, 0x65, 0x2e, 0x72, 0x2c,
0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x36, 0x2c, 0x20, 0x31, 0x36, 0x29, 0x0a,
0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x73, 0x65,
0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x28, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x2c, 0x20, 0x31, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x64, 0x72,
0x61, 0x77, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x61, 0x74, 0x63, 0x68, 0x2c, 0x20, 0x30, 0x2c, 0x20,
0x30, 0x29, 0x0a,
0x09, 0x65, 0x6e, 0x64, 0x0a,
0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6c, 0x6f, 0x61,
0x64, 0x28, 0x29, 0x0a,