mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
Move backend-agnostic Mesh and SpriteBatch code out of the opengl implementation folder.
--HG-- branch : minor
This commit is contained in:
@@ -118,12 +118,12 @@ graphics::Font *Graphics::newFont(love::font::Rasterizer *r, const Texture::Filt
|
||||
return new Font(r, filter);
|
||||
}
|
||||
|
||||
SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, vertex::Usage usage)
|
||||
love::graphics::SpriteBatch *Graphics::newSpriteBatch(Texture *texture, int size, vertex::Usage usage)
|
||||
{
|
||||
return new SpriteBatch(this, texture, size, usage);
|
||||
}
|
||||
|
||||
ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
|
||||
love::graphics::ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
|
||||
{
|
||||
return new ParticleSystem(this, texture, size);
|
||||
}
|
||||
@@ -167,22 +167,22 @@ love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, Buffe
|
||||
return new Buffer(size, data, type, usage, mapflags);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
love::graphics::Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
{
|
||||
return new Mesh(this, vertices, drawmode, usage);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
love::graphics::Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
{
|
||||
return new Mesh(this, vertexcount, drawmode, usage);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
love::graphics::Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
{
|
||||
return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
|
||||
}
|
||||
|
||||
Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
love::graphics::Mesh *Graphics::newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage)
|
||||
{
|
||||
return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
|
||||
}
|
||||
@@ -498,11 +498,6 @@ void Graphics::flushStreamDraws()
|
||||
streamBufferState.indexCount = 0;
|
||||
}
|
||||
|
||||
void Graphics::drawInstanced(Mesh *mesh, const love::Matrix4 &m, int instancecount)
|
||||
{
|
||||
mesh->drawInstanced(this, m, instancecount);
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@@ -66,9 +66,9 @@ public:
|
||||
|
||||
love::graphics::Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::defaultFilter) override;
|
||||
|
||||
SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage);
|
||||
love::graphics::SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage) override;
|
||||
|
||||
ParticleSystem *newParticleSystem(Texture *texture, int size);
|
||||
love::graphics::ParticleSystem *newParticleSystem(Texture *texture, int size) override;
|
||||
|
||||
love::graphics::Canvas *newCanvas(int width, int height, const Canvas::Settings &settings) override;
|
||||
|
||||
@@ -76,11 +76,11 @@ public:
|
||||
|
||||
love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override;
|
||||
|
||||
Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage);
|
||||
Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage);
|
||||
love::graphics::Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) override;
|
||||
love::graphics::Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) override;
|
||||
|
||||
Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage);
|
||||
Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage);
|
||||
love::graphics::Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) override;
|
||||
love::graphics::Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) override;
|
||||
|
||||
love::graphics::Text *newText(love::graphics::Font *font, const std::vector<Font::ColoredString> &text = {}) override;
|
||||
|
||||
@@ -94,8 +94,6 @@ public:
|
||||
|
||||
void flushStreamDraws() override;
|
||||
|
||||
void drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount);
|
||||
|
||||
void clear(Colorf color) override;
|
||||
void clear(const std::vector<OptionalColorf> &colors) override;
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
// LOVE
|
||||
#include "Mesh.h"
|
||||
#include "common/Matrix.h"
|
||||
#include "common/Exception.h"
|
||||
#include "Shader.h"
|
||||
#include "graphics/Graphics.h"
|
||||
@@ -36,87 +35,14 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
static const char *getBuiltinAttribName(VertexAttribID attribid)
|
||||
{
|
||||
const char *name = "";
|
||||
vertex::getConstant(attribid, name);
|
||||
return name;
|
||||
}
|
||||
|
||||
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, color.r) == sizeof(float) * 4, "Incorrect color offset in Vertex struct");
|
||||
|
||||
static std::vector<Mesh::AttribFormat> getDefaultVertexFormat()
|
||||
{
|
||||
// Corresponds to the love::Vertex struct.
|
||||
std::vector<Mesh::AttribFormat> vertexformat = {
|
||||
{getBuiltinAttribName(ATTRIB_POS), Mesh::DATA_FLOAT, 2},
|
||||
{getBuiltinAttribName(ATTRIB_TEXCOORD), Mesh::DATA_FLOAT, 2},
|
||||
{getBuiltinAttribName(ATTRIB_COLOR), Mesh::DATA_BYTE, 4},
|
||||
};
|
||||
|
||||
return vertexformat;
|
||||
}
|
||||
|
||||
love::Type Mesh::type("Mesh", &Drawable::type);
|
||||
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage)
|
||||
: vertexFormat(vertexformat)
|
||||
, vbo(nullptr)
|
||||
, vertexCount(0)
|
||||
, vertexStride(0)
|
||||
, ibo(nullptr)
|
||||
, useIndexBuffer(false)
|
||||
, elementCount(0)
|
||||
, elementDataType(INDEX_UINT16)
|
||||
, drawMode(drawmode)
|
||||
, rangeStart(-1)
|
||||
, rangeCount(-1)
|
||||
: love::graphics::Mesh(gfx, vertexformat, data, datasize, drawmode, usage)
|
||||
{
|
||||
setupAttachedAttributes();
|
||||
calculateAttributeSizes();
|
||||
|
||||
vertexCount = datasize / vertexStride;
|
||||
elementDataType = vertex::getIndexDataTypeFromMax(vertexCount);
|
||||
|
||||
if (vertexCount == 0)
|
||||
throw love::Exception("Data size is too small for specified vertex attribute formats.");
|
||||
|
||||
vbo = gfx->newBuffer(datasize, data, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY | Buffer::MAP_READ);
|
||||
|
||||
vertexScratchBuffer = new char[vertexStride];
|
||||
}
|
||||
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage)
|
||||
: vertexFormat(vertexformat)
|
||||
, vbo(nullptr)
|
||||
, vertexCount((size_t) vertexcount)
|
||||
, vertexStride(0)
|
||||
, ibo(nullptr)
|
||||
, useIndexBuffer(false)
|
||||
, elementCount(0)
|
||||
, elementDataType(vertex::getIndexDataTypeFromMax(vertexcount))
|
||||
, drawMode(drawmode)
|
||||
, rangeStart(-1)
|
||||
, rangeCount(-1)
|
||||
: love::graphics::Mesh(gfx, vertexformat, vertexcount, drawmode, usage)
|
||||
{
|
||||
if (vertexcount <= 0)
|
||||
throw love::Exception("Invalid number of vertices (%d).", vertexcount);
|
||||
|
||||
setupAttachedAttributes();
|
||||
calculateAttributeSizes();
|
||||
|
||||
size_t buffersize = vertexCount * vertexStride;
|
||||
|
||||
vbo = gfx->newBuffer(buffersize, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY | Buffer::MAP_READ);
|
||||
|
||||
// Initialize the buffer's contents to 0.
|
||||
memset(vbo->map(), 0, buffersize);
|
||||
vbo->setMappedRangeModified(0, vbo->getSize());
|
||||
vbo->unmap();
|
||||
|
||||
vertexScratchBuffer = new char[vertexStride];
|
||||
}
|
||||
|
||||
Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage)
|
||||
@@ -131,448 +57,6 @@ Mesh::Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::
|
||||
|
||||
Mesh::~Mesh()
|
||||
{
|
||||
delete vbo;
|
||||
delete ibo;
|
||||
delete vertexScratchBuffer;
|
||||
|
||||
for (const auto &attrib : attachedAttributes)
|
||||
{
|
||||
if (attrib.second.mesh != this)
|
||||
attrib.second.mesh->release();
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::setupAttachedAttributes()
|
||||
{
|
||||
for (size_t i = 0; i < vertexFormat.size(); i++)
|
||||
{
|
||||
const std::string &name = vertexFormat[i].name;
|
||||
|
||||
if (attachedAttributes.find(name) != attachedAttributes.end())
|
||||
throw love::Exception("Duplicate vertex attribute name: %s", name.c_str());
|
||||
|
||||
attachedAttributes[name] = {this, (int) i, STEP_PER_VERTEX, true};
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::calculateAttributeSizes()
|
||||
{
|
||||
size_t stride = 0;
|
||||
|
||||
for (const AttribFormat &format : vertexFormat)
|
||||
{
|
||||
// Hardware really doesn't like attributes that aren't 32 bit-aligned.
|
||||
if (format.type == DATA_BYTE && format.components != 4)
|
||||
throw love::Exception("byte vertex attributes must have 4 components.");
|
||||
|
||||
if (format.components <= 0 || format.components > 4)
|
||||
throw love::Exception("Vertex attributes must have between 1 and 4 components.");
|
||||
|
||||
// Total size in bytes of each attribute in a single vertex.
|
||||
attributeSizes.push_back(getAttribFormatSize(format));
|
||||
stride += attributeSizes.back();
|
||||
}
|
||||
|
||||
vertexStride = stride;
|
||||
}
|
||||
|
||||
size_t Mesh::getAttributeOffset(size_t attribindex) const
|
||||
{
|
||||
size_t offset = 0;
|
||||
|
||||
for (size_t i = 0; i < attribindex; i++)
|
||||
offset += attributeSizes[i];
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize)
|
||||
{
|
||||
if (vertindex >= vertexCount)
|
||||
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
|
||||
|
||||
size_t offset = vertindex * vertexStride;
|
||||
size_t size = std::min(datasize, vertexStride);
|
||||
|
||||
uint8 *bufferdata = (uint8 *) vbo->map();
|
||||
memcpy(bufferdata + offset, data, size);
|
||||
|
||||
vbo->setMappedRangeModified(offset, size);
|
||||
}
|
||||
|
||||
size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize)
|
||||
{
|
||||
if (vertindex >= vertexCount)
|
||||
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
|
||||
|
||||
size_t offset = vertindex * vertexStride;
|
||||
size_t size = std::min(datasize, vertexStride);
|
||||
|
||||
// We're relying on vbo->map() returning read/write data... ew.
|
||||
const uint8 *bufferdata = (const uint8 *) vbo->map();
|
||||
memcpy(data, bufferdata + offset, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void *Mesh::getVertexScratchBuffer()
|
||||
{
|
||||
return vertexScratchBuffer;
|
||||
}
|
||||
|
||||
void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *data, size_t datasize)
|
||||
{
|
||||
if (vertindex >= vertexCount)
|
||||
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
|
||||
|
||||
if (attribindex >= (int) vertexFormat.size())
|
||||
throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
|
||||
|
||||
size_t offset = vertindex * vertexStride + getAttributeOffset(attribindex);
|
||||
size_t size = std::min(datasize, attributeSizes[attribindex]);
|
||||
|
||||
uint8 *bufferdata = (uint8 *) vbo->map();
|
||||
memcpy(bufferdata + offset, data, size);
|
||||
|
||||
vbo->setMappedRangeModified(offset, size);
|
||||
}
|
||||
|
||||
size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, size_t datasize)
|
||||
{
|
||||
if (vertindex >= vertexCount)
|
||||
throw love::Exception("Invalid vertex index: %ld", vertindex + 1);
|
||||
|
||||
if (attribindex >= (int) vertexFormat.size())
|
||||
throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
|
||||
|
||||
size_t offset = vertindex * vertexStride + getAttributeOffset(attribindex);
|
||||
size_t size = std::min(datasize, attributeSizes[attribindex]);
|
||||
|
||||
// We're relying on vbo->map() returning read/write data... ew.
|
||||
const uint8 *bufferdata = (const uint8 *) vbo->map();
|
||||
memcpy(data, bufferdata + offset, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t Mesh::getVertexCount() const
|
||||
{
|
||||
return vertexCount;
|
||||
}
|
||||
|
||||
size_t Mesh::getVertexStride() const
|
||||
{
|
||||
return vertexStride;
|
||||
}
|
||||
|
||||
const std::vector<Mesh::AttribFormat> &Mesh::getVertexFormat() const
|
||||
{
|
||||
return vertexFormat;
|
||||
}
|
||||
|
||||
Mesh::DataType Mesh::getAttributeInfo(int attribindex, int &components) const
|
||||
{
|
||||
if (attribindex < 0 || attribindex >= (int) vertexFormat.size())
|
||||
throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
|
||||
|
||||
DataType type = vertexFormat[attribindex].type;
|
||||
components = vertexFormat[attribindex].components;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
int Mesh::getAttributeIndex(const std::string &name) const
|
||||
{
|
||||
for (int i = 0; i < (int) vertexFormat.size(); i++)
|
||||
{
|
||||
if (vertexFormat[i].name == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Mesh::setAttributeEnabled(const std::string &name, bool enable)
|
||||
{
|
||||
auto it = attachedAttributes.find(name);
|
||||
|
||||
if (it == attachedAttributes.end())
|
||||
throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
|
||||
|
||||
it->second.enabled = enable;
|
||||
}
|
||||
|
||||
bool Mesh::isAttributeEnabled(const std::string &name) const
|
||||
{
|
||||
const auto it = attachedAttributes.find(name);
|
||||
|
||||
if (it == attachedAttributes.end())
|
||||
throw love::Exception("Mesh does not have an attached vertex attribute named '%s'", name.c_str());
|
||||
|
||||
return it->second.enabled;
|
||||
}
|
||||
|
||||
void Mesh::attachAttribute(const std::string &name, Mesh *mesh, const std::string &attachname, AttributeStep step)
|
||||
{
|
||||
if (step == STEP_PER_INSTANCE && !gl.isInstancingSupported())
|
||||
throw love::Exception("Vertex attribute instancing is not supported on this system.");
|
||||
|
||||
if (mesh != this)
|
||||
{
|
||||
for (const auto &it : mesh->attachedAttributes)
|
||||
{
|
||||
// If the supplied Mesh has attached attributes of its own, then we
|
||||
// prevent it from being attached to avoid reference cycles.
|
||||
if (it.second.mesh != mesh)
|
||||
throw love::Exception("Cannot attach a Mesh which has attached Meshes of its own.");
|
||||
}
|
||||
}
|
||||
|
||||
AttachedAttribute oldattrib = {};
|
||||
AttachedAttribute newattrib = {};
|
||||
|
||||
auto it = attachedAttributes.find(name);
|
||||
if (it != attachedAttributes.end())
|
||||
oldattrib = it->second;
|
||||
|
||||
newattrib.mesh = mesh;
|
||||
newattrib.enabled = oldattrib.mesh ? oldattrib.enabled : true;
|
||||
newattrib.index = mesh->getAttributeIndex(attachname);
|
||||
newattrib.step = step;
|
||||
|
||||
if (newattrib.index < 0)
|
||||
throw love::Exception("The specified mesh does not have a vertex attribute named '%s'", attachname.c_str());
|
||||
|
||||
if (newattrib.mesh != this)
|
||||
newattrib.mesh->retain();
|
||||
|
||||
attachedAttributes[name] = newattrib;
|
||||
|
||||
if (oldattrib.mesh && oldattrib.mesh != this)
|
||||
oldattrib.mesh->release();
|
||||
}
|
||||
|
||||
bool Mesh::detachAttribute(const std::string &name)
|
||||
{
|
||||
auto it = attachedAttributes.find(name);
|
||||
|
||||
if (it != attachedAttributes.end() && it->second.mesh != this)
|
||||
{
|
||||
it->second.mesh->release();
|
||||
attachedAttributes.erase(it);
|
||||
|
||||
if (getAttributeIndex(name) != -1)
|
||||
attachAttribute(name, this, name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void *Mesh::mapVertexData()
|
||||
{
|
||||
return vbo->map();
|
||||
}
|
||||
|
||||
void Mesh::unmapVertexData(size_t modifiedoffset, size_t modifiedsize)
|
||||
{
|
||||
vbo->setMappedRangeModified(modifiedoffset, modifiedsize);
|
||||
vbo->unmap();
|
||||
}
|
||||
|
||||
void Mesh::flush()
|
||||
{
|
||||
vbo->unmap();
|
||||
|
||||
if (ibo != nullptr)
|
||||
ibo->unmap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies index data from a vector to a mapped index buffer.
|
||||
**/
|
||||
template <typename T>
|
||||
static void copyToIndexBuffer(const std::vector<uint32> &indices, Buffer::Mapper &buffermap, size_t maxval)
|
||||
{
|
||||
T *elems = (T *) buffermap.get();
|
||||
|
||||
for (size_t i = 0; i < indices.size(); i++)
|
||||
{
|
||||
if (indices[i] >= maxval)
|
||||
throw love::Exception("Invalid vertex map value: %d", indices[i] + 1);
|
||||
|
||||
elems[i] = (T) indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::setVertexMap(const std::vector<uint32> &map)
|
||||
{
|
||||
size_t maxval = getVertexCount();
|
||||
|
||||
IndexDataType datatype = vertex::getIndexDataTypeFromMax(maxval);
|
||||
|
||||
// Calculate the size in bytes of the index buffer data.
|
||||
size_t size = map.size() * vertex::getIndexDataSize(datatype);
|
||||
|
||||
if (ibo && size > ibo->getSize())
|
||||
{
|
||||
delete ibo;
|
||||
ibo = nullptr;
|
||||
}
|
||||
|
||||
if (!ibo && size > 0)
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
ibo = gfx->newBuffer(size, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ);
|
||||
}
|
||||
|
||||
useIndexBuffer = true;
|
||||
elementCount = map.size();
|
||||
|
||||
if (!ibo || elementCount == 0)
|
||||
return;
|
||||
|
||||
Buffer::Mapper ibomap(*ibo);
|
||||
|
||||
// Fill the buffer with the index values from the vector.
|
||||
switch (datatype)
|
||||
{
|
||||
case INDEX_UINT16:
|
||||
copyToIndexBuffer<uint16>(map, ibomap, maxval);
|
||||
break;
|
||||
case INDEX_UINT32:
|
||||
default:
|
||||
copyToIndexBuffer<uint32>(map, ibomap, maxval);
|
||||
break;
|
||||
}
|
||||
|
||||
elementDataType = datatype;
|
||||
}
|
||||
|
||||
void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize)
|
||||
{
|
||||
if (ibo && datasize > ibo->getSize())
|
||||
{
|
||||
delete ibo;
|
||||
ibo = nullptr;
|
||||
}
|
||||
|
||||
if (!ibo && datasize > 0)
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
ibo = gfx->newBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ);
|
||||
}
|
||||
|
||||
elementCount = datasize / vertex::getIndexDataSize(datatype);
|
||||
|
||||
if (!ibo || elementCount == 0)
|
||||
return;
|
||||
|
||||
Buffer::Mapper ibomap(*ibo);
|
||||
memcpy(ibomap.get(), data, datasize);
|
||||
|
||||
useIndexBuffer = true;
|
||||
elementDataType = datatype;
|
||||
}
|
||||
|
||||
void Mesh::setVertexMap()
|
||||
{
|
||||
useIndexBuffer = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies index data from a mapped buffer to a vector.
|
||||
**/
|
||||
template <typename T>
|
||||
static void copyFromIndexBuffer(void *buffer, size_t count, std::vector<uint32> &indices)
|
||||
{
|
||||
T *elems = (T *) buffer;
|
||||
for (size_t i = 0; i < count; i++)
|
||||
indices.push_back((uint32) elems[i]);
|
||||
}
|
||||
|
||||
bool Mesh::getVertexMap(std::vector<uint32> &map) const
|
||||
{
|
||||
if (!useIndexBuffer)
|
||||
return false;
|
||||
|
||||
map.clear();
|
||||
map.reserve(elementCount);
|
||||
|
||||
if (!ibo || elementCount == 0)
|
||||
return true;
|
||||
|
||||
// We unmap the buffer in Mesh::draw, Mesh::setVertexMap, and Mesh::flush.
|
||||
void *buffer = ibo->map();
|
||||
|
||||
// Fill the vector from the buffer.
|
||||
switch (elementDataType)
|
||||
{
|
||||
case INDEX_UINT16:
|
||||
copyFromIndexBuffer<uint16>(buffer, elementCount, map);
|
||||
break;
|
||||
case INDEX_UINT32:
|
||||
default:
|
||||
copyFromIndexBuffer<uint32>(buffer, elementCount, map);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Mesh::getVertexMapCount() const
|
||||
{
|
||||
return elementCount;
|
||||
}
|
||||
|
||||
void Mesh::setTexture(Texture *tex)
|
||||
{
|
||||
texture.set(tex);
|
||||
}
|
||||
|
||||
void Mesh::setTexture()
|
||||
{
|
||||
texture.set(nullptr);
|
||||
}
|
||||
|
||||
Texture *Mesh::getTexture() const
|
||||
{
|
||||
return texture.get();
|
||||
}
|
||||
|
||||
void Mesh::setDrawMode(DrawMode mode)
|
||||
{
|
||||
drawMode = mode;
|
||||
}
|
||||
|
||||
Mesh::DrawMode Mesh::getDrawMode() const
|
||||
{
|
||||
return drawMode;
|
||||
}
|
||||
|
||||
void Mesh::setDrawRange(int start, int count)
|
||||
{
|
||||
if (start < 0 || count <= 0)
|
||||
throw love::Exception("Invalid draw range.");
|
||||
|
||||
rangeStart = start;
|
||||
rangeCount = count;
|
||||
}
|
||||
|
||||
void Mesh::setDrawRange()
|
||||
{
|
||||
rangeStart = rangeCount = -1;
|
||||
}
|
||||
|
||||
bool Mesh::getDrawRange(int &start, int &count) const
|
||||
{
|
||||
if (rangeStart < 0 || rangeCount <= 0)
|
||||
return false;
|
||||
|
||||
start = rangeStart;
|
||||
count = rangeCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inputname)
|
||||
@@ -627,7 +111,7 @@ void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m,
|
||||
if (!attrib.second.enabled)
|
||||
continue;
|
||||
|
||||
Mesh *mesh = attrib.second.mesh;
|
||||
love::graphics::Mesh *mesh = attrib.second.mesh;
|
||||
int location = mesh->bindAttributeToShaderInput(attrib.second.index, attrib.first);
|
||||
|
||||
if (location >= 0)
|
||||
@@ -692,24 +176,6 @@ void Mesh::drawInstanced(love::graphics::Graphics *gfx, const love::Matrix4 &m,
|
||||
}
|
||||
}
|
||||
|
||||
void Mesh::draw(love::graphics::Graphics *gfx, const love::Matrix4 &m)
|
||||
{
|
||||
drawInstanced(gfx, m, 1);
|
||||
}
|
||||
|
||||
size_t Mesh::getAttribFormatSize(const AttribFormat &format)
|
||||
{
|
||||
switch (format.type)
|
||||
{
|
||||
case DATA_BYTE:
|
||||
return format.components * sizeof(uint8);
|
||||
case DATA_FLOAT:
|
||||
return format.components * sizeof(float);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
GLenum Mesh::getGLDrawMode(DrawMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
@@ -739,62 +205,6 @@ GLenum Mesh::getGLDataType(DataType type)
|
||||
}
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(const char *in, Mesh::DrawMode &out)
|
||||
{
|
||||
return drawModes.find(in, out);
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(Mesh::DrawMode in, const char *&out)
|
||||
{
|
||||
return drawModes.find(in, out);
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(const char *in, DataType &out)
|
||||
{
|
||||
return dataTypes.find(in, out);
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(DataType in, const char *&out)
|
||||
{
|
||||
return dataTypes.find(in, out);
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(const char *in, AttributeStep &out)
|
||||
{
|
||||
return attributeSteps.find(in, out);
|
||||
}
|
||||
|
||||
bool Mesh::getConstant(AttributeStep in, const char *&out)
|
||||
{
|
||||
return attributeSteps.find(in, out);
|
||||
}
|
||||
|
||||
StringMap<Mesh::DrawMode, Mesh::DRAWMODE_MAX_ENUM>::Entry Mesh::drawModeEntries[] =
|
||||
{
|
||||
{ "fan", DRAWMODE_FAN },
|
||||
{ "strip", DRAWMODE_STRIP },
|
||||
{ "triangles", DRAWMODE_TRIANGLES },
|
||||
{ "points", DRAWMODE_POINTS },
|
||||
};
|
||||
|
||||
StringMap<Mesh::DrawMode, Mesh::DRAWMODE_MAX_ENUM> Mesh::drawModes(Mesh::drawModeEntries, sizeof(Mesh::drawModeEntries));
|
||||
|
||||
StringMap<Mesh::DataType, Mesh::DATA_MAX_ENUM>::Entry Mesh::dataTypeEntries[] =
|
||||
{
|
||||
{ "byte", DATA_BYTE },
|
||||
{ "float", DATA_FLOAT },
|
||||
};
|
||||
|
||||
StringMap<Mesh::DataType, Mesh::DATA_MAX_ENUM> Mesh::dataTypes(Mesh::dataTypeEntries, sizeof(Mesh::dataTypeEntries));
|
||||
|
||||
StringMap<Mesh::AttributeStep, Mesh::STEP_MAX_ENUM>::Entry Mesh::attributeStepEntries[] =
|
||||
{
|
||||
{ "pervertex", STEP_PER_VERTEX },
|
||||
{ "perinstance", STEP_PER_INSTANCE },
|
||||
};
|
||||
|
||||
StringMap<Mesh::AttributeStep, Mesh::STEP_MAX_ENUM> Mesh::attributeSteps(Mesh::attributeStepEntries, sizeof(Mesh::attributeStepEntries));
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -18,78 +18,23 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_MESH_H
|
||||
#define LOVE_GRAPHICS_OPENGL_MESH_H
|
||||
#pragma once
|
||||
|
||||
// LOVE
|
||||
#include "common/config.h"
|
||||
#include "common/int.h"
|
||||
#include "common/math.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "graphics/Drawable.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/vertex.h"
|
||||
#include "graphics/Buffer.h"
|
||||
#include "graphics/Mesh.h"
|
||||
#include "OpenGL.h"
|
||||
|
||||
// C++
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
class Graphics;
|
||||
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
/**
|
||||
* Holds and draws arbitrary vertex geometry.
|
||||
* Each vertex in the Mesh has a collection of vertex attributes specified on
|
||||
* creation.
|
||||
**/
|
||||
class Mesh : public Drawable
|
||||
class Mesh : public love::graphics::Mesh
|
||||
{
|
||||
public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
// How the Mesh's vertices are used when drawing.
|
||||
// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
|
||||
enum DrawMode
|
||||
{
|
||||
DRAWMODE_FAN,
|
||||
DRAWMODE_STRIP,
|
||||
DRAWMODE_TRIANGLES,
|
||||
DRAWMODE_POINTS,
|
||||
DRAWMODE_MAX_ENUM
|
||||
};
|
||||
|
||||
// The type of data a vertex attribute can store.
|
||||
enum DataType
|
||||
{
|
||||
DATA_BYTE,
|
||||
DATA_FLOAT,
|
||||
DATA_MAX_ENUM
|
||||
};
|
||||
|
||||
enum AttributeStep
|
||||
{
|
||||
STEP_PER_VERTEX,
|
||||
STEP_PER_INSTANCE,
|
||||
STEP_MAX_ENUM
|
||||
};
|
||||
|
||||
struct AttribFormat
|
||||
{
|
||||
std::string name;
|
||||
DataType type;
|
||||
int components; // max 4
|
||||
};
|
||||
|
||||
Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage);
|
||||
Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage);
|
||||
|
||||
@@ -98,184 +43,16 @@ public:
|
||||
|
||||
virtual ~Mesh();
|
||||
|
||||
/**
|
||||
* Sets the values of all attributes at a specific vertex index in the Mesh.
|
||||
* The size of the data must be less than or equal to the total size of all
|
||||
* vertex attributes.
|
||||
**/
|
||||
void setVertex(size_t vertindex, const void *data, size_t datasize);
|
||||
size_t getVertex(size_t vertindex, void *data, size_t datasize);
|
||||
void *getVertexScratchBuffer();
|
||||
|
||||
/**
|
||||
* Sets the values for a single attribute at a specific vertex index in the
|
||||
* Mesh. The size of the data must be less than or equal to the size of the
|
||||
* attribute.
|
||||
**/
|
||||
void setVertexAttribute(size_t vertindex, int attribindex, const void *data, size_t datasize);
|
||||
size_t getVertexAttribute(size_t vertindex, int attribindex, void *data, size_t datasize);
|
||||
|
||||
/**
|
||||
* Gets the total number of vertices that can be used when drawing the Mesh.
|
||||
**/
|
||||
size_t getVertexCount() const;
|
||||
|
||||
/**
|
||||
* Gets the size in bytes of the start of one vertex to the start of the
|
||||
* next, in the buffer.
|
||||
**/
|
||||
size_t getVertexStride() const;
|
||||
|
||||
/**
|
||||
* Gets the format of each vertex attribute stored in the Mesh.
|
||||
**/
|
||||
const std::vector<AttribFormat> &getVertexFormat() const;
|
||||
DataType getAttributeInfo(int attribindex, int &components) const;
|
||||
int getAttributeIndex(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* Sets whether a specific vertex attribute is used when drawing the Mesh.
|
||||
**/
|
||||
void setAttributeEnabled(const std::string &name, bool enable);
|
||||
bool isAttributeEnabled(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* Attaches a vertex attribute from another Mesh to this one. The attribute
|
||||
* will be used when drawing this Mesh.
|
||||
**/
|
||||
void attachAttribute(const std::string &name, Mesh *mesh, const std::string &attachname, AttributeStep step = STEP_PER_VERTEX);
|
||||
bool detachAttribute(const std::string &name);
|
||||
|
||||
void *mapVertexData();
|
||||
void unmapVertexData(size_t modifiedoffset = 0, size_t modifiedsize = -1);
|
||||
|
||||
/**
|
||||
* Flushes all modified data to the GPU.
|
||||
**/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* Sets the vertex map to use when drawing the Mesh. The vertex map
|
||||
* determines the order in which vertices are used by the draw mode.
|
||||
* A 0-element vector is equivalent to the default vertex map:
|
||||
* {0, 1, 2, 3, 4, ...}
|
||||
**/
|
||||
void setVertexMap(const std::vector<uint32> &map);
|
||||
void setVertexMap(IndexDataType datatype, const void *data, size_t datasize);
|
||||
void setVertexMap();
|
||||
|
||||
/**
|
||||
* Fills the uint32 vector passed into the method with the previously set
|
||||
* vertex map (index buffer) values.
|
||||
**/
|
||||
bool getVertexMap(std::vector<uint32> &map) const;
|
||||
|
||||
/**
|
||||
* Gets the total number of elements in the vertex map array.
|
||||
**/
|
||||
size_t getVertexMapCount() const;
|
||||
|
||||
/**
|
||||
* Sets the texture used when drawing the Mesh.
|
||||
**/
|
||||
void setTexture(Texture *texture);
|
||||
|
||||
/**
|
||||
* Disables any texture from being used when drawing the Mesh.
|
||||
**/
|
||||
void setTexture();
|
||||
|
||||
/**
|
||||
* Gets the texture used when drawing the Mesh. May return null if no
|
||||
* texture is set.
|
||||
**/
|
||||
Texture *getTexture() const;
|
||||
|
||||
/**
|
||||
* Sets the draw mode used when drawing the Mesh.
|
||||
**/
|
||||
void setDrawMode(DrawMode mode);
|
||||
DrawMode getDrawMode() const;
|
||||
|
||||
void setDrawRange(int start, int count);
|
||||
void setDrawRange();
|
||||
bool getDrawRange(int &start, int &count) const;
|
||||
|
||||
int bindAttributeToShaderInput(int attributeindex, const std::string &inputname);
|
||||
|
||||
void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount);
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(Graphics *gfx, const Matrix4 &m) override;
|
||||
|
||||
static bool getConstant(const char *in, DrawMode &out);
|
||||
static bool getConstant(DrawMode in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, DataType &out);
|
||||
static bool getConstant(DataType in, const char *&out);
|
||||
|
||||
static bool getConstant(const char *in, AttributeStep &out);
|
||||
static bool getConstant(AttributeStep in, const char *&out);
|
||||
int bindAttributeToShaderInput(int attributeindex, const std::string &inputname) override;
|
||||
void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount) override;
|
||||
|
||||
private:
|
||||
|
||||
struct AttachedAttribute
|
||||
{
|
||||
Mesh *mesh;
|
||||
int index;
|
||||
AttributeStep step;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
void setupAttachedAttributes();
|
||||
void calculateAttributeSizes();
|
||||
size_t getAttributeOffset(size_t attribindex) const;
|
||||
|
||||
static size_t getAttribFormatSize(const AttribFormat &format);
|
||||
|
||||
static GLenum getGLDrawMode(DrawMode mode);
|
||||
static GLenum getGLDataType(DataType type);
|
||||
|
||||
std::vector<AttribFormat> vertexFormat;
|
||||
std::vector<size_t> attributeSizes;
|
||||
|
||||
std::unordered_map<std::string, AttachedAttribute> attachedAttributes;
|
||||
|
||||
// Vertex buffer, for the vertex data.
|
||||
Buffer *vbo;
|
||||
size_t vertexCount;
|
||||
size_t vertexStride;
|
||||
|
||||
// Block of memory whose size is at least as large as a single vertex. Helps
|
||||
// avoid memory allocations when using Mesh::setVertex etc.
|
||||
char *vertexScratchBuffer;
|
||||
|
||||
// Element (vertex index) buffer, for the vertex map.
|
||||
Buffer *ibo;
|
||||
bool useIndexBuffer;
|
||||
size_t elementCount;
|
||||
IndexDataType elementDataType;
|
||||
|
||||
DrawMode drawMode;
|
||||
|
||||
int rangeStart;
|
||||
int rangeCount;
|
||||
|
||||
StrongRef<Texture> texture;
|
||||
|
||||
static StringMap<DrawMode, DRAWMODE_MAX_ENUM>::Entry drawModeEntries[];
|
||||
static StringMap<DrawMode, DRAWMODE_MAX_ENUM> drawModes;
|
||||
|
||||
static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[];
|
||||
static StringMap<DataType, DATA_MAX_ENUM> dataTypes;
|
||||
|
||||
static StringMap<AttributeStep, STEP_MAX_ENUM>::Entry attributeStepEntries[];
|
||||
static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps;
|
||||
|
||||
}; // Mesh
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_OPENGL_MESH_H
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "OpenGL.h"
|
||||
|
||||
// LOVE
|
||||
#include "graphics/Buffer.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/Graphics.h"
|
||||
|
||||
@@ -41,199 +42,13 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
love::Type SpriteBatch::type("SpriteBatch", &Drawable::type);
|
||||
|
||||
SpriteBatch::SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usage usage)
|
||||
: texture(texture)
|
||||
, size(size)
|
||||
, next(0)
|
||||
, color(0)
|
||||
, array_buf(nullptr)
|
||||
, quad_indices(gfx, size)
|
||||
, range_start(-1)
|
||||
, range_count(-1)
|
||||
: love::graphics::SpriteBatch(gfx, texture, size, usage)
|
||||
{
|
||||
if (size <= 0)
|
||||
throw love::Exception("Invalid SpriteBatch size.");
|
||||
|
||||
size_t vertex_size = sizeof(Vertex) * 4 * size;
|
||||
|
||||
array_buf = gfx->newBuffer(vertex_size, nullptr, BUFFER_VERTEX, usage, Buffer::MAP_EXPLICIT_RANGE_MODIFY);
|
||||
}
|
||||
|
||||
SpriteBatch::~SpriteBatch()
|
||||
{
|
||||
delete color;
|
||||
delete array_buf;
|
||||
}
|
||||
|
||||
int SpriteBatch::add(const Matrix4 &m, int index /*= -1*/)
|
||||
{
|
||||
if (index < -1 || index >= size)
|
||||
throw love::Exception("Invalid sprite index: %d", index + 1);
|
||||
|
||||
if (index == -1 && next >= size)
|
||||
setBufferSize(size * 2);
|
||||
|
||||
addv(texture->getVertices(), m, (index == -1) ? next : index);
|
||||
|
||||
// Increment counter.
|
||||
if (index == -1)
|
||||
return next++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int SpriteBatch::addq(Quad *quad, const Matrix4 &m, int index /*= -1*/)
|
||||
{
|
||||
if (index < -1 || index >= size)
|
||||
throw love::Exception("Invalid sprite index: %d", index + 1);
|
||||
|
||||
if (index == -1 && next >= size)
|
||||
setBufferSize(size * 2);
|
||||
|
||||
addv(quad->getVertices(), m, (index == -1) ? next : index);
|
||||
|
||||
// Increment counter.
|
||||
if (index == -1)
|
||||
return next++;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void SpriteBatch::clear()
|
||||
{
|
||||
// Reset the position of the next index.
|
||||
next = 0;
|
||||
}
|
||||
|
||||
void SpriteBatch::flush()
|
||||
{
|
||||
array_buf->unmap();
|
||||
}
|
||||
|
||||
void SpriteBatch::setTexture(Texture *newtexture)
|
||||
{
|
||||
texture.set(newtexture);
|
||||
}
|
||||
|
||||
Texture *SpriteBatch::getTexture() const
|
||||
{
|
||||
return texture.get();
|
||||
}
|
||||
|
||||
void SpriteBatch::setColor(const Color &color)
|
||||
{
|
||||
if (!this->color)
|
||||
this->color = new Color(color);
|
||||
else
|
||||
*(this->color) = color;
|
||||
}
|
||||
|
||||
void SpriteBatch::setColor()
|
||||
{
|
||||
delete color;
|
||||
color = nullptr;
|
||||
}
|
||||
|
||||
const Color *SpriteBatch::getColor() const
|
||||
{
|
||||
return color;
|
||||
}
|
||||
|
||||
int SpriteBatch::getCount() const
|
||||
{
|
||||
return next;
|
||||
}
|
||||
|
||||
void SpriteBatch::setBufferSize(int newsize)
|
||||
{
|
||||
if (newsize <= 0)
|
||||
throw love::Exception("Invalid SpriteBatch size.");
|
||||
|
||||
if (newsize == size)
|
||||
return;
|
||||
|
||||
size_t vertex_size = sizeof(Vertex) * 4 * newsize;
|
||||
love::graphics::Buffer *new_array_buf = nullptr;
|
||||
|
||||
int new_next = std::min(next, newsize);
|
||||
|
||||
try
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
new_array_buf = gfx->newBuffer(vertex_size, nullptr, array_buf->getType(), array_buf->getUsage(), array_buf->getMapFlags());
|
||||
|
||||
// Copy as much of the old data into the new GLBuffer as can fit.
|
||||
size_t copy_size = sizeof(Vertex) * 4 * new_next;
|
||||
array_buf->copyTo(0, copy_size, new_array_buf, 0);
|
||||
|
||||
quad_indices = QuadIndices(gfx, newsize);
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
delete new_array_buf;
|
||||
throw;
|
||||
}
|
||||
|
||||
// We don't need to unmap the old GLBuffer since we're deleting it.
|
||||
delete array_buf;
|
||||
|
||||
array_buf = new_array_buf;
|
||||
size = newsize;
|
||||
|
||||
next = new_next;
|
||||
}
|
||||
|
||||
int SpriteBatch::getBufferSize() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
void SpriteBatch::attachAttribute(const std::string &name, Mesh *mesh)
|
||||
{
|
||||
AttachedAttribute oldattrib = {};
|
||||
AttachedAttribute newattrib = {};
|
||||
|
||||
if (mesh->getVertexCount() < (size_t) next * 4)
|
||||
throw love::Exception("Mesh has too few vertices to be attached to this SpriteBatch (at least %d vertices are required)", next*4);
|
||||
|
||||
auto it = attached_attributes.find(name);
|
||||
if (it != attached_attributes.end())
|
||||
oldattrib = it->second;
|
||||
|
||||
newattrib.index = mesh->getAttributeIndex(name);
|
||||
|
||||
if (newattrib.index < 0)
|
||||
throw love::Exception("The specified mesh does not have a vertex attribute named '%s'", name.c_str());
|
||||
|
||||
newattrib.mesh = mesh;
|
||||
|
||||
attached_attributes[name] = newattrib;
|
||||
}
|
||||
|
||||
void SpriteBatch::setDrawRange(int start, int count)
|
||||
{
|
||||
if (start < 0 || count <= 0)
|
||||
throw love::Exception("Invalid draw range.");
|
||||
|
||||
range_start = start;
|
||||
range_count = count;
|
||||
}
|
||||
|
||||
void SpriteBatch::setDrawRange()
|
||||
{
|
||||
range_start = range_count = -1;
|
||||
}
|
||||
|
||||
bool SpriteBatch::getDrawRange(int &start, int &count) const
|
||||
{
|
||||
if (range_start < 0 || range_count <= 0)
|
||||
return false;
|
||||
|
||||
start = range_start;
|
||||
count = range_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
@@ -308,27 +123,6 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index)
|
||||
{
|
||||
// Needed for colors.
|
||||
Vertex sprite[4] = {v[0], v[1], v[2], v[3]};
|
||||
const size_t sprite_size = 4 * sizeof(Vertex); // bytecount
|
||||
|
||||
m.transform(sprite, sprite, 4);
|
||||
|
||||
if (color != nullptr)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
sprite[i].color = *color;
|
||||
}
|
||||
|
||||
// Always keep the VBO mapped when adding data for now (it'll be unmapped
|
||||
// on draw.)
|
||||
array_buf->map();
|
||||
|
||||
array_buf->fill(index * sprite_size, sprite_size, sprite);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -18,139 +18,30 @@
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_SPRITE_BATCH_H
|
||||
#define LOVE_GRAPHICS_OPENGL_SPRITE_BATCH_H
|
||||
|
||||
// C
|
||||
#include <cstring>
|
||||
|
||||
// C++
|
||||
#include <unordered_map>
|
||||
#pragma once
|
||||
|
||||
// LOVE
|
||||
#include "common/math.h"
|
||||
#include "common/Matrix.h"
|
||||
#include "graphics/Drawable.h"
|
||||
#include "graphics/Volatile.h"
|
||||
#include "graphics/Color.h"
|
||||
#include "graphics/Quad.h"
|
||||
#include "graphics/Buffer.h"
|
||||
#include "Mesh.h"
|
||||
#include "graphics/SpriteBatch.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
// Forward declarations.
|
||||
class Texture;
|
||||
class Graphics;
|
||||
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
class SpriteBatch : public Drawable
|
||||
class SpriteBatch : public love::graphics::SpriteBatch
|
||||
{
|
||||
public:
|
||||
|
||||
static love::Type type;
|
||||
|
||||
SpriteBatch(Graphics *gfx, Texture *texture, int size, vertex::Usage usage);
|
||||
virtual ~SpriteBatch();
|
||||
|
||||
int add(const Matrix4 &m, int index = -1);
|
||||
int addq(Quad *quad, const Matrix4 &m, int index = -1);
|
||||
void clear();
|
||||
|
||||
void flush();
|
||||
|
||||
void setTexture(Texture *newtexture);
|
||||
Texture *getTexture() const;
|
||||
|
||||
/**
|
||||
* Set the current color for this SpriteBatch. The sprites added
|
||||
* after this call will use this color. Note that global color
|
||||
* will not longer apply to the SpriteBatch if this is used.
|
||||
*
|
||||
* @param color The color to use for the following sprites.
|
||||
*/
|
||||
void setColor(const Color &color);
|
||||
|
||||
/**
|
||||
* Disable per-sprite colors for this SpriteBatch. The next call to
|
||||
* draw will use the global color for all sprites.
|
||||
*/
|
||||
void setColor();
|
||||
|
||||
/**
|
||||
* Get the current color for this SpriteBatch. Returns NULL if no color is
|
||||
* set.
|
||||
**/
|
||||
const Color *getColor() const;
|
||||
|
||||
/**
|
||||
* Get the number of sprites currently in this SpriteBatch.
|
||||
**/
|
||||
int getCount() const;
|
||||
|
||||
/**
|
||||
* Get the total number of sprites this SpriteBatch can currently hold.
|
||||
**/
|
||||
int getBufferSize() const;
|
||||
|
||||
/**
|
||||
* Attaches a specific vertex attribute from a Mesh to this SpriteBatch.
|
||||
* The vertex attribute will be used when drawing the SpriteBatch.
|
||||
**/
|
||||
void attachAttribute(const std::string &name, Mesh *mesh);
|
||||
|
||||
void setDrawRange(int start, int count);
|
||||
void setDrawRange();
|
||||
bool getDrawRange(int &start, int &count) const;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(Graphics *gfx, const Matrix4 &m) override;
|
||||
|
||||
private:
|
||||
|
||||
struct AttachedAttribute
|
||||
{
|
||||
StrongRef<Mesh> mesh;
|
||||
int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the total number of sprites this SpriteBatch can hold.
|
||||
* Leaves existing sprite data intact when possible.
|
||||
**/
|
||||
void setBufferSize(int newsize);
|
||||
|
||||
void addv(const Vertex *v, const Matrix4 &m, int index);
|
||||
|
||||
StrongRef<Texture> texture;
|
||||
|
||||
// Max number of sprites in the batch.
|
||||
int size;
|
||||
|
||||
// The next free element.
|
||||
int next;
|
||||
|
||||
// Current color. This color, if present, will be applied to the next
|
||||
// added sprite.
|
||||
Color *color;
|
||||
|
||||
love::graphics::Buffer *array_buf;
|
||||
QuadIndices quad_indices;
|
||||
|
||||
std::unordered_map<std::string, AttachedAttribute> attached_attributes;
|
||||
|
||||
int range_start;
|
||||
int range_count;
|
||||
|
||||
}; // SpriteBatch
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_OPENGL_SPRITE_BATCH_H
|
||||
|
||||
@@ -651,7 +651,7 @@ int w_newSpriteBatch(lua_State *L)
|
||||
return luaL_error(L, "Invalid usage hint: %s", usagestr);
|
||||
}
|
||||
|
||||
SpriteBatch *t = nullptr;
|
||||
love::graphics::SpriteBatch *t = nullptr;
|
||||
luax_catchexcept(L,
|
||||
[&](){ t = instance()->newSpriteBatch(texture, size, usage); }
|
||||
);
|
||||
@@ -667,7 +667,7 @@ int w_newParticleSystem(lua_State *L)
|
||||
|
||||
Texture *texture = luax_checktexture(L, 1);
|
||||
lua_Number size = luaL_optnumber(L, 2, 1000);
|
||||
ParticleSystem *t = 0;
|
||||
love::graphics::ParticleSystem *t = nullptr;
|
||||
if (size < 1.0 || size > ParticleSystem::MAX_PARTICLES)
|
||||
return luaL_error(L, "Invalid ParticleSystem size");
|
||||
|
||||
@@ -882,9 +882,9 @@ static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode
|
||||
return def;
|
||||
}
|
||||
|
||||
static Mesh *newStandardMesh(lua_State *L)
|
||||
static love::graphics::Mesh *newStandardMesh(lua_State *L)
|
||||
{
|
||||
Mesh *t = nullptr;
|
||||
love::graphics::Mesh *t = nullptr;
|
||||
|
||||
Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 2, Mesh::DRAWMODE_FAN);
|
||||
vertex::Usage usage = luax_optmeshusage(L, 3, vertex::USAGE_DYNAMIC);
|
||||
@@ -938,9 +938,9 @@ static Mesh *newStandardMesh(lua_State *L)
|
||||
return t;
|
||||
}
|
||||
|
||||
static Mesh *newCustomMesh(lua_State *L)
|
||||
static love::graphics::Mesh *newCustomMesh(lua_State *L)
|
||||
{
|
||||
Mesh *t = nullptr;
|
||||
love::graphics::Mesh *t = nullptr;
|
||||
|
||||
// First argument is the vertex format, second is a table of vertices or
|
||||
// the number of vertices.
|
||||
@@ -1067,7 +1067,7 @@ int w_newMesh(lua_State *L)
|
||||
if (arg1type != LUA_TTABLE && arg1type != LUA_TNUMBER)
|
||||
luaL_argerror(L, 1, "table or number expected");
|
||||
|
||||
Mesh *t = nullptr;
|
||||
love::graphics::Mesh *t = nullptr;
|
||||
|
||||
int arg2type = lua_type(L, 2);
|
||||
if (arg1type == LUA_TTABLE && (arg2type == LUA_TTABLE || arg2type == LUA_TNUMBER || arg2type == LUA_TUSERDATA))
|
||||
@@ -1671,7 +1671,7 @@ int w_draw(lua_State *L)
|
||||
|
||||
int w_drawInstanced(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
love::graphics::Mesh *t = luax_checkmesh(L, 1);
|
||||
int instancecount = (int) luaL_checkinteger(L, 2);
|
||||
|
||||
if (luax_istype(L, 3, math::Transform::type))
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
#include "graphics/wrap_Font.h"
|
||||
#include "graphics/wrap_Image.h"
|
||||
#include "graphics/wrap_Quad.h"
|
||||
#include "wrap_SpriteBatch.h"
|
||||
#include "wrap_ParticleSystem.h"
|
||||
#include "graphics/wrap_SpriteBatch.h"
|
||||
#include "graphics/wrap_ParticleSystem.h"
|
||||
#include "graphics/wrap_Canvas.h"
|
||||
#include "graphics/wrap_Shader.h"
|
||||
#include "wrap_Mesh.h"
|
||||
#include "graphics/wrap_Mesh.h"
|
||||
#include "graphics/wrap_Text.h"
|
||||
#include "graphics/wrap_Video.h"
|
||||
#include "Graphics.h"
|
||||
|
||||
@@ -1,575 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
// LOVE
|
||||
#include "wrap_Mesh.h"
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
|
||||
// C++
|
||||
#include <typeinfo>
|
||||
#include <algorithm>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
Mesh *luax_checkmesh(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<Mesh>(L, idx);
|
||||
}
|
||||
|
||||
static inline size_t writeByteData(lua_State *L, int startidx, int components, char *data)
|
||||
{
|
||||
uint8 *componentdata = (uint8 *) data;
|
||||
|
||||
for (int i = 0; i < components; i++)
|
||||
componentdata[i] = (uint8) (luaL_optnumber(L, startidx + i, 1.0) * 255.0);
|
||||
|
||||
return sizeof(uint8) * components;
|
||||
}
|
||||
|
||||
static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data)
|
||||
{
|
||||
float *componentdata = (float *) data;
|
||||
|
||||
for (int i = 0; i < components; i++)
|
||||
componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0);
|
||||
|
||||
return sizeof(float) * components;
|
||||
}
|
||||
|
||||
char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Mesh::DATA_BYTE:
|
||||
return data + writeByteData(L, startidx, components, data);
|
||||
case Mesh::DATA_FLOAT:
|
||||
return data + writeFloatData(L, startidx, components, data);
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t readByteData(lua_State *L, int components, const char *data)
|
||||
{
|
||||
const uint8 *componentdata = (const uint8 *) data;
|
||||
|
||||
for (int i = 0; i < components; i++)
|
||||
lua_pushnumber(L, (lua_Number) componentdata[i] / 255.0);
|
||||
|
||||
return sizeof(uint8) * components;
|
||||
}
|
||||
|
||||
static inline size_t readFloatData(lua_State *L, int components, const char *data)
|
||||
{
|
||||
const float *componentdata = (const float *) data;
|
||||
|
||||
for (int i = 0; i < components; i++)
|
||||
lua_pushnumber(L, componentdata[i]);
|
||||
|
||||
return sizeof(float) * components;
|
||||
}
|
||||
|
||||
const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Mesh::DATA_BYTE:
|
||||
return data + readByteData(L, components, data);
|
||||
case Mesh::DATA_FLOAT:
|
||||
return data + readFloatData(L, components, data);
|
||||
default:
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
int w_Mesh_setVertices(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
size_t vertoffset = (size_t) luaL_optnumber(L, 3, 1) - 1;
|
||||
|
||||
if (vertoffset >= t->getVertexCount())
|
||||
return luaL_error(L, "Invalid vertex start index (must be between 1 and %d)", (int) t->getVertexCount());
|
||||
|
||||
size_t stride = t->getVertexStride();
|
||||
size_t byteoffset = vertoffset * stride;
|
||||
|
||||
if (luax_istype(L, 2, Data::type))
|
||||
{
|
||||
Data *d = luax_checktype<Data>(L, 2);
|
||||
|
||||
size_t datasize = std::min(d->getSize(), (t->getVertexCount() - vertoffset) * stride);
|
||||
char *bytedata = (char *) t->mapVertexData() + byteoffset;
|
||||
|
||||
memcpy(bytedata, d->getData(), datasize);
|
||||
|
||||
t->unmapVertexData(byteoffset, datasize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
luaL_checktype(L, 2, LUA_TTABLE);
|
||||
int nvertices = (int) luax_objlen(L, 2);
|
||||
|
||||
if (vertoffset + nvertices > t->getVertexCount())
|
||||
return luaL_error(L, "Too many vertices (expected at most %d, got %d)", (int) t->getVertexCount() - (int) vertoffset, (int) nvertices);
|
||||
|
||||
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
||||
|
||||
int ncomponents = 0;
|
||||
for (const Mesh::AttribFormat &format : vertexformat)
|
||||
ncomponents += format.components;
|
||||
|
||||
char *data = (char *) t->mapVertexData() + byteoffset;
|
||||
|
||||
for (int i = 0; i < nvertices; i++)
|
||||
{
|
||||
// get vertices[vertindex]
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
|
||||
// get vertices[vertindex][j]
|
||||
for (int j = 1; j <= ncomponents; j++)
|
||||
lua_rawgeti(L, -j, j);
|
||||
|
||||
int idx = -ncomponents;
|
||||
|
||||
for (const Mesh::AttribFormat &format : vertexformat)
|
||||
{
|
||||
// Fetch the values from Lua and store them in data buffer.
|
||||
data = luax_writeAttributeData(L, idx, format.type, format.components, data);
|
||||
|
||||
idx += format.components;
|
||||
}
|
||||
|
||||
lua_pop(L, ncomponents + 1);
|
||||
}
|
||||
|
||||
t->unmapVertexData(byteoffset, nvertices * stride);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_setVertex(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
|
||||
|
||||
bool istable = lua_istable(L, 3);
|
||||
|
||||
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
||||
|
||||
char *data = (char *) t->getVertexScratchBuffer();
|
||||
char *writtendata = data;
|
||||
|
||||
int idx = istable ? 1 : 3;
|
||||
|
||||
if (istable)
|
||||
{
|
||||
for (const Mesh::AttribFormat &format : vertexformat)
|
||||
{
|
||||
for (int i = idx; i < idx + format.components; i++)
|
||||
lua_rawgeti(L, 3, i);
|
||||
|
||||
// Fetch the values from Lua and store them in data buffer.
|
||||
writtendata = luax_writeAttributeData(L, -format.components, format.type, format.components, writtendata);
|
||||
|
||||
idx += format.components;
|
||||
lua_pop(L, format.components);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const Mesh::AttribFormat &format : vertexformat)
|
||||
{
|
||||
// Fetch the values from Lua and store them in data buffer.
|
||||
writtendata = luax_writeAttributeData(L, idx, format.type, format.components, writtendata);
|
||||
idx += format.components;
|
||||
}
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&](){ t->setVertex(index, data, t->getVertexStride()); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getVertex(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
size_t index = (size_t) luaL_checkinteger(L, 2) - 1;
|
||||
|
||||
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
||||
|
||||
char *data = (char *) t->getVertexScratchBuffer();
|
||||
const char *readdata = data;
|
||||
|
||||
luax_catchexcept(L, [&](){ t->getVertex(index, data, t->getVertexStride()); });
|
||||
|
||||
int n = 0;
|
||||
|
||||
for (const Mesh::AttribFormat &format : vertexformat)
|
||||
{
|
||||
readdata = luax_readAttributeData(L, format.type, format.components, readdata);
|
||||
n += format.components;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int w_Mesh_setVertexAttribute(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
|
||||
int attribindex = (int) luaL_checkinteger(L, 3) - 1;
|
||||
|
||||
Mesh::DataType type;
|
||||
int components;
|
||||
luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
|
||||
|
||||
// Maximum possible size for a single vertex attribute.
|
||||
char data[sizeof(float) * 4];
|
||||
|
||||
// Fetch the values from Lua and store them in the data buffer.
|
||||
luax_writeAttributeData(L, 4, type, components, data);
|
||||
|
||||
luax_catchexcept(L, [&](){ t->setVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getVertexAttribute(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
|
||||
int attribindex = (int) luaL_checkinteger(L, 3) - 1;
|
||||
|
||||
Mesh::DataType type;
|
||||
int components;
|
||||
luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
|
||||
|
||||
// Maximum possible size for a single vertex attribute.
|
||||
char data[sizeof(float) * 4];
|
||||
|
||||
luax_catchexcept(L, [&](){ t->getVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
|
||||
|
||||
luax_readAttributeData(L, type, components, data);
|
||||
return components;
|
||||
}
|
||||
|
||||
int w_Mesh_getVertexCount(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
lua_pushinteger(L, t->getVertexCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_getVertexFormat(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
const std::vector<Mesh::AttribFormat> &vertexformat = t->getVertexFormat();
|
||||
lua_createtable(L, (int) vertexformat.size(), 0);
|
||||
|
||||
const char *tname = nullptr;
|
||||
|
||||
for (size_t i = 0; i < vertexformat.size(); i++)
|
||||
{
|
||||
if (!Mesh::getConstant(vertexformat[i].type, tname))
|
||||
return luaL_error(L, "Unknown vertex attribute data type.");
|
||||
|
||||
lua_createtable(L, 3, 0);
|
||||
|
||||
lua_pushstring(L, vertexformat[i].name.c_str());
|
||||
lua_rawseti(L, -2, 1);
|
||||
|
||||
lua_pushstring(L, tname);
|
||||
lua_rawseti(L, -2, 2);
|
||||
|
||||
lua_pushinteger(L, vertexformat[i].components);
|
||||
lua_rawseti(L, -2, 3);
|
||||
|
||||
// format[i] = {name, type, components}
|
||||
lua_rawseti(L, -2, (int) i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_setAttributeEnabled(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
bool enable = luax_toboolean(L, 3);
|
||||
luax_catchexcept(L, [&](){ t->setAttributeEnabled(name, enable); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_isAttributeEnabled(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
bool enabled = false;
|
||||
luax_catchexcept(L, [&](){ enabled = t->isAttributeEnabled(name); });
|
||||
lua_pushboolean(L, enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_attachAttribute(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
Mesh *mesh = luax_checkmesh(L, 3);
|
||||
|
||||
Mesh::AttributeStep step = Mesh::STEP_PER_VERTEX;
|
||||
const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
|
||||
if (stepstr != nullptr && !Mesh::getConstant(stepstr, step))
|
||||
return luaL_error(L, "Invalid vertex attribute step: %s", stepstr);
|
||||
|
||||
const char *attachname = luaL_optstring(L, 5, name);
|
||||
|
||||
luax_catchexcept(L, [&](){ t->attachAttribute(name, mesh, attachname, step); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_detachAttribute(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
bool success = false;
|
||||
luax_catchexcept(L, [&](){ success = t->detachAttribute(name); });
|
||||
luax_pushboolean(L, success);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_flush(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
t->flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_setVertexMap(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
if (lua_isnoneornil(L, 2))
|
||||
{
|
||||
// Disable the vertex map / index buffer.
|
||||
luax_catchexcept(L, [&](){ t->setVertexMap(); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (luax_istype(L, 2, Data::type))
|
||||
{
|
||||
Data *d = luax_totype<Data>(L, 2, Data::type);
|
||||
|
||||
const char *indextypestr = luaL_checkstring(L, 3);
|
||||
IndexDataType indextype;
|
||||
if (!vertex::getConstant(indextypestr, indextype))
|
||||
return luaL_error(L, "Invalid index data type: %s", indextypestr);
|
||||
|
||||
size_t datatypesize = vertex::getIndexDataSize(indextype);
|
||||
|
||||
int indexcount = (int) luaL_optnumber(L, 4, d->getSize() / datatypesize);
|
||||
|
||||
if (indexcount < 1 || indexcount * datatypesize > d->getSize())
|
||||
return luaL_error(L, "Invalid index count: %d", indexcount);
|
||||
|
||||
luax_catchexcept(L, [&]() { t->setVertexMap(indextype, d->getData(), indexcount * datatypesize); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool is_table = lua_istable(L, 2);
|
||||
int nargs = is_table ? (int) luax_objlen(L, 2) : lua_gettop(L) - 1;
|
||||
|
||||
std::vector<uint32> vertexmap;
|
||||
vertexmap.reserve(nargs);
|
||||
|
||||
if (is_table)
|
||||
{
|
||||
for (int i = 0; i < nargs; i++)
|
||||
{
|
||||
lua_rawgeti(L, 2, i + 1);
|
||||
vertexmap.push_back(uint32(luaL_checkinteger(L, -1) - 1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < nargs; i++)
|
||||
vertexmap.push_back(uint32(luaL_checkinteger(L, i + 2) - 1));
|
||||
}
|
||||
|
||||
luax_catchexcept(L, [&](){ t->setVertexMap(vertexmap); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getVertexMap(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
std::vector<uint32> vertex_map;
|
||||
bool has_vertex_map = false;
|
||||
luax_catchexcept(L, [&](){ has_vertex_map = t->getVertexMap(vertex_map); });
|
||||
|
||||
if (!has_vertex_map)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int element_count = (int) vertex_map.size();
|
||||
|
||||
lua_createtable(L, element_count, 0);
|
||||
|
||||
for (int i = 0; i < element_count; i++)
|
||||
{
|
||||
lua_pushinteger(L, lua_Integer(vertex_map[i]) + 1);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_setTexture(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
if (lua_isnoneornil(L, 2))
|
||||
t->setTexture();
|
||||
else
|
||||
{
|
||||
Texture *tex = luax_checktexture(L, 2);
|
||||
t->setTexture(tex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getTexture(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
Texture *tex = t->getTexture();
|
||||
|
||||
if (tex == nullptr)
|
||||
return 0;
|
||||
|
||||
// FIXME: big hack right here.
|
||||
if (dynamic_cast<Image *>(tex) != nullptr)
|
||||
luax_pushtype(L, Image::type, tex);
|
||||
else if (dynamic_cast<Canvas *>(tex) != nullptr)
|
||||
luax_pushtype(L, Canvas::type, tex);
|
||||
else
|
||||
return luaL_error(L, "Unable to determine texture type.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_setDrawMode(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
const char *str = luaL_checkstring(L, 2);
|
||||
Mesh::DrawMode mode;
|
||||
|
||||
if (!Mesh::getConstant(str, mode))
|
||||
return luaL_error(L, "Invalid mesh draw mode: %s", str);
|
||||
|
||||
t->setDrawMode(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getDrawMode(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
Mesh::DrawMode mode = t->getDrawMode();
|
||||
const char *str;
|
||||
|
||||
if (!Mesh::getConstant(mode, str))
|
||||
return luaL_error(L, "Unknown mesh draw mode.");
|
||||
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_Mesh_setDrawRange(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
if (lua_isnoneornil(L, 2))
|
||||
t->setDrawRange();
|
||||
else
|
||||
{
|
||||
int start = (int) luaL_checknumber(L, 2) - 1;
|
||||
int count = (int) luaL_checknumber(L, 3);
|
||||
luax_catchexcept(L, [&](){ t->setDrawRange(start, count); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_Mesh_getDrawRange(lua_State *L)
|
||||
{
|
||||
Mesh *t = luax_checkmesh(L, 1);
|
||||
|
||||
int start = 0;
|
||||
int count = 1;
|
||||
if (!t->getDrawRange(start, count))
|
||||
return 0;
|
||||
|
||||
lua_pushinteger(L, start + 1);
|
||||
lua_pushinteger(L, count);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_Mesh_functions[] =
|
||||
{
|
||||
{ "setVertices", w_Mesh_setVertices },
|
||||
{ "setVertex", w_Mesh_setVertex },
|
||||
{ "getVertex", w_Mesh_getVertex },
|
||||
{ "setVertexAttribute", w_Mesh_setVertexAttribute },
|
||||
{ "getVertexAttribute", w_Mesh_getVertexAttribute },
|
||||
{ "getVertexCount", w_Mesh_getVertexCount },
|
||||
{ "getVertexFormat", w_Mesh_getVertexFormat },
|
||||
{ "setAttributeEnabled", w_Mesh_setAttributeEnabled },
|
||||
{ "isAttributeEnabled", w_Mesh_isAttributeEnabled },
|
||||
{ "attachAttribute", w_Mesh_attachAttribute },
|
||||
{ "detachAttribute", w_Mesh_detachAttribute },
|
||||
{ "flush", w_Mesh_flush },
|
||||
{ "setVertexMap", w_Mesh_setVertexMap },
|
||||
{ "getVertexMap", w_Mesh_getVertexMap },
|
||||
{ "setTexture", w_Mesh_setTexture },
|
||||
{ "getTexture", w_Mesh_getTexture },
|
||||
{ "setDrawMode", w_Mesh_setDrawMode },
|
||||
{ "getDrawMode", w_Mesh_getDrawMode },
|
||||
{ "setDrawRange", w_Mesh_setDrawRange },
|
||||
{ "getDrawRange", w_Mesh_getDrawRange },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_mesh(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, &Mesh::type, w_Mesh_functions, nullptr);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
|
||||
#define LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
|
||||
|
||||
// LOVE
|
||||
#include "common/config.h"
|
||||
#include "common/runtime.h"
|
||||
#include "Mesh.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data);
|
||||
const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data);
|
||||
|
||||
Mesh *luax_checkmesh(lua_State *L, int idx);
|
||||
extern "C" int luaopen_mesh(lua_State *L);
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_OPENGL_WRAP_MESH_H
|
||||
@@ -1,777 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
// LOVE
|
||||
#include "wrap_ParticleSystem.h"
|
||||
#include "common/Vector.h"
|
||||
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
|
||||
// C
|
||||
#include <cstring>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
ParticleSystem *luax_checkparticlesystem(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<ParticleSystem>(L, idx);
|
||||
}
|
||||
|
||||
int w_ParticleSystem_clone(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
|
||||
ParticleSystem *clone = nullptr;
|
||||
luax_catchexcept(L, [&](){ clone = t->clone(); });
|
||||
|
||||
luax_pushtype(L, clone);
|
||||
clone->release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setTexture(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
Texture *tex = luax_checktexture(L, 2);
|
||||
t->setTexture(tex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getTexture(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
Texture *tex = t->getTexture();
|
||||
|
||||
// FIXME: big hack right here.
|
||||
if (dynamic_cast<Image *>(tex) != nullptr)
|
||||
luax_pushtype(L, Image::type, tex);
|
||||
else if (dynamic_cast<Canvas *>(tex) != nullptr)
|
||||
luax_pushtype(L, Canvas::type, tex);
|
||||
else
|
||||
return luaL_error(L, "Unable to determine texture type.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setBufferSize(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_Number arg1 = luaL_checknumber(L, 2);
|
||||
if (arg1 < 1.0 || arg1 > ParticleSystem::MAX_PARTICLES)
|
||||
return luaL_error(L, "Invalid buffer size");
|
||||
|
||||
luax_catchexcept(L, [&](){ t->setBufferSize((uint32) arg1); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getBufferSize(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushinteger(L, t->getBufferSize());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setInsertMode(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
ParticleSystem::InsertMode mode;
|
||||
const char *str = luaL_checkstring(L, 2);
|
||||
if (!ParticleSystem::getConstant(str, mode))
|
||||
return luaL_error(L, "Invalid insert mode: '%s'", str);
|
||||
t->setInsertMode(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getInsertMode(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
ParticleSystem::InsertMode mode;
|
||||
mode = t->getInsertMode();
|
||||
const char *str;
|
||||
if (!ParticleSystem::getConstant(mode, str))
|
||||
return luaL_error(L, "Unknown insert mode");
|
||||
lua_pushstring(L, str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setEmissionRate(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float) luaL_checknumber(L, 2);
|
||||
luax_catchexcept(L, [&](){ t->setEmissionRate(arg1); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getEmissionRate(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getEmissionRate());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setEmitterLifetime(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setEmitterLifetime(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getEmitterLifetime(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getEmitterLifetime());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setParticleLifetime(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setParticleLifetime(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getParticleLifetime(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getParticleLifetime(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setPosition(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_checknumber(L, 3);
|
||||
t->setPosition(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getPosition(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
love::Vector pos = t->getPosition();
|
||||
lua_pushnumber(L, pos.getX());
|
||||
lua_pushnumber(L, pos.getY());
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_moveTo(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_checknumber(L, 3);
|
||||
t->moveTo(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setAreaSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
|
||||
ParticleSystem::AreaSpreadDistribution distribution = ParticleSystem::DISTRIBUTION_NONE;
|
||||
float x = 0.f, y = 0.f;
|
||||
|
||||
const char *str = lua_isnoneornil(L, 2) ? 0 : luaL_checkstring(L, 2);
|
||||
if (str && !ParticleSystem::getConstant(str, distribution))
|
||||
return luaL_error(L, "Invalid particle distribution: %s", str);
|
||||
|
||||
if (distribution != ParticleSystem::DISTRIBUTION_NONE)
|
||||
{
|
||||
x = (float) luaL_checknumber(L, 3);
|
||||
y = (float) luaL_checknumber(L, 4);
|
||||
if (x < 0.0f || y < 0.0f)
|
||||
return luaL_error(L, "Invalid area spread parameters (must be >= 0)");
|
||||
}
|
||||
|
||||
t->setAreaSpread(distribution, x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getAreaSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
ParticleSystem::AreaSpreadDistribution distribution = t-> getAreaSpreadDistribution();
|
||||
const char *str;
|
||||
ParticleSystem::getConstant(distribution, str);
|
||||
const love::Vector &p = t->getAreaSpreadParameters();
|
||||
|
||||
lua_pushstring(L, str);
|
||||
lua_pushnumber(L, p.x);
|
||||
lua_pushnumber(L, p.y);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setDirection(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setDirection(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getDirection(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getDirection());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setSpread(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSpread(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getSpread());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSpeed(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setSpeed(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSpeed(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getSpeed(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setLinearAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float xmin = (float) luaL_checknumber(L, 2);
|
||||
float ymin = (float) luaL_checknumber(L, 3);
|
||||
float xmax = (float) luaL_optnumber(L, 4, xmin);
|
||||
float ymax = (float) luaL_optnumber(L, 5, ymin);
|
||||
t->setLinearAcceleration(xmin, ymin, xmax, ymax);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getLinearAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
love::Vector min, max;
|
||||
t->getLinearAcceleration(min, max);
|
||||
lua_pushnumber(L, min.x);
|
||||
lua_pushnumber(L, min.y);
|
||||
lua_pushnumber(L, max.x);
|
||||
lua_pushnumber(L, max.y);
|
||||
return 4;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setRadialAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setRadialAcceleration(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getRadialAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getRadialAcceleration(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setTangentialAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setTangentialAcceleration(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getTangentialAcceleration(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getTangentialAcceleration(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setLinearDamping(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setLinearDamping(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getLinearDamping(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getLinearDamping(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSizes(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
size_t nSizes = lua_gettop(L) - 1;
|
||||
|
||||
if (nSizes > 8)
|
||||
return luaL_error(L, "At most eight (8) sizes may be used.");
|
||||
|
||||
if (nSizes <= 1)
|
||||
{
|
||||
float size = luax_checkfloat(L, 2);
|
||||
t->setSize(size);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<float> sizes(nSizes);
|
||||
for (size_t i = 0; i < nSizes; ++i)
|
||||
sizes[i] = luax_checkfloat(L, (int) (1 + i + 1));
|
||||
|
||||
t->setSizes(sizes);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSizes(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
const std::vector<float> &sizes = t->getSizes();
|
||||
|
||||
for (size_t i = 0; i < sizes.size(); i++)
|
||||
lua_pushnumber(L, sizes[i]);
|
||||
|
||||
return (int) sizes.size();
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSizeVariation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
if (arg1 < 0.0f || arg1 > 1.0f)
|
||||
return luaL_error(L, "Size variation has to be between 0 and 1, inclusive.");
|
||||
|
||||
t->setSizeVariation(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSizeVariation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getSizeVariation());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setRotation(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float min, max;
|
||||
t->getRotation(min, max);
|
||||
lua_pushnumber(L, min);
|
||||
lua_pushnumber(L, max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSpin(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
float arg2 = (float)luaL_optnumber(L, 3, arg1);
|
||||
t->setSpin(arg1, arg2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSpin(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float start, end;
|
||||
t->getSpin(start, end);
|
||||
lua_pushnumber(L, start);
|
||||
lua_pushnumber(L, end);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setSpinVariation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float arg1 = (float)luaL_checknumber(L, 2);
|
||||
t->setSpinVariation(arg1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getSpinVariation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getSpinVariation());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setOffset(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float x = (float)luaL_checknumber(L, 2);
|
||||
float y = (float)luaL_checknumber(L, 3);
|
||||
t->setOffset(x, y);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getOffset(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
love::Vector offset = t->getOffset();
|
||||
lua_pushnumber(L, offset.getX());
|
||||
lua_pushnumber(L, offset.getY());
|
||||
return 2;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setColors(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
|
||||
if (lua_istable(L, 2)) // setColors({r,g,b,a}, {r,g,b,a}, ...)
|
||||
{
|
||||
int nColors = (int) lua_gettop(L) - 1;
|
||||
|
||||
if (nColors > 8)
|
||||
return luaL_error(L, "At most eight (8) colors may be used.");
|
||||
|
||||
std::vector<Colorf> colors(nColors);
|
||||
|
||||
for (int i = 0; i < nColors; i++)
|
||||
{
|
||||
luaL_checktype(L, i + 2, LUA_TTABLE);
|
||||
|
||||
if (luax_objlen(L, i + 2) < 3)
|
||||
return luaL_argerror(L, i + 2, "expected 4 color components");
|
||||
|
||||
for (int j = 0; j < 4; j++)
|
||||
// push args[i+2][j+1] onto the stack
|
||||
lua_rawgeti(L, i + 2, j + 1);
|
||||
|
||||
colors[i].r = (float) luaL_checknumber(L, -4);
|
||||
colors[i].g = (float) luaL_checknumber(L, -3);
|
||||
colors[i].b = (float) luaL_checknumber(L, -2);
|
||||
colors[i].a = (float) luaL_optnumber(L, -1, 1.0);
|
||||
|
||||
// pop the color components from the stack
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
|
||||
t->setColor(colors);
|
||||
}
|
||||
else // setColors(r,g,b,a, r,g,b,a, ...)
|
||||
{
|
||||
int cargs = lua_gettop(L) - 1;
|
||||
int nColors = (cargs + 3) / 4; // nColors = ceil(color_args / 4)
|
||||
|
||||
if (cargs != 3 && (cargs % 4 != 0 || cargs == 0))
|
||||
return luaL_error(L, "Expected red, green, blue, and alpha. Only got %d of 4 components.", cargs % 4);
|
||||
|
||||
if (nColors > 8)
|
||||
return luaL_error(L, "At most eight (8) colors may be used.");
|
||||
|
||||
std::vector<Colorf> colors(nColors);
|
||||
|
||||
for (int i = 0; i < nColors; ++i)
|
||||
{
|
||||
colors[i].r = (float) luaL_checknumber(L, 1 + i*4 + 1);
|
||||
colors[i].g = (float) luaL_checknumber(L, 1 + i*4 + 2);
|
||||
colors[i].b = (float) luaL_checknumber(L, 1 + i*4 + 3);
|
||||
colors[i].a = (float) luaL_checknumber(L, 1 + i*4 + 4);
|
||||
}
|
||||
|
||||
t->setColor(colors);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getColors(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
|
||||
const std::vector<Colorf> &colors =t->getColor();
|
||||
|
||||
for (size_t i = 0; i < colors.size(); i++)
|
||||
{
|
||||
lua_createtable(L, 4, 0);
|
||||
|
||||
lua_pushnumber(L, colors[i].r);
|
||||
lua_rawseti(L, -2, 1);
|
||||
lua_pushnumber(L, colors[i].g);
|
||||
lua_rawseti(L, -2, 2);
|
||||
lua_pushnumber(L, colors[i].b);
|
||||
lua_rawseti(L, -2, 3);
|
||||
lua_pushnumber(L, colors[i].a);
|
||||
lua_rawseti(L, -2, 4);
|
||||
}
|
||||
|
||||
return (int) colors.size();
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setQuads(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
std::vector<Quad *> quads;
|
||||
|
||||
if (lua_istable(L, 2))
|
||||
{
|
||||
for (int i = 1; i <= (int) luax_objlen(L, 2); i++)
|
||||
{
|
||||
lua_rawgeti(L, 2, i);
|
||||
|
||||
Quad *q = luax_checktype<Quad>(L, -1);
|
||||
quads.push_back(q);
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 2; i <= lua_gettop(L); i++)
|
||||
{
|
||||
Quad *q = luax_checktype<Quad>(L, i);
|
||||
quads.push_back(q);
|
||||
}
|
||||
}
|
||||
|
||||
t->setQuads(quads);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getQuads(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
const std::vector<Quad *> quads = t->getQuads();
|
||||
|
||||
lua_createtable(L, (int) quads.size(), 0);
|
||||
|
||||
for (int i = 0; i < (int) quads.size(); i++)
|
||||
{
|
||||
luax_pushtype(L, quads[i]);
|
||||
lua_rawseti(L, -2, i + 1);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_setRelativeRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->setRelativeRotation(luax_toboolean(L, 2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_hasRelativeRotation(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
luax_pushboolean(L, t->hasRelativeRotation());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_getCount(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
lua_pushnumber(L, t->getCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_start(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->start();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_stop(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->stop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_pause(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->pause();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_reset(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
t->reset();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_emit(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
int num = (int) luaL_checknumber(L, 2);
|
||||
t->emit(num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_isActive(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
luax_pushboolean(L, t->isActive());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_isPaused(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
luax_pushboolean(L, t->isPaused());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_isStopped(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
luax_pushboolean(L, t->isStopped());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_ParticleSystem_update(lua_State *L)
|
||||
{
|
||||
ParticleSystem *t = luax_checkparticlesystem(L, 1);
|
||||
float dt = (float)luaL_checknumber(L, 2);
|
||||
t->update(dt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_ParticleSystem_functions[] =
|
||||
{
|
||||
{ "clone", w_ParticleSystem_clone },
|
||||
{ "setTexture", w_ParticleSystem_setTexture },
|
||||
{ "getTexture", w_ParticleSystem_getTexture },
|
||||
{ "setBufferSize", w_ParticleSystem_setBufferSize },
|
||||
{ "getBufferSize", w_ParticleSystem_getBufferSize },
|
||||
{ "setInsertMode", w_ParticleSystem_setInsertMode },
|
||||
{ "getInsertMode", w_ParticleSystem_getInsertMode },
|
||||
{ "setEmissionRate", w_ParticleSystem_setEmissionRate },
|
||||
{ "getEmissionRate", w_ParticleSystem_getEmissionRate },
|
||||
{ "setEmitterLifetime", w_ParticleSystem_setEmitterLifetime },
|
||||
{ "getEmitterLifetime", w_ParticleSystem_getEmitterLifetime },
|
||||
{ "setParticleLifetime", w_ParticleSystem_setParticleLifetime },
|
||||
{ "getParticleLifetime", w_ParticleSystem_getParticleLifetime },
|
||||
{ "setPosition", w_ParticleSystem_setPosition },
|
||||
{ "getPosition", w_ParticleSystem_getPosition },
|
||||
{ "moveTo", w_ParticleSystem_moveTo },
|
||||
{ "setAreaSpread", w_ParticleSystem_setAreaSpread },
|
||||
{ "getAreaSpread", w_ParticleSystem_getAreaSpread },
|
||||
{ "setDirection", w_ParticleSystem_setDirection },
|
||||
{ "getDirection", w_ParticleSystem_getDirection },
|
||||
{ "setSpread", w_ParticleSystem_setSpread },
|
||||
{ "getSpread", w_ParticleSystem_getSpread },
|
||||
{ "setSpeed", w_ParticleSystem_setSpeed },
|
||||
{ "getSpeed", w_ParticleSystem_getSpeed },
|
||||
{ "setLinearAcceleration", w_ParticleSystem_setLinearAcceleration },
|
||||
{ "getLinearAcceleration", w_ParticleSystem_getLinearAcceleration },
|
||||
{ "setRadialAcceleration", w_ParticleSystem_setRadialAcceleration },
|
||||
{ "getRadialAcceleration", w_ParticleSystem_getRadialAcceleration },
|
||||
{ "setTangentialAcceleration", w_ParticleSystem_setTangentialAcceleration },
|
||||
{ "getTangentialAcceleration", w_ParticleSystem_getTangentialAcceleration },
|
||||
{ "setLinearDamping", w_ParticleSystem_setLinearDamping },
|
||||
{ "getLinearDamping", w_ParticleSystem_getLinearDamping },
|
||||
{ "setSizes", w_ParticleSystem_setSizes },
|
||||
{ "getSizes", w_ParticleSystem_getSizes },
|
||||
{ "setSizeVariation", w_ParticleSystem_setSizeVariation },
|
||||
{ "getSizeVariation", w_ParticleSystem_getSizeVariation },
|
||||
{ "setRotation", w_ParticleSystem_setRotation },
|
||||
{ "getRotation", w_ParticleSystem_getRotation },
|
||||
{ "setSpin", w_ParticleSystem_setSpin },
|
||||
{ "getSpin", w_ParticleSystem_getSpin },
|
||||
{ "setSpinVariation", w_ParticleSystem_setSpinVariation },
|
||||
{ "getSpinVariation", w_ParticleSystem_getSpinVariation },
|
||||
{ "setColors", w_ParticleSystem_setColors },
|
||||
{ "getColors", w_ParticleSystem_getColors },
|
||||
{ "setQuads", w_ParticleSystem_setQuads },
|
||||
{ "getQuads", w_ParticleSystem_getQuads },
|
||||
{ "setOffset", w_ParticleSystem_setOffset },
|
||||
{ "getOffset", w_ParticleSystem_getOffset },
|
||||
{ "setRelativeRotation", w_ParticleSystem_setRelativeRotation },
|
||||
{ "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation },
|
||||
{ "getCount", w_ParticleSystem_getCount },
|
||||
{ "start", w_ParticleSystem_start },
|
||||
{ "stop", w_ParticleSystem_stop },
|
||||
{ "pause", w_ParticleSystem_pause },
|
||||
{ "reset", w_ParticleSystem_reset },
|
||||
{ "emit", w_ParticleSystem_emit },
|
||||
{ "isActive", w_ParticleSystem_isActive },
|
||||
{ "isPaused", w_ParticleSystem_isPaused },
|
||||
{ "isStopped", w_ParticleSystem_isStopped },
|
||||
{ "update", w_ParticleSystem_update },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_particlesystem(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, &ParticleSystem::type, w_ParticleSystem_functions, nullptr);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_WRAP_PARTICLE_SYSTEM_H
|
||||
#define LOVE_GRAPHICS_OPENGL_WRAP_PARTICLE_SYSTEM_H
|
||||
|
||||
// LOVE
|
||||
#include "common/runtime.h"
|
||||
#include "ParticleSystem.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
ParticleSystem *luax_checkparticlesystem(lua_State *L, int idx);
|
||||
extern "C" int luaopen_particlesystem(lua_State *L);
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_OPENGL_WRAP_PARTICLE_SYSTEM_H
|
||||
@@ -1,279 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
// LOVE
|
||||
#include "wrap_SpriteBatch.h"
|
||||
#include "Image.h"
|
||||
#include "Canvas.h"
|
||||
#include "graphics/wrap_Texture.h"
|
||||
#include "math/wrap_Transform.h"
|
||||
|
||||
// C++
|
||||
#include <typeinfo>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
SpriteBatch *luax_checkspritebatch(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<SpriteBatch>(L, idx);
|
||||
}
|
||||
|
||||
static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int startidx, int index)
|
||||
{
|
||||
Quad *quad = nullptr;
|
||||
|
||||
if (luax_istype(L, startidx, Quad::type))
|
||||
{
|
||||
quad = luax_totype<Quad>(L, startidx);
|
||||
startidx++;
|
||||
}
|
||||
else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1))
|
||||
return luax_typerror(L, startidx, "Quad");
|
||||
|
||||
if (luax_istype(L, startidx, math::Transform::type))
|
||||
{
|
||||
math::Transform *tf = luax_totype<math::Transform>(L, startidx);
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (quad)
|
||||
index = t->addq(quad, tf->getMatrix(), index);
|
||||
else
|
||||
index = t->add(tf->getMatrix(), index);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
float x = (float) luaL_optnumber(L, startidx + 0, 0.0);
|
||||
float y = (float) luaL_optnumber(L, startidx + 1, 0.0);
|
||||
float a = (float) luaL_optnumber(L, startidx + 2, 0.0);
|
||||
float sx = (float) luaL_optnumber(L, startidx + 3, 1.0);
|
||||
float sy = (float) luaL_optnumber(L, startidx + 4, sx);
|
||||
float ox = (float) luaL_optnumber(L, startidx + 5, 0.0);
|
||||
float oy = (float) luaL_optnumber(L, startidx + 6, 0.0);
|
||||
float kx = (float) luaL_optnumber(L, startidx + 7, 0.0);
|
||||
float ky = (float) luaL_optnumber(L, startidx + 8, 0.0);
|
||||
|
||||
Matrix4 m(x, y, a, sx, sy, ox, oy, kx, ky);
|
||||
|
||||
luax_catchexcept(L, [&]() {
|
||||
if (quad)
|
||||
index = t->addq(quad, m, index);
|
||||
else
|
||||
index = t->add(m, index);
|
||||
});
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_add(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
|
||||
int index = w_SpriteBatch_add_or_set(L, t, 2, -1);
|
||||
lua_pushinteger(L, index + 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_set(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
int index = (int) luaL_checknumber(L, 2) - 1;
|
||||
|
||||
w_SpriteBatch_add_or_set(L, t, 3, index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_clear(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
t->clear();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_flush(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
t->flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_setTexture(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
Texture *tex = luax_checktexture(L, 2);
|
||||
t->setTexture(tex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_getTexture(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
Texture *tex = t->getTexture();
|
||||
|
||||
// FIXME: big hack right here.
|
||||
if (dynamic_cast<Image *>(tex) != nullptr)
|
||||
luax_pushtype(L, Image::type, tex);
|
||||
else if (dynamic_cast<Canvas *>(tex) != nullptr)
|
||||
luax_pushtype(L, Canvas::type, tex);
|
||||
else
|
||||
return luaL_error(L, "Unable to determine texture type.");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_setColor(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
Color c;
|
||||
|
||||
if (lua_gettop(L) <= 1)
|
||||
{
|
||||
t->setColor();
|
||||
return 0;
|
||||
}
|
||||
else if (lua_istable(L, 2))
|
||||
{
|
||||
for (int i = 1; i <= 4; i++)
|
||||
lua_rawgeti(L, 2, i);
|
||||
|
||||
c.r = (unsigned char) (luaL_checknumber(L, -4) * 255.0);
|
||||
c.g = (unsigned char) (luaL_checknumber(L, -3) * 255.0);
|
||||
c.b = (unsigned char) (luaL_checknumber(L, -2) * 255.0);
|
||||
c.a = (unsigned char) (luaL_optnumber(L, -1, 1.0) * 255.0);
|
||||
|
||||
lua_pop(L, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.r = (unsigned char) (luaL_checknumber(L, 2) * 255.0);
|
||||
c.g = (unsigned char) (luaL_checknumber(L, 3) * 255.0);
|
||||
c.b = (unsigned char) (luaL_checknumber(L, 4) * 255.0);
|
||||
c.a = (unsigned char) (luaL_optnumber(L, 5, 1.0) * 255.0);
|
||||
}
|
||||
|
||||
t->setColor(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_getColor(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
const Color *color = t->getColor();
|
||||
|
||||
// getColor returns null if no color is set.
|
||||
if (!color)
|
||||
return 0;
|
||||
|
||||
lua_pushnumber(L, (lua_Number) color->r / 255.0);
|
||||
lua_pushnumber(L, (lua_Number) color->g / 255.0);
|
||||
lua_pushnumber(L, (lua_Number) color->b / 255.0);
|
||||
lua_pushnumber(L, (lua_Number) color->a / 255.0);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_getCount(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
lua_pushinteger(L, t->getCount());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_getBufferSize(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
lua_pushinteger(L, t->getBufferSize());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_attachAttribute(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
const char *name = luaL_checkstring(L, 2);
|
||||
Mesh *m = luax_checktype<Mesh>(L, 3);
|
||||
|
||||
luax_catchexcept(L, [&](){ t->attachAttribute(name, m); });
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_setDrawRange(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
|
||||
if (lua_isnoneornil(L, 2))
|
||||
t->setDrawRange();
|
||||
else
|
||||
{
|
||||
int start = (int) luaL_checknumber(L, 2) - 1;
|
||||
int count = (int) luaL_checknumber(L, 3);
|
||||
luax_catchexcept(L, [&](){ t->setDrawRange(start, count); });
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w_SpriteBatch_getDrawRange(lua_State *L)
|
||||
{
|
||||
SpriteBatch *t = luax_checkspritebatch(L, 1);
|
||||
|
||||
int start = 0;
|
||||
int count = 1;
|
||||
if (!t->getDrawRange(start, count))
|
||||
return 0;
|
||||
|
||||
lua_pushnumber(L, start + 1);
|
||||
lua_pushnumber(L, count);
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const luaL_Reg w_SpriteBatch_functions[] =
|
||||
{
|
||||
{ "add", w_SpriteBatch_add },
|
||||
{ "set", w_SpriteBatch_set },
|
||||
{ "clear", w_SpriteBatch_clear },
|
||||
{ "flush", w_SpriteBatch_flush },
|
||||
{ "setTexture", w_SpriteBatch_setTexture },
|
||||
{ "getTexture", w_SpriteBatch_getTexture },
|
||||
{ "setColor", w_SpriteBatch_setColor },
|
||||
{ "getColor", w_SpriteBatch_getColor },
|
||||
{ "getCount", w_SpriteBatch_getCount },
|
||||
{ "getBufferSize", w_SpriteBatch_getBufferSize },
|
||||
{ "attachAttribute", w_SpriteBatch_attachAttribute },
|
||||
{ "setDrawRange", w_SpriteBatch_setDrawRange },
|
||||
{ "getDrawRange", w_SpriteBatch_getDrawRange },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
extern "C" int luaopen_spritebatch(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, &SpriteBatch::type, w_SpriteBatch_functions, nullptr);
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2017 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.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_GRAPHICS_OPENGL_WRAP_SPRITE_BATCH_H
|
||||
#define LOVE_GRAPHICS_OPENGL_WRAP_SPRITE_BATCH_H
|
||||
|
||||
#include "common/runtime.h"
|
||||
#include "SpriteBatch.h"
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
SpriteBatch *luax_checkspritebatch(lua_State *L, int idx);
|
||||
extern "C" int luaopen_spritebatch(lua_State *L);
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
#endif // LOVE_GRAPHICS_OPENGL_WRAP_SPRITE_BATCH_H
|
||||
Reference in New Issue
Block a user