mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Make internal vertex attribute code less OpenGL-specific.
--HG-- branch : minor
This commit is contained in:
@@ -527,6 +527,7 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
|
||||
src/modules/graphics/Polyline.h
|
||||
src/modules/graphics/Quad.cpp
|
||||
src/modules/graphics/Quad.h
|
||||
src/modules/graphics/Resource.h
|
||||
src/modules/graphics/Shader.cpp
|
||||
src/modules/graphics/Shader.h
|
||||
src/modules/graphics/ShaderStage.cpp
|
||||
|
||||
@@ -1730,6 +1730,7 @@
|
||||
FA0B7CCC1A95902C000E1D17 /* wrap_Window.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Window.h; sourceTree = "<group>"; };
|
||||
FA0B7EF01A959D2C000E1D17 /* ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ios.h; sourceTree = "<group>"; };
|
||||
FA0B7EF11A959D2C000E1D17 /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ios.mm; sourceTree = "<group>"; };
|
||||
FA10DD7B1F9EC24E00E1FE3D /* Resource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Resource.h; sourceTree = "<group>"; };
|
||||
FA1557BF1CE90A2C00AFF582 /* tinyexr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyexr.h; sourceTree = "<group>"; };
|
||||
FA1557C11CE90BD200AFF582 /* EXRHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EXRHandler.cpp; sourceTree = "<group>"; };
|
||||
FA1557C21CE90BD200AFF582 /* EXRHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXRHandler.h; sourceTree = "<group>"; };
|
||||
@@ -2725,6 +2726,7 @@
|
||||
FA0B7B9C1A95902C000E1D17 /* Polyline.h */,
|
||||
FA0B7BBC1A95902C000E1D17 /* Quad.cpp */,
|
||||
FA0B7BBD1A95902C000E1D17 /* Quad.h */,
|
||||
FA10DD7B1F9EC24E00E1FE3D /* Resource.h */,
|
||||
FA1BA0AF1E16FD0800AA2803 /* Shader.cpp */,
|
||||
FA1BA0B01E16FD0800AA2803 /* Shader.h */,
|
||||
FA3C5E401F8C368C0003C579 /* ShaderStage.cpp */,
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "common/config.h"
|
||||
#include "common/int.h"
|
||||
#include "vertex.h"
|
||||
#include "Resource.h"
|
||||
|
||||
// C
|
||||
#include <stddef.h>
|
||||
@@ -38,7 +39,7 @@ class Graphics;
|
||||
/**
|
||||
* A block of GPU-owned memory. Currently meant for internal use.
|
||||
**/
|
||||
class Buffer
|
||||
class Buffer : public Resource
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -91,11 +92,6 @@ public:
|
||||
**/
|
||||
virtual void setMappedRangeModified(size_t offset, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Gets the backend-specific handle for this Buffer.
|
||||
**/
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
/**
|
||||
* Fill a portion of the buffer with data and marks the range as modified.
|
||||
*
|
||||
|
||||
@@ -323,6 +323,8 @@ void Mesh::attachAttribute(const std::string &name, Mesh *mesh, const std::strin
|
||||
auto it = attachedAttributes.find(name);
|
||||
if (it != attachedAttributes.end())
|
||||
oldattrib = it->second;
|
||||
else if (attachedAttributes.size() + 1 > vertex::Attributes::MAX)
|
||||
throw love::Exception("A maximum of %d attributes can be attached at once.", vertex::Attributes::MAX);
|
||||
|
||||
newattrib.mesh = mesh;
|
||||
newattrib.enabled = oldattrib.mesh ? oldattrib.enabled : true;
|
||||
@@ -585,30 +587,48 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
if (Shader::current && texture.get())
|
||||
Shader::current->checkMainTexture(texture);
|
||||
|
||||
uint32 enabledattribs = 0;
|
||||
uint32 instancedattribs = 0;
|
||||
vertex::Attributes attributes;
|
||||
vertex::Buffers buffers;
|
||||
|
||||
int activebuffers = 0;
|
||||
|
||||
for (const auto &attrib : attachedAttributes)
|
||||
{
|
||||
if (!attrib.second.enabled)
|
||||
continue;
|
||||
|
||||
love::graphics::Mesh *mesh = attrib.second.mesh;
|
||||
int location = mesh->bindAttributeToShaderInput(attrib.second.index, attrib.first);
|
||||
Mesh *mesh = attrib.second.mesh;
|
||||
int attributeindex = -1;
|
||||
|
||||
if (location >= 0)
|
||||
// If the attribute is one of the LOVE-defined ones, use the constant
|
||||
// attribute index for it, otherwise query the index from the shader.
|
||||
VertexAttribID builtinattrib;
|
||||
if (vertex::getConstant(attrib.first.c_str(), builtinattrib))
|
||||
attributeindex = (int) builtinattrib;
|
||||
else if (Shader::current)
|
||||
attributeindex = Shader::current->getVertexAttributeIndex(attrib.first);
|
||||
|
||||
if (attributeindex >= 0)
|
||||
{
|
||||
uint32 bit = 1u << (uint32) location;
|
||||
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
|
||||
mesh->vbo->unmap();
|
||||
|
||||
enabledattribs |= bit;
|
||||
const auto &formats = mesh->getVertexFormat();
|
||||
const auto &format = formats[attrib.second.index];
|
||||
|
||||
if (attrib.second.step == STEP_PER_INSTANCE)
|
||||
instancedattribs |= bit;
|
||||
uint16 offset = (uint16) mesh->getAttributeOffset(attrib.second.index);
|
||||
uint16 stride = (uint16) mesh->getVertexStride();
|
||||
|
||||
attributes.set(attributeindex, format.type, format.components, offset, stride, activebuffers, attrib.second.step);
|
||||
|
||||
// TODO: Ideally we want to reuse buffers with the same stride+step.
|
||||
buffers.set(activebuffers, mesh->vbo, 0);
|
||||
activebuffers++;
|
||||
}
|
||||
}
|
||||
|
||||
// Not supported on all platforms or GL versions, I believe.
|
||||
if (!(enabledattribs & ATTRIBFLAG_POS))
|
||||
if (!attributes.isEnabled(ATTRIB_POS))
|
||||
throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
|
||||
|
||||
bool useindexbuffer = useIndexBuffer && ibo != nullptr && indexCount > 0;
|
||||
@@ -643,7 +663,7 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
if (count > 0)
|
||||
drawInternal(start, count, instancecount, useindexbuffer, enabledattribs, instancedattribs);
|
||||
drawInternal(start, count, instancecount, useindexbuffer, attributes, buffers);
|
||||
}
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -167,8 +167,6 @@ public:
|
||||
void setDrawRange();
|
||||
bool getDrawRange(int &start, int &count) const;
|
||||
|
||||
virtual int bindAttributeToShaderInput(int attributeindex, const std::string &inputname) = 0;
|
||||
|
||||
// Implements Drawable.
|
||||
void draw(Graphics *gfx, const Matrix4 &m) override;
|
||||
|
||||
@@ -178,6 +176,8 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
friend class SpriteBatch;
|
||||
|
||||
struct AttachedAttribute
|
||||
{
|
||||
Mesh *mesh;
|
||||
@@ -190,7 +190,7 @@ protected:
|
||||
void calculateAttributeSizes();
|
||||
size_t getAttributeOffset(size_t attribindex) const;
|
||||
|
||||
virtual void drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const = 0;
|
||||
virtual void drawInternal(int start, int count, int instancecount, bool useindexbuffer, const vertex::Attributes &attributes, const vertex::Buffers &buffers) const = 0;
|
||||
|
||||
std::vector<AttribFormat> vertexFormat;
|
||||
std::vector<size_t> attributeSizes;
|
||||
|
||||
@@ -93,6 +93,7 @@ ParticleSystem::ParticleSystem(Graphics *gfx, Texture *texture, uint32 size)
|
||||
, offset(float(texture->getWidth())*0.5f, float(texture->getHeight())*0.5f)
|
||||
, defaultOffset(true)
|
||||
, relativeRotation(false)
|
||||
, vertexAttributes(vertex::CommonFormat::XYf_STf_RGBAub, 0)
|
||||
, buffer(nullptr)
|
||||
, quadIndices(gfx, size)
|
||||
{
|
||||
@@ -154,6 +155,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
|
||||
, colors(p.colors)
|
||||
, quads(p.quads)
|
||||
, relativeRotation(p.relativeRotation)
|
||||
, vertexAttributes(p.vertexAttributes)
|
||||
, buffer(nullptr)
|
||||
, quadIndices(p.quadIndices)
|
||||
{
|
||||
@@ -1089,8 +1091,11 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
|
||||
|
||||
buffer->unmap();
|
||||
|
||||
vertex::Buffers vertexbuffers;
|
||||
vertexbuffers.set(0, buffer, 0);
|
||||
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
drawInternal();
|
||||
drawInternal(vertexAttributes, vertexbuffers);
|
||||
}
|
||||
|
||||
bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
|
||||
|
||||
@@ -584,7 +584,7 @@ protected:
|
||||
int quadIndex;
|
||||
};
|
||||
|
||||
virtual void drawInternal() const = 0;
|
||||
virtual void drawInternal(const vertex::Attributes &attributes, const vertex::Buffers &buffers) const = 0;
|
||||
|
||||
// Pointer to the beginning of the allocated memory.
|
||||
Particle *pMem;
|
||||
@@ -687,6 +687,7 @@ protected:
|
||||
|
||||
bool relativeRotation;
|
||||
|
||||
const vertex::Attributes vertexAttributes;
|
||||
Buffer *buffer;
|
||||
|
||||
// Vertex index buffer.
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
class Resource
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~Resource() {}
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
}; // Resource
|
||||
|
||||
} // graphics
|
||||
} // love
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "common/StringMap.h"
|
||||
#include "Texture.h"
|
||||
#include "ShaderStage.h"
|
||||
#include "Resource.h"
|
||||
|
||||
// STL
|
||||
#include <string>
|
||||
@@ -45,7 +46,7 @@ namespace graphics
|
||||
class Graphics;
|
||||
|
||||
// A GLSL shader
|
||||
class Shader : public Object
|
||||
class Shader : public Object, public Resource
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -185,8 +186,6 @@ public:
|
||||
void checkMainTextureType(TextureType textype, bool isDepthSampler) const;
|
||||
void checkMainTexture(Texture *texture) const;
|
||||
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
static bool validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err);
|
||||
|
||||
static bool initialize();
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "common/Object.h"
|
||||
#include "common/StringMap.h"
|
||||
#include "Volatile.h"
|
||||
#include "Resource.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
@@ -39,7 +40,7 @@ namespace graphics
|
||||
|
||||
class Graphics;
|
||||
|
||||
class ShaderStage : public love::Object, public Volatile
|
||||
class ShaderStage : public love::Object, public Volatile, public Resource
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -57,8 +58,6 @@ public:
|
||||
const std::string &getSource() const { return source; }
|
||||
const std::string &getWarnings() const { return warnings; }
|
||||
glslang::TShader *getGLSLangShader() const { return glslangShader; }
|
||||
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
static bool getConstant(const char *in, StageType &out);
|
||||
static bool getConstant(StageType in, const char *&out);
|
||||
|
||||
@@ -334,14 +334,55 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
// Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.)
|
||||
array_buf->unmap();
|
||||
|
||||
CommonFormat format = vertex_format;
|
||||
Attributes attributes;
|
||||
Buffers buffers;
|
||||
|
||||
if (!color_active)
|
||||
{
|
||||
if (format == CommonFormat::XYf_STPf_RGBAub)
|
||||
format = CommonFormat::XYf_STPf;
|
||||
else
|
||||
format = CommonFormat::XYf_STf;
|
||||
buffers.set(0, array_buf, 0);
|
||||
attributes.setCommonFormat(vertex_format, 0);
|
||||
|
||||
if (!color_active)
|
||||
attributes.disable(ATTRIB_COLOR);
|
||||
}
|
||||
|
||||
int activebuffers = 1;
|
||||
|
||||
for (const auto &it : attached_attributes)
|
||||
{
|
||||
Mesh *mesh = it.second.mesh.get();
|
||||
|
||||
// We have to do this check here as wll because setBufferSize can be
|
||||
// called after attachAttribute.
|
||||
if (mesh->getVertexCount() < (size_t) next * 4)
|
||||
throw love::Exception("Mesh with attribute '%s' attached to this SpriteBatch has too few vertices", it.first.c_str());
|
||||
|
||||
int attributeindex = -1;
|
||||
|
||||
// If the attribute is one of the LOVE-defined ones, use the constant
|
||||
// attribute index for it, otherwise query the index from the shader.
|
||||
VertexAttribID builtinattrib;
|
||||
if (vertex::getConstant(it.first.c_str(), builtinattrib))
|
||||
attributeindex = (int) builtinattrib;
|
||||
else if (Shader::current)
|
||||
attributeindex = Shader::current->getVertexAttributeIndex(it.first);
|
||||
|
||||
if (attributeindex >= 0)
|
||||
{
|
||||
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
|
||||
mesh->vbo->unmap();
|
||||
|
||||
const auto &formats = mesh->getVertexFormat();
|
||||
const auto &format = formats[it.second.index];
|
||||
|
||||
uint16 offset = (uint16) mesh->getAttributeOffset(it.second.index);
|
||||
uint16 stride = (uint16) mesh->getVertexStride();
|
||||
|
||||
attributes.set(attributeindex, format.type, format.components, offset, stride, activebuffers);
|
||||
|
||||
// TODO: Ideally we want to reuse buffers with the same stride+step.
|
||||
buffers.set(activebuffers, mesh->vbo, 0);
|
||||
activebuffers++;
|
||||
}
|
||||
}
|
||||
|
||||
int start = std::min(std::max(0, range_start), next - 1);
|
||||
@@ -358,7 +399,7 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
|
||||
Graphics::TempTransform transform(gfx, m);
|
||||
|
||||
if (count > 0)
|
||||
drawInternal(format, indexbytestart, indexcount);
|
||||
drawInternal(indexbytestart, indexcount, attributes, buffers);
|
||||
}
|
||||
|
||||
} // graphics
|
||||
|
||||
@@ -123,7 +123,7 @@ protected:
|
||||
**/
|
||||
void setBufferSize(int newsize);
|
||||
|
||||
virtual void drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount) = 0;
|
||||
virtual void drawInternal(size_t indexbytestart, size_t indexcount, const vertex::Attributes &attributes, const vertex::Buffers &buffers) = 0;
|
||||
|
||||
StrongRef<Texture> texture;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
// LOVE
|
||||
#include "common/int.h"
|
||||
#include "vertex.h"
|
||||
#include "Resource.h"
|
||||
|
||||
// C
|
||||
#include <cstddef>
|
||||
@@ -32,7 +33,7 @@ namespace love
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
class StreamBuffer
|
||||
class StreamBuffer : public Resource
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -61,8 +62,6 @@ public:
|
||||
|
||||
virtual void nextFrame() {}
|
||||
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
StreamBuffer(BufferType mode, size_t size);
|
||||
|
||||
@@ -32,6 +32,7 @@ love::Type Text::type("Text", &Drawable::type);
|
||||
|
||||
Text::Text(Graphics *gfx, Font *font, const std::vector<Font::ColoredString> &text)
|
||||
: font(font)
|
||||
, vertexAttributes(Font::vertexFormat, 0)
|
||||
, vbo(nullptr)
|
||||
, quadIndices(gfx, 20)
|
||||
, vert_offset(0)
|
||||
@@ -68,6 +69,8 @@ void Text::uploadVertices(const std::vector<Font::GlyphVertex> &vertices, size_t
|
||||
|
||||
delete vbo;
|
||||
vbo = new_vbo;
|
||||
|
||||
vertexBuffers.set(0, vbo, 0);
|
||||
}
|
||||
|
||||
if (vbo != nullptr && datasize > 0)
|
||||
|
||||
@@ -86,6 +86,10 @@ protected:
|
||||
virtual void drawInternal(const std::vector<Font::DrawCommand> &commands) const = 0;
|
||||
|
||||
StrongRef<Font> font;
|
||||
|
||||
vertex::Attributes vertexAttributes;
|
||||
vertex::Buffers vertexBuffers;
|
||||
|
||||
Buffer *vbo;
|
||||
QuadIndices quadIndices;
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "Quad.h"
|
||||
#include "vertex.h"
|
||||
#include "depthstencil.h"
|
||||
#include "Resource.h"
|
||||
|
||||
// C
|
||||
#include <stddef.h>
|
||||
@@ -56,7 +57,7 @@ enum TextureType
|
||||
* Base class for 2D textures. All textures can be drawn with Quads, have a
|
||||
* width and height, and have filter and wrap modes.
|
||||
**/
|
||||
class Texture : public Drawable
|
||||
class Texture : public Drawable, public Resource
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -145,8 +146,6 @@ public:
|
||||
|
||||
Quad *getQuad() const;
|
||||
|
||||
virtual ptrdiff_t getHandle() const = 0;
|
||||
|
||||
static bool validateFilter(const Filter &f, bool mipmapsAllowed);
|
||||
|
||||
static int getMipmapCount(int w, int h);
|
||||
|
||||
@@ -353,7 +353,9 @@ void Graphics::flushStreamDraws()
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Stream vertices flush and draw");
|
||||
|
||||
uint32 attribs = 0;
|
||||
Attributes attributes;
|
||||
Buffers buffers;
|
||||
|
||||
size_t usedsizes[3] = {0, 0, 0};
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
@@ -361,26 +363,20 @@ void Graphics::flushStreamDraws()
|
||||
if (sbstate.formats[i] == CommonFormat::NONE)
|
||||
continue;
|
||||
|
||||
attributes.setCommonFormat(sbstate.formats[i], (uint8) i);
|
||||
|
||||
usedsizes[i] = getFormatStride(sbstate.formats[i]) * sbstate.vertexCount;
|
||||
|
||||
love::graphics::StreamBuffer *buffer = sbstate.vb[i];
|
||||
|
||||
gl.bindBuffer(BUFFER_VERTEX, (GLuint) buffer->getHandle());
|
||||
size_t offset = buffer->unmap(usedsizes[i]);
|
||||
|
||||
size_t offset = sbstate.vb[i]->unmap(usedsizes[i]);
|
||||
buffers.set(i, sbstate.vb[i], offset);
|
||||
sbstate.vbMap[i] = StreamBuffer::MapInfo();
|
||||
|
||||
gl.setVertexPointers(sbstate.formats[i], offset);
|
||||
attribs |= getFormatFlags(sbstate.formats[i]);
|
||||
}
|
||||
|
||||
if (attribs == 0)
|
||||
if (attributes.enablebits == 0)
|
||||
return;
|
||||
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(sbstate.primitiveMode);
|
||||
|
||||
Colorf nc = gl.getConstantColor();
|
||||
if (attribs & ATTRIBFLAG_COLOR)
|
||||
if (attributes.isEnabled(ATTRIB_COLOR))
|
||||
gl.setConstantColor(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
|
||||
pushIdentityTransform();
|
||||
@@ -388,7 +384,9 @@ void Graphics::flushStreamDraws()
|
||||
gl.prepareDraw();
|
||||
gl.bindTextureToUnit(sbstate.texture, 0, false);
|
||||
|
||||
gl.useVertexAttribArrays(attribs);
|
||||
gl.setVertexAttributes(attributes, buffers);
|
||||
|
||||
GLenum glprimitivetype = OpenGL::getGLPrimitiveType(sbstate.primitiveMode);
|
||||
|
||||
if (sbstate.indexCount > 0)
|
||||
{
|
||||
@@ -415,7 +413,7 @@ void Graphics::flushStreamDraws()
|
||||
|
||||
popTransform();
|
||||
|
||||
if (attribs & ATTRIB_CONSTANTCOLOR)
|
||||
if (attributes.isEnabled(ATTRIB_COLOR))
|
||||
gl.setConstantColor(nc);
|
||||
|
||||
streamBufferState.vertexCount = 0;
|
||||
|
||||
@@ -49,44 +49,11 @@ Mesh::~Mesh()
|
||||
{
|
||||
}
|
||||
|
||||
int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inputname)
|
||||
{
|
||||
const AttribFormat &format = vertexFormat[attributeindex];
|
||||
|
||||
GLint attriblocation = -1;
|
||||
|
||||
// If the attribute is one of the LOVE-defined ones, use the constant
|
||||
// attribute index for it, otherwise query the index from the shader.
|
||||
VertexAttribID builtinattrib;
|
||||
if (vertex::getConstant(inputname.c_str(), builtinattrib))
|
||||
attriblocation = (GLint) builtinattrib;
|
||||
else if (Shader::current)
|
||||
attriblocation = Shader::current->getVertexAttributeIndex(inputname);
|
||||
|
||||
// The active shader might not use this vertex attribute name.
|
||||
if (attriblocation < 0)
|
||||
return attriblocation;
|
||||
|
||||
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
|
||||
vbo->unmap();
|
||||
|
||||
gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle());
|
||||
|
||||
GLboolean normalized = GL_FALSE;
|
||||
GLenum datatype = OpenGL::getGLVertexDataType(format.type, normalized);
|
||||
|
||||
const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex));
|
||||
|
||||
glVertexAttribPointer(attriblocation, format.components, datatype, normalized, (GLsizei) vertexStride, gloffset);
|
||||
|
||||
return attriblocation;
|
||||
}
|
||||
|
||||
void Mesh::drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const
|
||||
void Mesh::drawInternal(int start, int count, int instancecount, bool useindexbuffer, const vertex::Attributes &attributes, const vertex::Buffers &buffers) const
|
||||
{
|
||||
OpenGL::TempDebugGroup debuggroup("Mesh draw");
|
||||
|
||||
gl.useVertexAttribArrays(attribflags, instancedattribflags);
|
||||
gl.setVertexAttributes(attributes, buffers);
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
gl.prepareDraw();
|
||||
|
||||
|
||||
@@ -37,14 +37,11 @@ public:
|
||||
|
||||
Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage);
|
||||
Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage);
|
||||
|
||||
virtual ~Mesh();
|
||||
|
||||
int bindAttributeToShaderInput(int attributeindex, const std::string &inputname) override;
|
||||
|
||||
protected:
|
||||
|
||||
void drawInternal(int start, int count, int instancecount, bool useindexbuffer, uint32 attribflags, uint32 instancedattribflags) const override;
|
||||
void drawInternal(int start, int count, int instancecount, bool useindexbuffer, const vertex::Attributes &attributes, const vertex::Buffers &buffers) const override;
|
||||
|
||||
}; // Mesh
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ void OpenGL::setupContext()
|
||||
else
|
||||
state.instancedAttribArrays = 0;
|
||||
|
||||
useVertexAttribArrays(0, 0);
|
||||
setVertexAttributes(vertex::Attributes(), vertex::Buffers());
|
||||
|
||||
// Get the current viewport.
|
||||
glGetIntegerv(GL_VIEWPORT, (GLint *) &state.viewport.x);
|
||||
@@ -647,111 +647,52 @@ void OpenGL::drawElements(GLenum mode, GLsizei count, GLenum type, const void *i
|
||||
++stats.drawCalls;
|
||||
}
|
||||
|
||||
void OpenGL::useVertexAttribArrays(uint32 arraybits, uint32 instancedbits)
|
||||
void OpenGL::setVertexAttributes(const vertex::Attributes &attributes, const vertex::Buffers &buffers)
|
||||
{
|
||||
uint32 diff = arraybits ^ state.enabledAttribArrays;
|
||||
uint32 instancediff = instancedbits ^ state.instancedAttribArrays;
|
||||
uint32 enablediff = attributes.enablebits ^ state.enabledAttribArrays;
|
||||
uint32 instancediff = attributes.instancebits ^ state.instancedAttribArrays;
|
||||
|
||||
if (diff == 0 && instancediff == 0)
|
||||
return;
|
||||
|
||||
// Max 32 attributes. As of when this was written, no GL driver exposes more
|
||||
// than 32. Lets hope that doesn't change...
|
||||
for (uint32 i = 0; i < 32; i++)
|
||||
for (uint32 i = 0; i < vertex::Attributes::MAX; i++)
|
||||
{
|
||||
uint32 bit = 1u << i;
|
||||
|
||||
if (diff & bit)
|
||||
if (enablediff & bit)
|
||||
{
|
||||
if (arraybits & bit)
|
||||
if (attributes.enablebits & bit)
|
||||
glEnableVertexAttribArray(i);
|
||||
else
|
||||
glDisableVertexAttribArray(i);
|
||||
}
|
||||
|
||||
if (instancediff & bit)
|
||||
glVertexAttribDivisor(i, (instancedbits & bit) != 0 ? 1 : 0);
|
||||
glVertexAttribDivisor(i, (attributes.instancebits & bit) != 0 ? 1 : 0);
|
||||
|
||||
if (attributes.enablebits & bit)
|
||||
{
|
||||
const auto &attrib = attributes.attribs[i];
|
||||
const auto &bufferinfo = buffers.info[attrib.bufferindex];
|
||||
|
||||
GLboolean normalized = GL_FALSE;
|
||||
GLenum gltype = getGLVertexDataType(attrib.type, normalized);
|
||||
|
||||
const void *offsetpointer = BUFFER_OFFSET(bufferinfo.offset + attrib.offsetfromvertex);
|
||||
|
||||
bindBuffer(BUFFER_VERTEX, (GLuint) bufferinfo.buffer->getHandle());
|
||||
glVertexAttribPointer(i, attrib.components, gltype, normalized, attrib.stride, offsetpointer);
|
||||
}
|
||||
}
|
||||
|
||||
state.enabledAttribArrays = arraybits;
|
||||
state.instancedAttribArrays = instancedbits;
|
||||
state.enabledAttribArrays = attributes.enablebits;
|
||||
state.instancedAttribArrays = attributes.instancebits;
|
||||
|
||||
// glDisableVertexAttribArray will make the constant value for a vertex
|
||||
// attribute undefined. We rely on the per-vertex color attribute being
|
||||
// white when no per-vertex color is used, so we set it here.
|
||||
// FIXME: Is there a better place to do this?
|
||||
if ((diff & ATTRIBFLAG_COLOR) && !(arraybits & ATTRIBFLAG_COLOR))
|
||||
if ((enablediff & ATTRIBFLAG_COLOR) && !(attributes.enablebits & ATTRIBFLAG_COLOR))
|
||||
glVertexAttrib4f(ATTRIB_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGL::setVertexPointers(vertex::CommonFormat format, size_t stride, size_t offset)
|
||||
{
|
||||
using namespace vertex;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case CommonFormat::NONE:
|
||||
break;
|
||||
case CommonFormat::XYf:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset));
|
||||
break;
|
||||
case CommonFormat::XYZf:
|
||||
glVertexAttribPointer(ATTRIB_POS, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset));
|
||||
break;
|
||||
case CommonFormat::RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset));
|
||||
break;
|
||||
case CommonFormat::STf_RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(STf_RGBAub, s)));
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(STf_RGBAub, color.r)));
|
||||
break;
|
||||
case CommonFormat::STPf_RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(STPf_RGBAub, s)));
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(STPf_RGBAub, color.r)));
|
||||
break;
|
||||
case CommonFormat::XYf_STf:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf, x)));
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf, s)));
|
||||
break;
|
||||
case CommonFormat::XYf_STPf:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf, x)));
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf, s)));
|
||||
break;
|
||||
case CommonFormat::XYf_STf_RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, x)));
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, s)));
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STf_RGBAub, color.r)));
|
||||
break;
|
||||
case CommonFormat::XYf_STus_RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, x)));
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 2, GL_UNSIGNED_SHORT, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, s)));
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STus_RGBAub, color.r)));
|
||||
break;
|
||||
case CommonFormat::XYf_STPf_RGBAub:
|
||||
glVertexAttribPointer(ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, x)));
|
||||
glVertexAttribPointer(ATTRIB_TEXCOORD, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, s)));
|
||||
glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, BUFFER_OFFSET(offset + offsetof(XYf_STPf_RGBAub, color.r)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::setVertexPointers(vertex::CommonFormat format, size_t offset)
|
||||
{
|
||||
setVertexPointers(format, getFormatStride(format), offset);
|
||||
}
|
||||
|
||||
void OpenGL::setVertexPointers(vertex::CommonFormat format, love::graphics::Buffer *buffer, size_t offset)
|
||||
{
|
||||
bindBuffer(BUFFER_VERTEX, (GLuint) buffer->getHandle());
|
||||
setVertexPointers(format, offset);
|
||||
}
|
||||
|
||||
void OpenGL::setVertexPointers(vertex::CommonFormat format, love::graphics::Buffer *buffer, size_t stride, size_t offset)
|
||||
{
|
||||
bindBuffer(BUFFER_VERTEX, (GLuint) buffer->getHandle());
|
||||
setVertexPointers(format, stride, offset);
|
||||
}
|
||||
|
||||
void OpenGL::clearDepth(double value)
|
||||
{
|
||||
if (GLAD_ES_VERSION_2_0)
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace love
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
class Resource;
|
||||
class Buffer;
|
||||
|
||||
namespace opengl
|
||||
@@ -206,23 +207,7 @@ public:
|
||||
void drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instancecount = 1);
|
||||
void drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instancecount = 1);
|
||||
|
||||
/**
|
||||
* Sets the enabled vertex attribute arrays based on the specified attribute
|
||||
* bits. Each bit in the uint32 represents an enabled attribute array index.
|
||||
* For example, useVertexAttribArrays(1 << 0) will enable attribute index 0.
|
||||
* See the VertexAttribFlags enum for the standard vertex attributes.
|
||||
* This function *must* be used instead of glEnable/DisableVertexAttribArray.
|
||||
**/
|
||||
void useVertexAttribArrays(uint32 arraybits, uint32 instancedbits = 0);
|
||||
|
||||
/**
|
||||
* Calls glVertexAttribPointer appropriately for each attribute used in the
|
||||
* specified format.
|
||||
**/
|
||||
void setVertexPointers(vertex::CommonFormat format, size_t offset);
|
||||
void setVertexPointers(vertex::CommonFormat format, size_t stride, size_t offset);
|
||||
void setVertexPointers(vertex::CommonFormat format, love::graphics::Buffer *buffer, size_t offset);
|
||||
void setVertexPointers(vertex::CommonFormat format, love::graphics::Buffer *buffer, size_t stride, size_t offset);
|
||||
void setVertexAttributes(const vertex::Attributes &attributes, const vertex::Buffers &buffers);
|
||||
|
||||
/**
|
||||
* Wrapper for glClearDepth and glClearDepthf.
|
||||
|
||||
@@ -50,17 +50,14 @@ ParticleSystem *ParticleSystem::clone()
|
||||
return new ParticleSystem(*this);
|
||||
}
|
||||
|
||||
void ParticleSystem::drawInternal() const
|
||||
void ParticleSystem::drawInternal(const vertex::Attributes &attributes, const vertex::Buffers &buffers) const
|
||||
{
|
||||
using namespace vertex;
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("ParticleSystem draw");
|
||||
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
gl.prepareDraw();
|
||||
|
||||
gl.useVertexAttribArrays(getFormatFlags(CommonFormat::XYf_STf_RGBAub));
|
||||
gl.setVertexPointers(CommonFormat::XYf_STf_RGBAub, buffer, 0);
|
||||
gl.setVertexAttributes(attributes, buffers);
|
||||
|
||||
GLsizei count = (GLsizei) quadIndices.getIndexCount(getCount());
|
||||
GLenum gltype = OpenGL::getGLIndexDataType(quadIndices.getType());
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
void drawInternal() const override;
|
||||
void drawInternal(const vertex::Attributes &attributes, const vertex::Buffers &buffers) const override;
|
||||
|
||||
}; // ParticleSystem
|
||||
|
||||
|
||||
@@ -51,32 +51,11 @@ SpriteBatch::~SpriteBatch()
|
||||
{
|
||||
}
|
||||
|
||||
void SpriteBatch::drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount)
|
||||
void SpriteBatch::drawInternal(size_t indexbytestart, size_t indexcount, const vertex::Attributes &attributes, const vertex::Buffers &buffers)
|
||||
{
|
||||
OpenGL::TempDebugGroup debuggroup("SpriteBatch draw");
|
||||
|
||||
uint32 enabledattribs = getFormatFlags(format);
|
||||
|
||||
// We want attached attributes to override local attributes, so we should
|
||||
// call this before binding attached attributes.
|
||||
gl.setVertexPointers(format, array_buf, vertex_stride, 0);
|
||||
|
||||
for (const auto &it : attached_attributes)
|
||||
{
|
||||
Mesh *mesh = it.second.mesh.get();
|
||||
|
||||
// We have to do this check here as wll because setBufferSize can be
|
||||
// called after attachAttribute.
|
||||
if (mesh->getVertexCount() < (size_t) next * 4)
|
||||
throw love::Exception("Mesh with attribute '%s' attached to this SpriteBatch has too few vertices", it.first.c_str());
|
||||
|
||||
int location = mesh->bindAttributeToShaderInput(it.second.index, it.first);
|
||||
|
||||
if (location >= 0)
|
||||
enabledattribs |= 1u << (uint32) location;
|
||||
}
|
||||
|
||||
gl.useVertexAttribArrays(enabledattribs);
|
||||
gl.setVertexAttributes(attributes, buffers);
|
||||
gl.bindTextureToUnit(texture, 0, false);
|
||||
|
||||
gl.prepareDraw();
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
|
||||
protected:
|
||||
|
||||
void drawInternal(vertex::CommonFormat format, size_t indexbytestart, size_t indexcount) override;
|
||||
void drawInternal(size_t indexbytestart, size_t indexcount, const vertex::Attributes &attributes, const vertex::Buffers &buffers) override;
|
||||
|
||||
}; // SpriteBatch
|
||||
|
||||
|
||||
@@ -45,9 +45,7 @@ void Text::drawInternal(const std::vector<Font::DrawCommand> &commands) const
|
||||
OpenGL::TempDebugGroup debuggroup("Text object draw");
|
||||
|
||||
gl.prepareDraw();
|
||||
|
||||
gl.setVertexPointers(Font::vertexFormat, vbo, 0);
|
||||
gl.useVertexAttribArrays(vertex::getFormatFlags(Font::vertexFormat));
|
||||
gl.setVertexAttributes(vertexAttributes, vertexBuffers);
|
||||
|
||||
const GLenum gltype = OpenGL::getGLIndexDataType(quadIndices.getType());
|
||||
const size_t elemsize = quadIndices.getElementSize();
|
||||
|
||||
@@ -37,6 +37,8 @@ static_assert(sizeof(XYf_STf_RGBAub) == sizeof(float)*2 + sizeof(float)*2 + size
|
||||
static_assert(sizeof(XYf_STus_RGBAub) == sizeof(float)*2 + sizeof(uint16)*2 + sizeof(Color), "sizeof(XYf_STus_RGBAub) incorrect!");
|
||||
static_assert(sizeof(XYf_STPf_RGBAub) == sizeof(float)*2 + sizeof(float)*3 + sizeof(Color), "sizeof(XYf_STPf_RGBAub) incorrect!");
|
||||
|
||||
static_assert(sizeof(AttributeInfo) == sizeof(uint64), "sizeof(AttributeInfo) incorrect!");
|
||||
|
||||
size_t getFormatStride(CommonFormat format)
|
||||
{
|
||||
switch (format)
|
||||
@@ -222,6 +224,57 @@ void fillIndices(TriangleIndexMode mode, uint32 vertexStart, uint32 vertexCount,
|
||||
fillIndicesT(mode, vertexStart, vertexCount, indices);
|
||||
}
|
||||
|
||||
void Attributes::setCommonFormat(CommonFormat format, uint8 bufferindex)
|
||||
{
|
||||
uint16 stride = (uint16) getFormatStride(format);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case CommonFormat::NONE:
|
||||
break;
|
||||
case CommonFormat::XYf:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYZf:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 3, 0, stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::RGBAub:
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, 0, stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::STf_RGBAub:
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::STPf_RGBAub:
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, 0, stride, bufferindex);
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 3), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYf_STf:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYf_STPf:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYf_STf_RGBAub:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 2, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 4), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYf_STus_RGBAub:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_TEXCOORD, DATA_UNORM16, 2, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 2 + sizeof(uint16) * 2), stride, bufferindex);
|
||||
break;
|
||||
case CommonFormat::XYf_STPf_RGBAub:
|
||||
set(ATTRIB_POS, DATA_FLOAT, 2, 0, stride, bufferindex);
|
||||
set(ATTRIB_TEXCOORD, DATA_FLOAT, 3, uint16(sizeof(float) * 2), stride, bufferindex);
|
||||
set(ATTRIB_COLOR, DATA_UNORM8, 4, uint16(sizeof(float) * 5), stride, bufferindex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static StringMap<VertexAttribID, ATTRIB_MAX_ENUM>::Entry attribNameEntries[] =
|
||||
{
|
||||
{ "VertexPosition", ATTRIB_POS },
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace love
|
||||
namespace graphics
|
||||
{
|
||||
|
||||
class Resource;
|
||||
|
||||
// Vertex attribute indices used in shaders by LOVE. The values map to OpenGL
|
||||
// generic vertex attribute indices.
|
||||
enum VertexAttribID
|
||||
@@ -172,6 +174,119 @@ struct XYf_STPf_RGBAub
|
||||
Color color;
|
||||
};
|
||||
|
||||
struct Buffers
|
||||
{
|
||||
static const unsigned int MAX = 32;
|
||||
|
||||
uint32 usebits = 0;
|
||||
|
||||
struct
|
||||
{
|
||||
Resource *buffer;
|
||||
size_t offset;
|
||||
} info[MAX];
|
||||
|
||||
void set(unsigned int index, Resource *r, size_t offset)
|
||||
{
|
||||
usebits |= (1u << index);
|
||||
info[index] = {r, offset};
|
||||
}
|
||||
|
||||
void disable(unsigned int index) { usebits &= (1u << index); }
|
||||
void clear() { usebits = 0; }
|
||||
};
|
||||
|
||||
struct AttributeInfo
|
||||
{
|
||||
uint8 bufferindex;
|
||||
DataType type : 8;
|
||||
uint16 components;
|
||||
uint16 offsetfromvertex;
|
||||
uint16 stride;
|
||||
};
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
static const unsigned int MAX = 32;
|
||||
|
||||
uint32 enablebits = 0;
|
||||
uint32 instancebits = 0;
|
||||
|
||||
union
|
||||
{
|
||||
AttributeInfo attribs[MAX];
|
||||
uint64 data[MAX];
|
||||
};
|
||||
|
||||
Attributes() {}
|
||||
Attributes(CommonFormat format, uint8 bufferindex)
|
||||
{
|
||||
setCommonFormat(format, bufferindex);
|
||||
}
|
||||
|
||||
void set(unsigned int index, DataType type, uint16 components, uint16 offsetfromvertex, uint16 stride, uint8 bufferindex, AttributeStep step = STEP_PER_VERTEX)
|
||||
{
|
||||
uint32 bit = (1u << index);
|
||||
|
||||
enablebits |= bit;
|
||||
|
||||
if (step == STEP_PER_INSTANCE)
|
||||
instancebits |= bit;
|
||||
else
|
||||
instancebits &= ~bit;
|
||||
|
||||
attribs[index].bufferindex = bufferindex;
|
||||
attribs[index].type = type;
|
||||
attribs[index].components = components;
|
||||
attribs[index].offsetfromvertex = offsetfromvertex;
|
||||
attribs[index].stride = stride;
|
||||
}
|
||||
|
||||
void disable(unsigned int index)
|
||||
{
|
||||
enablebits &= ~(1u << index);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
enablebits = 0;
|
||||
}
|
||||
|
||||
bool isEnabled(unsigned int index) const
|
||||
{
|
||||
return (enablebits & (1u << index)) != 0;
|
||||
}
|
||||
|
||||
AttributeStep getStep(unsigned int index) const
|
||||
{
|
||||
return (instancebits & (1u << index)) != 0 ? STEP_PER_INSTANCE : STEP_PER_VERTEX;
|
||||
}
|
||||
|
||||
void setCommonFormat(CommonFormat format, uint8 bufferindex);
|
||||
|
||||
bool operator == (const Attributes &other) const
|
||||
{
|
||||
if (enablebits != other.enablebits)
|
||||
return false;
|
||||
|
||||
uint32 instancediff = instancebits ^ other.instancebits;
|
||||
|
||||
for (unsigned int i = 0; i < MAX; i++)
|
||||
{
|
||||
if (isEnabled(i))
|
||||
{
|
||||
if (instancediff & (1u << i))
|
||||
return false;
|
||||
|
||||
if (data[i] != other.data[i])
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
size_t getFormatStride(CommonFormat format);
|
||||
|
||||
uint32 getFormatFlags(CommonFormat format);
|
||||
|
||||
Reference in New Issue
Block a user