Merge branch '12.0-development' into metal

This commit is contained in:
Alex Szpakowski
2020-02-28 23:21:08 -04:00
58 changed files with 26065 additions and 6331 deletions
-40
View File
@@ -38,46 +38,6 @@ Message::~Message()
{
}
int Message::toLua(lua_State *L)
{
luax_pushstring(L, name);
for (const Variant &v : args)
v.toLua(L);
return (int) args.size() + 1;
}
Message *Message::fromLua(lua_State *L, int n)
{
std::string name = luax_checkstring(L, n);
std::vector<Variant> vargs;
int count = lua_gettop(L) - n;
n++;
Variant varg;
for (int i = 0; i < count; i++)
{
if (lua_isnoneornil(L, n+i))
break;
luax_catchexcept(L, [&]() {
vargs.push_back(Variant::fromLua(L, n+i));
});
if (vargs.back().getType() == Variant::UNKNOWN)
{
vargs.clear();
luaL_error(L, "Argument %d can't be stored safely\nExpected boolean, number, string or userdata.", n+i);
return nullptr;
}
}
return new Message(name, vargs);
}
Event::~Event()
{
}
-3
View File
@@ -46,9 +46,6 @@ public:
Message(const std::string &name, const std::vector<Variant> &vargs = {});
~Message();
int toLua(lua_State *L);
static Message *fromLua(lua_State *L, int n);
const std::string name;
const std::vector<Variant> args;
+34 -11
View File
@@ -38,13 +38,23 @@ namespace event
#define instance() (Module::getInstance<Event>(Module::M_EVENT))
static int luax_pushmessage(lua_State *L, const Message &m)
{
luax_pushstring(L, m.name);
for (const Variant &v : m.args)
luax_pushvariant(L, v);
return (int) m.args.size() + 1;
}
static int w_poll_i(lua_State *L)
{
Message *m = nullptr;
if (instance()->poll(m))
if (instance()->poll(m) && m != nullptr)
{
int args = m->toLua(L);
int args = luax_pushmessage(L, *m);
m->release();
return args;
}
@@ -63,9 +73,9 @@ int w_wait(lua_State *L)
{
Message *m = nullptr;
luax_catchexcept(L, [&]() { m = instance()->wait(); });
if (m)
if (m != nullptr)
{
int args = m->toLua(L);
int args = luax_pushmessage(L, *m);
m->release();
return args;
}
@@ -75,15 +85,28 @@ int w_wait(lua_State *L)
int w_push(lua_State *L)
{
StrongRef<Message> m;
luax_catchexcept(L, [&]() { m.set(Message::fromLua(L, 1), Acquire::NORETAIN); });
std::string name = luax_checkstring(L, 1);
std::vector<Variant> vargs;
luax_pushboolean(L, m.get() != nullptr);
int nargs = lua_gettop(L);
for (int i = 2; i <= nargs; i++)
{
if (lua_isnoneornil(L, i))
break;
if (m.get() == nullptr)
return 1;
luax_catchexcept(L, [&]() { vargs.push_back(luax_checkvariant(L, i)); });
if (vargs.back().getType() == Variant::UNKNOWN)
{
vargs.clear();
return luaL_error(L, "Argument %d can't be stored safely\nExpected boolean, number, string or userdata.", i);
}
}
StrongRef<Message> m(new Message(name, vargs), Acquire::NORETAIN);
instance()->push(m);
luax_pushboolean(L, true);
return 1;
}
@@ -98,7 +121,7 @@ int w_quit(lua_State *L)
luax_catchexcept(L, [&]() {
std::vector<Variant> args;
for (int i = 1; i <= std::max(1, lua_gettop(L)); i++)
args.push_back(Variant::fromLua(L, i));
args.push_back(luax_checkvariant(L, i));
StrongRef<Message> m(new Message("quit", args), Acquire::NORETAIN);
instance()->push(m);
@@ -115,7 +138,7 @@ int w_restart(lua_State *L)
args.emplace_back("restart", strlen("restart"));
for (int i = 1; i <= lua_gettop(L); i++)
args.push_back(Variant::fromLua(L, i));
args.push_back(luax_checkvariant(L, i));
StrongRef<Message> m(new Message("quit", args), Acquire::NORETAIN);
instance()->push(m);
+1
View File
@@ -24,6 +24,7 @@
// LOVE
#include "common/config.h"
#include "Event.h"
#include "common/runtime.h"
namespace love
{
+13 -12
View File
@@ -22,6 +22,7 @@
#include "Font.h"
#include "BMFontRasterizer.h"
#include "ImageRasterizer.h"
#include "data/DataModule.h"
#include "libraries/utf8/utf8.h"
@@ -30,28 +31,28 @@ namespace love
namespace font
{
// Default TrueType font.
#include "Vera.ttf.h"
// Default TrueType font, gzip-compressed.
#include "NotoSans-Regular.ttf.gzip.h"
class DefaultFontData : public love::Data
Font::Font()
{
public:
auto compressedbytes = (const char *) NotoSans_Regular_ttf_gzip;
size_t compressedsize = NotoSans_Regular_ttf_gzip_len;
Data *clone() const override { return new DefaultFontData(); }
void *getData() const override { return Vera_ttf; }
size_t getSize() const override { return sizeof(Vera_ttf); }
};
size_t rawsize = 0;
char *fontdata = data::decompress(data::Compressor::FORMAT_GZIP, compressedbytes, compressedsize, rawsize);
defaultFontData.set(new data::ByteData(fontdata, rawsize, true), Acquire::NORETAIN);
}
Rasterizer *Font::newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting)
{
StrongRef<DefaultFontData> data(new DefaultFontData, Acquire::NORETAIN);
return newTrueTypeRasterizer(data.get(), size, hinting);
return newTrueTypeRasterizer(defaultFontData.get(), size, hinting);
}
Rasterizer *Font::newTrueTypeRasterizer(int size, float dpiscale, TrueTypeRasterizer::Hinting hinting)
{
StrongRef<DefaultFontData> data(new DefaultFontData, Acquire::NORETAIN);
return newTrueTypeRasterizer(data.get(), size, dpiscale, hinting);
return newTrueTypeRasterizer(defaultFontData.get(), size, dpiscale, hinting);
}
Rasterizer *Font::newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector<image::ImageData *> &images, float dpiscale)
+5
View File
@@ -43,6 +43,7 @@ class Font : public Module
public:
Font();
virtual ~Font() {}
virtual Rasterizer *newRasterizer(love::filesystem::FileData *data) = 0;
@@ -64,6 +65,10 @@ public:
virtual ModuleType getModuleType() const { return M_FONT; }
virtual const char *getName() const = 0;
private:
StrongRef<Data> defaultFontData;
}; // Font
} // font
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -72,7 +72,7 @@ int w_newTrueTypeRasterizer(lua_State *L)
if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1))
{
// First argument is a number: use the default TrueType font.
int size = (int) luaL_optinteger(L, 1, 12);
int size = (int) luaL_optinteger(L, 1, 13);
const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting))
+1 -1
View File
@@ -82,7 +82,7 @@ void Deprecations::draw(Graphics *gfx)
font.set(gfx->newDefaultFont(9, hinting), Acquire::NORETAIN);
}
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
gfx->push(Graphics::STACK_ALL);
gfx->reset();
+3 -3
View File
@@ -133,7 +133,7 @@ bool Font::loadVolatile()
void Font::createTexture()
{
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
Texture *texture = nullptr;
TextureSize size = {textureWidth, textureHeight};
@@ -645,13 +645,13 @@ void Font::printv(graphics::Graphics *gfx, const Matrix4 &t, const std::vector<D
for (const DrawCommand &cmd : drawcommands)
{
Graphics::StreamDrawCommand streamcmd;
Graphics::BatchedDrawCommand streamcmd;
streamcmd.formats[0] = vertexFormat;
streamcmd.indexMode = vertex::TriangleIndexMode::QUADS;
streamcmd.vertexCount = cmd.vertexcount;
streamcmd.texture = cmd.texture;
Graphics::StreamVertexData data = gfx->requestStreamDraw(streamcmd);
Graphics::BatchedVertexData data = gfx->requestBatchedDraw(streamcmd);
GlyphVertex *vertexdata = (GlyphVertex *) data.stream[0];
memcpy(vertexdata, &vertices[cmd.startvertex], sizeof(GlyphVertex) * cmd.vertexcount);
+22 -22
View File
@@ -145,7 +145,7 @@ Graphics::Graphics()
, created(false)
, active(true)
, writingToStencil(false)
, streamBufferState()
, batchedDrawState()
, projectionMatrix()
, renderTargetSwitchCount(0)
, drawCalls(0)
@@ -188,9 +188,9 @@ Graphics::~Graphics()
defaultFont.set(nullptr);
delete streamBufferState.vb[0];
delete streamBufferState.vb[1];
delete streamBufferState.indexBuffer;
delete batchedDrawState.vb[0];
delete batchedDrawState.vb[1];
delete batchedDrawState.indexBuffer;
for (int i = 0; i < (int) ShaderStage::STAGE_MAX_ENUM; i++)
cachedShaderStages[i].clear();
@@ -535,7 +535,7 @@ void Graphics::checkSetDefaultFont()
// Create a new default font if we don't have one yet.
if (!defaultFont.get())
defaultFont.set(newDefaultFont(12, font::TrueTypeRasterizer::HINTING_NORMAL), Acquire::NORETAIN);
defaultFont.set(newDefaultFont(13, font::TrueTypeRasterizer::HINTING_NORMAL), Acquire::NORETAIN);
states.back().font.set(defaultFont.get());
}
@@ -722,7 +722,7 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
int w = firsttex->getWidth(firsttarget.mipmap);
int h = firsttex->getHeight(firsttarget.mipmap);
flushStreamDraws();
flushBatchedDraws();
if (rts.depthStencil.texture == nullptr && rts.temporaryRTFlags != 0)
{
@@ -772,7 +772,7 @@ void Graphics::setRenderTarget()
if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.texture == nullptr)
return;
flushStreamDraws();
flushBatchedDraws();
setRenderTargetsInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect());
state.renderTargets = RenderTargetsStrongRef();
@@ -1017,11 +1017,11 @@ void Graphics::captureScreenshot(const ScreenshotInfo &info)
pendingScreenshotCallbacks.push_back(info);
}
Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &cmd)
Graphics::BatchedVertexData Graphics::requestBatchedDraw(const BatchedDrawCommand &cmd)
{
using namespace vertex;
StreamBufferState &state = streamBufferState;
BatchedDrawState &state = batchedDrawState;
bool shouldflush = false;
bool shouldresize = false;
@@ -1083,7 +1083,7 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &
if (shouldflush || shouldresize)
{
flushStreamDraws();
flushBatchedDraws();
state.primitiveMode = cmd.primitiveMode;
state.formats[0] = cmd.formats[0];
@@ -1127,7 +1127,7 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &
state.indexBufferMap.data += reqIndexSize;
}
StreamVertexData d;
BatchedVertexData d;
for (int i = 0; i < 2; i++)
{
@@ -1151,11 +1151,11 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawCommand &
return d;
}
void Graphics::flushStreamDraws()
void Graphics::flushBatchedDraws()
{
using namespace vertex;
auto &sbstate = streamBufferState;
auto &sbstate = batchedDrawState;
if (sbstate.vertexCount == 0 && sbstate.indexCount == 0)
return;
@@ -1226,15 +1226,15 @@ void Graphics::flushStreamDraws()
if (attributes.isEnabled(ATTRIB_COLOR))
setColor(nc);
streamBufferState.vertexCount = 0;
streamBufferState.indexCount = 0;
batchedDrawState.vertexCount = 0;
batchedDrawState.indexCount = 0;
}
void Graphics::flushStreamDrawsGlobal()
void Graphics::flushBatchedDrawsGlobal()
{
Graphics *instance = getInstance<Graphics>(M_GRAPHICS);
if (instance != nullptr)
instance->flushStreamDraws();
instance->flushBatchedDraws();
}
/**
@@ -1301,13 +1301,13 @@ void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t num
const Matrix4 &t = getTransform();
bool is2D = t.isAffine2DTransform();
StreamDrawCommand cmd;
BatchedDrawCommand cmd;
cmd.primitiveMode = PRIMITIVE_POINTS;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = vertex::CommonFormat::RGBAub;
cmd.vertexCount = (int) numpoints;
StreamVertexData data = requestStreamDraw(cmd);
BatchedVertexData data = requestBatchedDraw(cmd);
if (is2D)
t.transformXY((Vector2 *) data.stream[0], positions, cmd.vertexCount);
@@ -1597,13 +1597,13 @@ void Graphics::polygon(DrawMode mode, const Vector2 *coords, size_t count, bool
const Matrix4 &t = getTransform();
bool is2D = t.isAffine2DTransform();
StreamDrawCommand cmd;
BatchedDrawCommand cmd;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = vertex::CommonFormat::RGBAub;
cmd.indexMode = vertex::TriangleIndexMode::FAN;
cmd.vertexCount = (int)count - (skipLastFilledVertex ? 1 : 0);
StreamVertexData data = requestStreamDraw(cmd);
BatchedVertexData data = requestBatchedDraw(cmd);
if (is2D)
t.transformXY((Vector2 *) data.stream[0], coords, cmd.vertexCount);
@@ -1629,7 +1629,7 @@ Graphics::Stats Graphics::getStats() const
getAPIStats(stats.shaderSwitches);
stats.drawCalls = drawCalls;
if (streamBufferState.vertexCount > 0)
if (batchedDrawState.vertexCount > 0)
stats.drawCalls++;
stats.renderTargetSwitches = renderTargetSwitchCount;
+9 -9
View File
@@ -253,7 +253,7 @@ public:
{}
};
struct StreamDrawCommand
struct BatchedDrawCommand
{
PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
vertex::CommonFormat formats[2];
@@ -262,14 +262,14 @@ public:
Texture *texture = nullptr;
Shader::StandardShader standardShaderType = Shader::STANDARD_DEFAULT;
StreamDrawCommand()
BatchedDrawCommand()
{
// VS2013 can't initialize arrays in the above manner...
formats[1] = formats[0] = vertex::CommonFormat::NONE;
}
};
struct StreamVertexData
struct BatchedVertexData
{
void *stream[2];
};
@@ -827,10 +827,10 @@ public:
virtual void draw(const DrawIndexedCommand &cmd) = 0;
virtual void drawQuads(int start, int count, const vertex::Attributes &attributes, const vertex::BufferBindings &buffers, Texture *texture) = 0;
void flushStreamDraws();
StreamVertexData requestStreamDraw(const StreamDrawCommand &command);
void flushBatchedDraws();
BatchedVertexData requestBatchedDraw(const BatchedDrawCommand &command);
static void flushStreamDrawsGlobal();
static void flushBatchedDrawsGlobal();
virtual Shader::Language getShaderLanguageTarget() const = 0;
const DefaultShaderCode &getCurrentDefaultShaderCode() const;
@@ -918,7 +918,7 @@ protected:
SamplerState defaultSamplerState = SamplerState();
};
struct StreamBufferState
struct BatchedDrawState
{
StreamBuffer *vb[2];
StreamBuffer *indexBuffer = nullptr;
@@ -933,7 +933,7 @@ protected:
StreamBuffer::MapInfo vbMap[2];
StreamBuffer::MapInfo indexBufferMap = StreamBuffer::MapInfo();
StreamBufferState()
BatchedDrawState()
{
vb[0] = vb[1] = nullptr;
formats[0] = formats[1] = vertex::CommonFormat::NONE;
@@ -986,7 +986,7 @@ protected:
std::vector<ScreenshotInfo> pendingScreenshotCallbacks;
StreamBufferState streamBufferState;
BatchedDrawState batchedDrawState;
std::vector<Matrix4> transformStack;
Matrix4 projectionMatrix;
+1 -1
View File
@@ -584,7 +584,7 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING])
throw love::Exception("Instancing is not supported on this system.");
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
if (Shader::isDefaultActive())
Shader::attachDefault(Shader::STANDARD_DEFAULT);
+1 -1
View File
@@ -1029,7 +1029,7 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
if (pCount == 0 || texture.get() == nullptr || pMem == nullptr || buffer == nullptr)
return;
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
if (Shader::isDefaultActive())
Shader::attachDefault(Shader::STANDARD_DEFAULT);
+2 -2
View File
@@ -390,13 +390,13 @@ void Polyline::draw(love::graphics::Graphics *gfx)
{
const Vector2 *verts = vertices + vertex_start;
Graphics::StreamDrawCommand cmd;
Graphics::BatchedDrawCommand cmd;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = vertex::CommonFormat::RGBAub;
cmd.indexMode = triangle_mode;
cmd.vertexCount = std::min(maxvertices, total_vertex_count - vertex_start);
Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd);
Graphics::BatchedVertexData data = gfx->requestBatchedDraw(cmd);
if (is2D)
t.transformXY((Vector2 *) data.stream[0], verts, cmd.vertexCount);
+1 -1
View File
@@ -301,7 +301,7 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
if (next == 0)
return;
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
if (texture.get())
{
+1 -1
View File
@@ -246,7 +246,7 @@ void Text::draw(Graphics *gfx, const Matrix4 &m)
if (vertex_buffer == nullptr || draw_commands.empty())
return;
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
if (Shader::isDefaultActive())
Shader::attachDefault(Shader::STANDARD_DEFAULT);
+8 -8
View File
@@ -324,14 +324,14 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform)
const Matrix4 &tm = gfx->getTransform();
bool is2D = tm.isAffine2DTransform();
Graphics::StreamDrawCommand cmd;
Graphics::BatchedDrawCommand cmd;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = CommonFormat::STf_RGBAub;
cmd.indexMode = TriangleIndexMode::QUADS;
cmd.vertexCount = 4;
cmd.texture = this;
Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd);
Graphics::BatchedVertexData data = gfx->requestBatchedDraw(cmd);
Matrix4 t(tm, localTransform);
@@ -381,7 +381,7 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m)
Matrix4 t(tm, m);
Graphics::StreamDrawCommand cmd;
Graphics::BatchedDrawCommand cmd;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = CommonFormat::STPf_RGBAub;
cmd.indexMode = TriangleIndexMode::QUADS;
@@ -389,7 +389,7 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m)
cmd.texture = this;
cmd.standardShaderType = Shader::STANDARD_ARRAY;
Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd);
Graphics::BatchedVertexData data = gfx->requestBatchedDraw(cmd);
if (is2D)
t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4);
@@ -464,7 +464,7 @@ void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap
if (isPixelFormatCompressed(d->getFormat()) && (rect.x != 0 || rect.y != 0 || rect.w != mipw || rect.h != miph))
throw love::Exception("Compressed textures only support replacing the entire Texture.");
Graphics::flushStreamDrawsGlobal();
Graphics::flushBatchedDrawsGlobal();
uploadImageData(d, mipmap, slice, x, y);
@@ -481,7 +481,7 @@ void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap
if (gfx != nullptr && gfx->isRenderTargetActive(this))
return;
Graphics::flushStreamDrawsGlobal();
Graphics::flushBatchedDrawsGlobal();
uploadByteData(format, data, size, mipmap, slice, rect, nullptr);
@@ -631,7 +631,7 @@ void Texture::setSamplerState(const SamplerState &s)
if (s.depthSampleMode.hasValue && !isPixelFormatDepth(format))
throw love::Exception("Only depth textures can have a depth sample compare mode.");
Graphics::flushStreamDrawsGlobal();
Graphics::flushBatchedDrawsGlobal();
samplerState = s;
@@ -908,7 +908,7 @@ static StringMap<Texture::SettingType, Texture::SETTING_MAX_ENUM>::Entry setting
{ "type", Texture::SETTING_TYPE },
{ "dpiscale", Texture::SETTING_DPI_SCALE },
{ "msaa", Texture::SETTING_MSAA },
{ "rendertarget", Texture::SETTING_RENDER_TARGET },
{ "canvas", Texture::SETTING_RENDER_TARGET },
{ "readable", Texture::SETTING_READABLE },
};
+3 -3
View File
@@ -120,14 +120,14 @@ void Video::draw(Graphics *gfx, const Matrix4 &m)
Matrix4 t(tm, m);
Graphics::StreamDrawCommand cmd;
Graphics::BatchedDrawCommand cmd;
cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
cmd.formats[1] = vertex::CommonFormat::STf_RGBAub;
cmd.indexMode = vertex::TriangleIndexMode::QUADS;
cmd.vertexCount = 4;
cmd.standardShaderType = Shader::STANDARD_VIDEO;
Graphics::StreamVertexData data = gfx->requestStreamDraw(cmd);
Graphics::BatchedVertexData data = gfx->requestBatchedDraw(cmd);
if (is2D)
t.transformXY((Vector2 *) data.stream[0], vertices, 4);
@@ -148,7 +148,7 @@ void Video::draw(Graphics *gfx, const Matrix4 &m)
if (Shader::current != nullptr)
Shader::current->setVideoTextures(textures[0], textures[1], textures[2]);
gfx->flushStreamDraws();
gfx->flushBatchedDraws();
}
void Video::update()
+24 -24
View File
@@ -251,13 +251,13 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
setDebug(isDebugEnabled());
if (streamBufferState.vb[0] == nullptr)
if (batchedDrawState.vb[0] == nullptr)
{
// Initial sizes that should be good enough for most cases. It will
// resize to fit if needed, later.
streamBufferState.vb[0] = CreateStreamBuffer(BUFFER_VERTEX, 1024 * 1024 * 1);
streamBufferState.vb[1] = CreateStreamBuffer(BUFFER_VERTEX, 256 * 1024 * 1);
streamBufferState.indexBuffer = CreateStreamBuffer(BUFFER_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
batchedDrawState.vb[0] = CreateStreamBuffer(BUFFER_VERTEX, 1024 * 1024 * 1);
batchedDrawState.vb[1] = CreateStreamBuffer(BUFFER_VERTEX, 256 * 1024 * 1);
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFER_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
}
// Reload all volatile objects.
@@ -310,7 +310,7 @@ void Graphics::unSetMode()
if (!isCreated())
return;
flushStreamDraws();
flushBatchedDraws();
// Unload all volatile objects. These must be reloaded after the display
// mode change.
@@ -338,7 +338,7 @@ void Graphics::unSetMode()
void Graphics::setActive(bool enable)
{
flushStreamDraws();
flushBatchedDraws();
// Make sure all pending OpenGL commands have fully executed before
// returning, when going from active to inactive. This is required on iOS.
@@ -637,7 +637,7 @@ void Graphics::endPass()
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
{
if (c.hasValue || stencil.hasValue || depth.hasValue)
flushStreamDraws();
flushBatchedDraws();
GLbitfield flags = 0;
@@ -694,7 +694,7 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
return;
}
flushStreamDraws();
flushBatchedDraws();
bool drawbuffersmodified = false;
ncolors = std::min(ncolors, ncolorRTs);
@@ -770,7 +770,7 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
{
flushStreamDraws();
flushBatchedDraws();
discard(OpenGL::FRAMEBUFFER_ALL, colorbuffers, depthstencil);
}
@@ -951,7 +951,7 @@ void Graphics::present(void *screenshotCallbackData)
deprecations.draw(this);
flushStreamDraws();
flushBatchedDraws();
endPass();
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
@@ -1054,9 +1054,9 @@ void Graphics::present(void *screenshotCallbackData)
glBindRenderbuffer(GL_RENDERBUFFER, info.info.uikit.colorbuffer);
#endif
for (StreamBuffer *buffer : streamBufferState.vb)
for (StreamBuffer *buffer : batchedDrawState.vb)
buffer->nextFrame();
streamBufferState.indexBuffer->nextFrame();
batchedDrawState.indexBuffer->nextFrame();
auto window = getInstance<love::window::Window>(M_WINDOW);
if (window != nullptr)
@@ -1084,7 +1084,7 @@ void Graphics::present(void *screenshotCallbackData)
void Graphics::setScissor(const Rect &rect)
{
flushStreamDraws();
flushBatchedDraws();
DisplayState &state = states.back();
@@ -1109,7 +1109,7 @@ void Graphics::setScissor(const Rect &rect)
void Graphics::setScissor()
{
if (states.back().scissor)
flushStreamDraws();
flushBatchedDraws();
states.back().scissor = false;
@@ -1127,7 +1127,7 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
throw love::Exception("Drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type texture to be used, in setRenderTarget.");
flushStreamDraws();
flushBatchedDraws();
writingToStencil = true;
@@ -1172,7 +1172,7 @@ void Graphics::stopDrawToStencilBuffer()
if (!writingToStencil)
return;
flushStreamDraws();
flushBatchedDraws();
writingToStencil = false;
@@ -1190,7 +1190,7 @@ void Graphics::setStencilTest(CompareMode compare, int value)
DisplayState &state = states.back();
if (state.stencilCompare != compare || state.stencilTestValue != value)
flushStreamDraws();
flushBatchedDraws();
state.stencilCompare = compare;
state.stencilTestValue = value;
@@ -1227,7 +1227,7 @@ void Graphics::setDepthMode(CompareMode compare, bool write)
DisplayState &state = states.back();
if (state.depthTest != compare || state.depthWrite != write)
flushStreamDraws();
flushBatchedDraws();
state.depthTest = compare;
state.depthWrite = write;
@@ -1249,7 +1249,7 @@ void Graphics::setFrontFaceWinding(vertex::Winding winding)
DisplayState &state = states.back();
if (state.winding != winding)
flushStreamDraws();
flushBatchedDraws();
state.winding = winding;
@@ -1271,7 +1271,7 @@ void Graphics::setColor(Colorf c)
void Graphics::setColorMask(ColorChannelMask mask)
{
flushStreamDraws();
flushBatchedDraws();
glColorMask(mask.r, mask.g, mask.b, mask.a);
states.back().colorMask = mask;
@@ -1280,7 +1280,7 @@ void Graphics::setColorMask(ColorChannelMask mask)
void Graphics::setBlendState(const BlendState &blend)
{
if (!(blend == states.back().blend))
flushStreamDraws();
flushBatchedDraws();
if (blend.operationRGB == BLENDOP_MAX || blend.operationA == BLENDOP_MAX
|| blend.operationRGB == BLENDOP_MIN || blend.operationA == BLENDOP_MIN)
@@ -1310,8 +1310,8 @@ void Graphics::setBlendState(const BlendState &blend)
void Graphics::setPointSize(float size)
{
if (streamBufferState.primitiveMode == PRIMITIVE_POINTS)
flushStreamDraws();
if (batchedDrawState.primitiveMode == PRIMITIVE_POINTS)
flushBatchedDraws();
gl.setPointSize(size * getCurrentDPIScale());
states.back().pointSize = size;
@@ -1323,7 +1323,7 @@ void Graphics::setWireframe(bool enable)
if (GLAD_ES_VERSION_2_0)
return;
flushStreamDraws();
flushBatchedDraws();
glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
states.back().wireframe = enable;
+5 -5
View File
@@ -429,7 +429,7 @@ void Shader::attach()
{
if (current != this)
{
Graphics::flushStreamDrawsGlobal();
Graphics::flushBatchedDrawsGlobal();
gl.useProgram(program);
current = this;
@@ -480,7 +480,7 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
}
if (!internalupdate)
flushStreamDraws();
flushBatchedDraws();
int location = info->location;
UniformType type = info->baseType;
@@ -578,7 +578,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
bool shaderactive = current == this;
if (!internalUpdate && shaderactive)
flushStreamDraws();
flushBatchedDraws();
count = std::min(count, info->count);
@@ -644,10 +644,10 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
}
}
void Shader::flushStreamDraws() const
void Shader::flushBatchedDraws() const
{
if (current == this)
Graphics::flushStreamDrawsGlobal();
Graphics::flushBatchedDrawsGlobal();
}
bool Shader::hasUniform(const std::string &name) const
+1 -1
View File
@@ -90,7 +90,7 @@ private:
TextureType getUniformTextureType(GLenum type) const;
bool isDepthTextureType(GLenum type) const;
void flushStreamDraws() const;
void flushBatchedDraws() const;
// Get any warnings or errors generated only by the shader program object.
std::string getProgramWarnings() const;
+10 -31
View File
@@ -263,7 +263,7 @@ static Graphics::RenderTarget checkRenderTarget(lua_State *L, int idx)
return target;
}
int w_setRenderTarget(lua_State *L)
int w_setCanvas(lua_State *L)
{
// Disable stencil writes.
luax_catchexcept(L, [](){ instance()->stopDrawToStencilBuffer(); });
@@ -295,7 +295,7 @@ int w_setRenderTarget(lua_State *L)
targets.colors.emplace_back(luax_checktexture(L, -1), 0);
if (targets.colors.back().texture->getTextureType() != TEXTURE_2D)
return luaL_error(L, "Non-2D textures must use the table-of-tables variant of setRenderTargets.");
return luaL_error(L, "Non-2D textures must use the table-of-tables variant of setCanvas.");
}
lua_pop(L, 1);
@@ -341,7 +341,7 @@ int w_setRenderTarget(lua_State *L)
}
if (i > 1 && type != TEXTURE_2D)
return luaL_error(L, "This variant of setRenderTarget only supports 2D texture types.");
return luaL_error(L, "This variant of setCanvas only supports 2D texture types.");
targets.colors.push_back(target);
}
@@ -357,12 +357,6 @@ int w_setRenderTarget(lua_State *L)
return 0;
}
int w_setCanvas(lua_State *L)
{
luax_markdeprecated(L, "love.graphics.setCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.setRenderTarget");
return w_setRenderTarget(L);
}
static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt)
{
lua_createtable(L, 1, 2);
@@ -387,7 +381,7 @@ static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt)
lua_setfield(L, -2, "mipmap");
}
int w_getRenderTarget(lua_State *L)
int w_getCanvas(lua_State *L)
{
Graphics::RenderTargets targets = instance()->getRenderTargets();
int ntargets = (int) targets.colors.size();
@@ -439,12 +433,6 @@ int w_getRenderTarget(lua_State *L)
}
}
int w_getCanvas(lua_State *L)
{
luax_markdeprecated(L, "love.graphics.getCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.getRenderTarget");
return w_getRenderTarget(L);
}
static void screenshotFunctionCallback(const Graphics::ScreenshotInfo *info, love::image::ImageData *i, void *gd)
{
if (info == nullptr)
@@ -831,7 +819,7 @@ static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool chec
lua_pop(L, 1);
}
int w_newRenderTarget(lua_State *L)
int w_newCanvas(lua_State *L)
{
luax_checkgraphicscreated(L);
@@ -1209,12 +1197,6 @@ int w_newVolumeTexture(lua_State *L)
return w__pushNewTexture(L, slicesref, settings);
}
int w_newCanvas(lua_State *L)
{
luax_markdeprecated(L, "love.graphics.newCanvas", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newRenderTarget");
return w_newRenderTarget(L);
}
int w_newImage(lua_State *L)
{
luax_markdeprecated(L, "love.graphics.newImage", API_FUNCTION, DEPRECATED_RENAMED, "love.graphics.newTexture");
@@ -2562,7 +2544,7 @@ int w_getStats(lua_State *L)
lua_setfield(L, -2, "drawcallsbatched");
lua_pushinteger(L, stats.renderTargetSwitches);
lua_setfield(L, -2, "rendertargetswitches");
lua_setfield(L, -2, "canvasswitches");
lua_pushinteger(L, stats.shaderSwitches);
lua_setfield(L, -2, "shaderswitches");
@@ -3047,7 +3029,7 @@ int w_polygon(lua_State *L)
int w_flushBatch(lua_State *)
{
instance()->flushStreamDraws();
instance()->flushBatchedDraws();
return 0;
}
@@ -3163,7 +3145,7 @@ static const luaL_Reg functions[] =
{ "discard", w_discard },
{ "present", w_present },
{ "newRenderTarget", w_newRenderTarget },
{ "newCanvas", w_newCanvas },
{ "newTexture", w_newTexture },
{ "newCubeTexture", w_newCubeTexture },
{ "newArrayTexture", w_newArrayTexture },
@@ -3180,8 +3162,8 @@ static const luaL_Reg functions[] =
{ "validateShader", w_validateShader },
{ "setRenderTarget", w_setRenderTarget },
{ "getRenderTarget", w_getRenderTarget },
{ "setCanvas", w_setCanvas },
{ "getCanvas", w_getCanvas },
{ "setColor", w_setColor },
{ "getColor", w_getColor },
@@ -3282,13 +3264,10 @@ static const luaL_Reg functions[] =
{ "inverseTransformPoint", w_inverseTransformPoint },
// Deprecated
{ "newCanvas", w_newCanvas },
{ "newImage", w_newImage },
{ "newArrayImage", w_newArrayImage },
{ "newVolumeImage", w_newVolumeImage },
{ "newCubeImage", w_newCubeImage },
{ "setCanvas", w_setCanvas },
{ "getCanvas", w_getCanvas },
{ "getCanvasFormats", w_getCanvasFormats },
{ "getImageFormats", w_getImageFormats },
+19 -9
View File
@@ -411,14 +411,18 @@ int w_Shader_send(lua_State *L)
const Shader::UniformInfo *info = shader->getUniformInfo(name);
if (info == nullptr)
return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name);
{
luax_pushboolean(L, false);
return 1;
}
int startidx = 3;
if (luax_istype(L, startidx, Data::type))
return w_Shader_sendData(L, startidx, shader, info, false);
if (luax_istype(L, 3, Data::type))
w_Shader_sendData(L, 3, shader, info, false);
else
return w_Shader_sendLuaValues(L, startidx, shader, info, name);
w_Shader_sendLuaValues(L, 3, shader, info, name);
luax_pushboolean(L, true);
return 1;
}
int w_Shader_sendColors(lua_State *L)
@@ -428,15 +432,21 @@ int w_Shader_sendColors(lua_State *L)
const Shader::UniformInfo *info = shader->getUniformInfo(name);
if (info == nullptr)
return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name);
{
luax_pushboolean(L, false);
return 1;
}
if (info->baseType != Shader::UNIFORM_FLOAT || info->components < 3)
return luaL_error(L, "sendColor can only be used on vec3 or vec4 uniforms.");
if (luax_istype(L, 3, Data::type))
return w_Shader_sendData(L, 3, shader, info, true);
w_Shader_sendData(L, 3, shader, info, true);
else
return w_Shader_sendFloats(L, 3, shader, info, true);
w_Shader_sendFloats(L, 3, shader, info, true);
luax_pushboolean(L, true);
return 1;
}
int w_Shader_hasUniform(lua_State *L)
+1 -1
View File
@@ -25,7 +25,7 @@
#include "common/Data.h"
#include "sound/Decoder.h"
#include "dr_flac/dr_flac.h"
#include "dr/dr_flac.h"
#include <string.h>
namespace love
+144
View File
@@ -0,0 +1,144 @@
/**
* Copyright (c) 2006-2020 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.
**/
#define DR_MP3_IMPLEMENTATION
#define DR_MP3_NO_STDIO
#include "MP3Decoder.h"
namespace love
{
namespace sound
{
namespace lullaby
{
MP3Decoder::MP3Decoder(Data *data, int bufferSize)
: Decoder(data, bufferSize)
{
// initialize mp3 handle
if(drmp3_init_memory(&mp3, data->getData(), data->getSize(), nullptr, nullptr) == 0)
throw love::Exception("Could not read mp3 data.");
sampleRate = mp3.sampleRate;
// calculate duration
drmp3_uint64 pcmCount, mp3FrameCount;
if (!drmp3_get_mp3_and_pcm_frame_count(&mp3, &mp3FrameCount, &pcmCount))
{
drmp3_uninit(&mp3);
throw love::Exception("Could not calculate duration.");
}
duration = ((double) pcmCount) / ((double) mp3.sampleRate);
// create seek table
uint32_t mp3FrameInt = mp3FrameCount;
seekTable.resize(mp3FrameCount, {0ULL, 0ULL, 0, 0});
if (!drmp3_calculate_seek_points(&mp3, &mp3FrameInt, seekTable.data()))
{
drmp3_uninit(&mp3);
throw love::Exception("Could not calculate seek table");
}
mp3FrameInt = mp3FrameInt > mp3FrameCount ? mp3FrameCount : mp3FrameInt;
// bind seek table
if (!drmp3_bind_seek_table(&mp3, mp3FrameInt, seekTable.data()))
{
drmp3_uninit(&mp3);
throw love::Exception("Could not bind seek table");
}
}
MP3Decoder::~MP3Decoder()
{
drmp3_uninit(&mp3);
}
bool MP3Decoder::accepts(const std::string &ext)
{
static const std::string supported[] =
{
"mp3", ""
};
for (int i = 0; !(supported[i].empty()); i++)
{
if (supported[i].compare(ext) == 0)
return true;
}
return false;
}
love::sound::Decoder *MP3Decoder::clone()
{
return new MP3Decoder(data, bufferSize);
}
int MP3Decoder::decode()
{
// bufferSize is in char
int maxRead = bufferSize / sizeof(int16_t) / mp3.channels;
int read = (int) drmp3_read_pcm_frames_s16(&mp3, maxRead, (drmp3_int16 *) buffer);
if (read < maxRead)
eof = true;
return read * sizeof(int16_t) * mp3.channels;
}
bool MP3Decoder::seek(double s)
{
drmp3_uint64 targetSample = s * mp3.sampleRate;
drmp3_bool32 success = drmp3_seek_to_pcm_frame(&mp3, targetSample);
if (success)
eof = false;
return success;
}
bool MP3Decoder::rewind()
{
return seek(0.0);
}
bool MP3Decoder::isSeekable()
{
return true;
}
int MP3Decoder::getChannelCount() const
{
return mp3.channels;
}
int MP3Decoder::getBitDepth() const
{
return 16;
}
double MP3Decoder::getDuration()
{
return duration;
}
} // lullaby
} // sound
} // love
@@ -18,21 +18,17 @@
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_SOUND_LULLABY_LIBMPG123_DECODER_H
#define LOVE_SOUND_LULLABY_LIBMPG123_DECODER_H
#ifndef LOVE_SOUND_LULLABY_MP3_DECODER_H
#define LOVE_SOUND_LULLABY_MP3_DECODER_H
// LOVE
#include "common/Data.h"
#include "sound/Decoder.h"
#ifndef LOVE_NOMPG123
// dr_mp3
#include "dr/dr_mp3.h"
// libmpg123
#ifdef LOVE_APPLE_USE_FRAMEWORKS
#include <mpg123/mpg123.h>
#else
#include <mpg123.h>
#endif
#include <vector>
namespace love
{
@@ -41,29 +37,14 @@ namespace sound
namespace lullaby
{
struct DecoderFile
{
unsigned char *data;
size_t size;
size_t offset;
DecoderFile(Data *d)
: data((unsigned char *) d->getData())
, size(d->getSize())
, offset(0)
{}
};
class Mpg123Decoder : public Decoder
class MP3Decoder: public love::sound::Decoder
{
public:
Mpg123Decoder(Data *data, int bufferSize);
virtual ~Mpg123Decoder();
MP3Decoder(Data *data, int bufsize);
virtual ~MP3Decoder();
static bool accepts(const std::string &ext);
static void quit();
love::sound::Decoder *clone();
int decode();
bool seek(double s);
@@ -75,21 +56,16 @@ public:
private:
DecoderFile decoder_file;
mpg123_handle *handle;
static bool inited;
int channels;
// MP3 handle
drmp3 mp3;
// Used for fast seeking
std::vector<drmp3_seek_point> seekTable;
double duration;
}; // Decoder
}; // MP3Decoder
} // lullaby
} // sound
} // love
#endif // LOVE_NOMPG123
#endif // LOVE_SOUND_LULLABY_LIBMPG123_DECODER_H
#endif
-298
View File
@@ -1,298 +0,0 @@
/**
* Copyright (c) 2006-2020 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 "Mpg123Decoder.h"
#include "common/Exception.h"
#include <iostream>
#ifndef LOVE_NOMPG123
namespace love
{
namespace sound
{
namespace lullaby
{
/**
* mpg123 callbacks for seekable streams.
**/
static ssize_t read_callback(void *udata, void *buffer, size_t count)
{
DecoderFile *file = (DecoderFile *) udata;
// Calculates how much data is still left and takes that value or
// the buffer size, whichever is lower, as the number of bytes to write.
size_t countLeft = file->size - file->offset;
size_t countWrite = countLeft < count ? countLeft : count;
if (countWrite > 0)
{
memcpy(buffer, file->data + file->offset, countWrite);
file->offset += countWrite;
}
// Returns the number of written bytes. 0 means EOF.
return countWrite;
}
static off_t seek_callback(void *udata, off_t offset, int whence)
{
DecoderFile *file = (DecoderFile *) udata;
switch (whence)
{
case SEEK_SET:
// Negative values are invalid at this point.
if (offset < 0)
return -1;
// Prevents the offset from going over EOF.
if (file->size > (size_t) offset)
file->offset = offset;
else
file->offset = file->size;
break;
case SEEK_END:
// Offset is set to EOF. Offset calculation is just like SEEK_CUR.
file->offset = file->size;
case SEEK_CUR:
// Prevents the offset from going over EOF or below 0.
if (offset > 0)
{
if (file->size > file->offset + (size_t) offset)
file->offset = file->offset + offset;
else
file->offset = file->size;
}
else if (offset < 0)
{
if (file->offset >= (size_t) (-offset))
file->offset = file->offset - (size_t) (-offset);
else
file->offset = 0;
}
break;
default:
return -1;
};
return file->offset;
}
static void cleanup_callback(void *)
{
// Cleanup is done by the Decoder class.
}
bool Mpg123Decoder::inited = false;
Mpg123Decoder::Mpg123Decoder(Data *data, int bufferSize)
: Decoder(data, bufferSize)
, decoder_file(data)
, handle(0)
, channels(MPG123_STEREO)
, duration(-2.0)
{
int ret = 0;
if (!inited)
{
ret = mpg123_init();
if (ret != MPG123_OK)
throw love::Exception("Could not initialize mpg123.");
inited = (ret == MPG123_OK);
}
// Intialize the handle.
handle = mpg123_new(nullptr, nullptr);
if (handle == nullptr)
throw love::Exception("Could not create decoder.");
// Suppressing all mpg123 messages.
mpg123_param(handle, MPG123_ADD_FLAGS, MPG123_QUIET, 0);
try
{
ret = mpg123_replace_reader_handle(handle, &read_callback, &seek_callback, &cleanup_callback);
if (ret != MPG123_OK)
throw love::Exception("Could not set decoder callbacks.");
ret = mpg123_open_handle(handle, &decoder_file);
if (ret != MPG123_OK)
throw love::Exception("Could not open decoder.");
// mpg123_getformat should be able to tell us the properties of the stream's first frame.
long rate = 0;
ret = mpg123_getformat(handle, &rate, &channels, nullptr);
if (ret == MPG123_ERR)
throw love::Exception("Could not get stream information.");
// I forgot what this was about.
if (channels == 0)
channels = 2;
// Force signed 16-bit output.
mpg123_param(handle, MPG123_FLAGS, (channels == 2 ? MPG123_FORCE_STEREO : MPG123_MONO_MIX), 0);
mpg123_format_none(handle);
mpg123_format(handle, rate, channels, MPG123_ENC_SIGNED_16);
sampleRate = (int) rate;
// Force a read, so we can determine if it's actually an mp3
struct mpg123_frameinfo info;
ret = mpg123_info(handle, &info);
if (ret != MPG123_OK)
throw love::Exception("Could not read mp3 data.");
}
catch (love::Exception &)
{
mpg123_delete(handle);
throw;
}
}
Mpg123Decoder::~Mpg123Decoder()
{
mpg123_delete(handle);
}
bool Mpg123Decoder::accepts(const std::string &ext)
{
static const std::string supported[] =
{
"mp3", ""
};
for (int i = 0; !(supported[i].empty()); i++)
{
if (supported[i].compare(ext) == 0)
return true;
}
return false;
}
void Mpg123Decoder::quit()
{
if (inited)
mpg123_exit();
}
love::sound::Decoder *Mpg123Decoder::clone()
{
return new Mpg123Decoder(data.get(), bufferSize);
}
int Mpg123Decoder::decode()
{
int size = 0;
while (size < bufferSize && !eof)
{
size_t numbytes = 0;
int res = mpg123_read(handle, (unsigned char *) buffer + size, bufferSize - size, &numbytes);
switch (res)
{
case MPG123_NEED_MORE:
case MPG123_NEW_FORMAT:
case MPG123_OK:
size += numbytes;
continue;
case MPG123_DONE:
size += numbytes;
eof = true;
default:
return size;
}
}
return size;
}
bool Mpg123Decoder::seek(double s)
{
off_t offset = (off_t) (s * (double) sampleRate);
if (offset < 0)
return false;
if (mpg123_seek(handle, offset, SEEK_SET) >= 0)
{
eof = false;
return true;
}
else
return false;
}
bool Mpg123Decoder::rewind()
{
eof = false;
if (mpg123_seek(handle, 0, SEEK_SET) >= 0)
return true;
else
return false;
}
bool Mpg123Decoder::isSeekable()
{
return true;
}
int Mpg123Decoder::getChannelCount() const
{
return channels;
}
int Mpg123Decoder::getBitDepth() const
{
return 16;
}
double Mpg123Decoder::getDuration()
{
// Only calculate the duration if we haven't done so already.
if (duration == -2.0)
{
mpg123_scan(handle);
off_t length = mpg123_length(handle);
if (length == MPG123_ERR || length < 0)
duration = -1.0;
else
duration = (double) length / (double) sampleRate;
}
return duration;
}
} // lullaby
} // sound
} // love
#endif // LOVE_NOMPG123
+2 -10
View File
@@ -30,10 +30,7 @@
#include "GmeDecoder.h"
#include "WaveDecoder.h"
#include "FLACDecoder.h"
#ifndef LOVE_NOMPG123
# include "Mpg123Decoder.h"
#endif // LOVE_NOMPG123
#include "MP3Decoder.h"
#ifdef LOVE_SUPPORT_COREAUDIO
# include "CoreAudioDecoder.h"
@@ -73,9 +70,6 @@ Sound::Sound()
Sound::~Sound()
{
#ifndef LOVE_NOMPG123
Mpg123Decoder::quit();
#endif // LOVE_NOMPG123
}
const char *Sound::getName() const
@@ -92,9 +86,7 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi
#ifndef LOVE_NO_MODPLUG
DecoderImplFor<ModPlugDecoder>(),
#endif // LOVE_NO_MODPLUG
#ifndef LOVE_NOMPG123
DecoderImplFor<Mpg123Decoder>(),
#endif // LOVE_NOMPG123
DecoderImplFor<MP3Decoder>(),
DecoderImplFor<VorbisDecoder>(),
#ifdef LOVE_SUPPORT_GME
DecoderImplFor<GmeDecoder>(),
+1 -1
View File
@@ -37,7 +37,7 @@ namespace lullaby
/**
* The love.sound.lullaby module is the custom sound decoder module for LOVE. Instead
* of using an intermediate library like SDL_sound, it interfaces with relevant libraries
* directly (libmpg123, libmodplug, libFLAC, etc).
* directly (libvorbis, dr_mp3, dr_flac, etc).
*
* It was Mike that came up with the name Lullaby, which we both instantly recognized as awesome.
**/
+2 -5
View File
@@ -36,9 +36,6 @@ namespace thread
class Channel : public love::Object
{
// FOR WRAPPER USE ONLY
friend int w_Channel_performAtomic(lua_State *);
public:
static love::Type type;
@@ -57,11 +54,11 @@ public:
bool hasRead(uint64 id) const;
void clear();
private:
void lockMutex();
void unlockMutex();
private:
MutexRef mutex;
ConditionalRef cond;
std::queue<Variant> queue;
+2 -1
View File
@@ -21,6 +21,7 @@
#include "LuaThread.h"
#include "event/Event.h"
#include "common/config.h"
#include "common/runtime.h"
#ifdef LOVE_BUILD_STANDALONE
extern "C" int luaopen_love(lua_State * L);
@@ -76,7 +77,7 @@ void LuaThread::threadFunction()
int pushedargs = (int) args.size();
for (int i = 0; i < pushedargs; i++)
args[i].toLua(L);
luax_pushvariant(L, args[i]);
args.clear();
+5 -5
View File
@@ -34,7 +34,7 @@ int w_Channel_push(lua_State *L)
{
Channel *c = luax_checkchannel(L, 1);
luax_catchexcept(L, [&]() {
Variant var = Variant::fromLua(L, 2);
Variant var = luax_checkvariant(L, 2);
if (var.getType() == Variant::UNKNOWN)
luaL_argerror(L, 2, "boolean, number, string, love type, or table expected");
uint64 id = c->push(var);
@@ -48,7 +48,7 @@ int w_Channel_supply(lua_State *L)
Channel *c = luax_checkchannel(L, 1);
bool result = false;
luax_catchexcept(L, [&]() {
Variant var = Variant::fromLua(L, 2);
Variant var = luax_checkvariant(L, 2);
if (var.getType() == Variant::UNKNOWN)
luaL_argerror(L, 2, "boolean, number, string, love type, or table expected");
if (lua_isnumber(L, 3))
@@ -66,7 +66,7 @@ int w_Channel_pop(lua_State *L)
Channel *c = luax_checkchannel(L, 1);
Variant var;
if (c->pop(&var))
var.toLua(L);
luax_pushvariant(L, var);
else
lua_pushnil(L);
return 1;
@@ -84,7 +84,7 @@ int w_Channel_demand(lua_State *L)
result = c->demand(&var);
if (result)
var.toLua(L);
luax_pushvariant(L, var);
else
lua_pushnil(L);
return 1;
@@ -95,7 +95,7 @@ int w_Channel_peek(lua_State *L)
Channel *c = luax_checkchannel(L, 1);
Variant var;
if (c->peek(&var))
var.toLua(L);
luax_pushvariant(L, var);
else
lua_pushnil(L);
return 1;
+1
View File
@@ -23,6 +23,7 @@
// LOVE
#include "Channel.h"
#include "common/runtime.h"
namespace love
{
+1 -1
View File
@@ -39,7 +39,7 @@ int w_Thread_start(lua_State *L)
for (int i = 0; i < nargs; ++i)
{
luax_catchexcept(L, [&]() {
args.push_back(Variant::fromLua(L, i+2));
args.push_back(luax_checkvariant(L, i+2));
});
if (args.back().getType() == Variant::UNKNOWN)
+1
View File
@@ -23,6 +23,7 @@
// LOVE
#include "ThreadModule.h"
#include "common/runtime.h"
namespace love
{