Browse Source

Cleaned up some vertex data-related code.

--HG--
branch : minor
Alex Szpakowski 7 years ago
parent
commit
7a2e52b12d

+ 16 - 6
src/modules/graphics/Graphics.cpp

@@ -217,11 +217,6 @@ ShaderStage *Graphics::newShaderStage(ShaderStage::StageType stage, const std::s
 	return s;
 	return s;
 }
 }
 
 
-void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &hashkey)
-{
-	cachedShaderStages[type].erase(hashkey);
-}
-
 Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel)
 Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel)
 {
 {
 	if (vertex.empty() && pixel.empty())
 	if (vertex.empty() && pixel.empty())
@@ -233,6 +228,21 @@ Shader *Graphics::newShader(const std::string &vertex, const std::string &pixel)
 	return newShaderInternal(vertexstage.get(), pixelstage.get());
 	return newShaderInternal(vertexstage.get(), pixelstage.get());
 }
 }
 
 
+Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, PrimitiveType drawmode, vertex::Usage usage)
+{
+	return newMesh(Mesh::getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage);
+}
+
+Mesh *Graphics::newMesh(int vertexcount, PrimitiveType drawmode, vertex::Usage usage)
+{
+	return newMesh(Mesh::getDefaultVertexFormat(), vertexcount, drawmode, usage);
+}
+
+void Graphics::cleanupCachedShaderStage(ShaderStage::StageType type, const std::string &hashkey)
+{
+	cachedShaderStages[type].erase(hashkey);
+}
+
 bool Graphics::validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err)
 bool Graphics::validateShader(bool gles, const std::string &vertex, const std::string &pixel, std::string &err)
 {
 {
 	if (vertex.empty() && pixel.empty())
 	if (vertex.empty() && pixel.empty())
@@ -1040,7 +1050,7 @@ void Graphics::points(const Vector2 *positions, const Colorf *colors, size_t num
 	bool is2D = t.isAffine2DTransform();
 	bool is2D = t.isAffine2DTransform();
 
 
 	StreamDrawCommand cmd;
 	StreamDrawCommand cmd;
-	cmd.primitiveMode = vertex::PrimitiveMode::POINTS;
+	cmd.primitiveMode = PRIMITIVE_POINTS;
 	cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
 	cmd.formats[0] = vertex::getSinglePositionFormat(is2D);
 	cmd.formats[1] = vertex::CommonFormat::RGBAub;
 	cmd.formats[1] = vertex::CommonFormat::RGBAub;
 	cmd.vertexCount = (int) numpoints;
 	cmd.vertexCount = (int) numpoints;

+ 6 - 6
src/modules/graphics/Graphics.h

@@ -252,7 +252,7 @@ public:
 
 
 	struct StreamDrawCommand
 	struct StreamDrawCommand
 	{
 	{
-		vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES;
+		PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
 		vertex::CommonFormat formats[2];
 		vertex::CommonFormat formats[2];
 		vertex::TriangleIndexMode indexMode = vertex::TriangleIndexMode::NONE;
 		vertex::TriangleIndexMode indexMode = vertex::TriangleIndexMode::NONE;
 		int vertexCount = 0;
 		int vertexCount = 0;
@@ -391,11 +391,11 @@ public:
 
 
 	virtual Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) = 0;
 	virtual Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) = 0;
 
 
-	virtual Mesh *newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage) = 0;
-	virtual Mesh *newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) = 0;
+	Mesh *newMesh(const std::vector<Vertex> &vertices, PrimitiveType drawmode, vertex::Usage usage);
+	Mesh *newMesh(int vertexcount, PrimitiveType drawmode, vertex::Usage usage);
 
 
-	virtual Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage) = 0;
-	virtual Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, Mesh::DrawMode drawmode, vertex::Usage usage) = 0;
+	virtual Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) = 0;
+	virtual Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) = 0;
 
 
 	virtual Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {}) = 0;
 	virtual Text *newText(Font *font, const std::vector<Font::ColoredString> &text = {}) = 0;
 
 
@@ -861,7 +861,7 @@ protected:
 		StreamBuffer *vb[2];
 		StreamBuffer *vb[2];
 		StreamBuffer *indexBuffer = nullptr;
 		StreamBuffer *indexBuffer = nullptr;
 
 
-		vertex::PrimitiveMode primitiveMode = vertex::PrimitiveMode::TRIANGLES;
+		PrimitiveType primitiveMode = PRIMITIVE_TRIANGLES;
 		vertex::CommonFormat formats[2];
 		vertex::CommonFormat formats[2];
 		StrongRef<Texture> texture;
 		StrongRef<Texture> texture;
 		Shader::StandardShader standardShaderType = Shader::STANDARD_DEFAULT;
 		Shader::StandardShader standardShaderType = Shader::STANDARD_DEFAULT;

+ 41 - 125
src/modules/graphics/Mesh.cpp

@@ -49,9 +49,9 @@ std::vector<Mesh::AttribFormat> Mesh::getDefaultVertexFormat()
 {
 {
 	// Corresponds to the love::Vertex struct.
 	// Corresponds to the love::Vertex struct.
 	std::vector<Mesh::AttribFormat> vertexformat = {
 	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},
+		{ getBuiltinAttribName(ATTRIB_POS),      vertex::DATA_FLOAT,  2 },
+		{ getBuiltinAttribName(ATTRIB_TEXCOORD), vertex::DATA_FLOAT,  2 },
+		{ getBuiltinAttribName(ATTRIB_COLOR),    vertex::DATA_UNORM8, 4 },
 	};
 	};
 
 
 	return vertexformat;
 	return vertexformat;
@@ -59,16 +59,16 @@ std::vector<Mesh::AttribFormat> Mesh::getDefaultVertexFormat()
 
 
 love::Type Mesh::type("Mesh", &Drawable::type);
 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)
+Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage)
 	: vertexFormat(vertexformat)
 	: vertexFormat(vertexformat)
 	, vbo(nullptr)
 	, vbo(nullptr)
 	, vertexCount(0)
 	, vertexCount(0)
 	, vertexStride(0)
 	, vertexStride(0)
 	, ibo(nullptr)
 	, ibo(nullptr)
 	, useIndexBuffer(false)
 	, useIndexBuffer(false)
-	, elementCount(0)
-	, elementDataType(INDEX_UINT16)
-	, drawMode(drawmode)
+	, indexCount(0)
+	, indexDataType(INDEX_UINT16)
+	, primitiveType(drawmode)
 	, rangeStart(-1)
 	, rangeStart(-1)
 	, rangeCount(-1)
 	, rangeCount(-1)
 {
 {
@@ -76,7 +76,7 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexforma
 	calculateAttributeSizes();
 	calculateAttributeSizes();
 
 
 	vertexCount = datasize / vertexStride;
 	vertexCount = datasize / vertexStride;
-	elementDataType = vertex::getIndexDataTypeFromMax(vertexCount);
+	indexDataType = vertex::getIndexDataTypeFromMax(vertexCount);
 
 
 	if (vertexCount == 0)
 	if (vertexCount == 0)
 		throw love::Exception("Data size is too small for specified vertex attribute formats.");
 		throw love::Exception("Data size is too small for specified vertex attribute formats.");
@@ -86,16 +86,16 @@ Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexforma
 	vertexScratchBuffer = new char[vertexStride];
 	vertexScratchBuffer = new char[vertexStride];
 }
 }
 
 
-Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage)
+Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage)
 	: vertexFormat(vertexformat)
 	: vertexFormat(vertexformat)
 	, vbo(nullptr)
 	, vbo(nullptr)
 	, vertexCount((size_t) vertexcount)
 	, vertexCount((size_t) vertexcount)
 	, vertexStride(0)
 	, vertexStride(0)
 	, ibo(nullptr)
 	, ibo(nullptr)
 	, useIndexBuffer(false)
 	, useIndexBuffer(false)
-	, elementCount(0)
-	, elementDataType(vertex::getIndexDataTypeFromMax(vertexcount))
-	, drawMode(drawmode)
+	, indexCount(0)
+	, indexDataType(vertex::getIndexDataTypeFromMax(vertexcount))
+	, primitiveType(drawmode)
 	, rangeStart(-1)
 	, rangeStart(-1)
 	, rangeCount(-1)
 	, rangeCount(-1)
 {
 {
@@ -149,16 +149,18 @@ void Mesh::calculateAttributeSizes()
 
 
 	for (const AttribFormat &format : vertexFormat)
 	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.");
+		size_t size = vertex::getDataTypeSize(format.type) * format.components;
 
 
 		if (format.components <= 0 || format.components > 4)
 		if (format.components <= 0 || format.components > 4)
 			throw love::Exception("Vertex attributes must have between 1 and 4 components.");
 			throw love::Exception("Vertex attributes must have between 1 and 4 components.");
 
 
+		// Hardware really doesn't like attributes that aren't 32 bit-aligned.
+		if (size % 4 != 0)
+			throw love::Exception("Vertex attributes must have enough components to be a multiple of 32 bits.");
+
 		// Total size in bytes of each attribute in a single vertex.
 		// Total size in bytes of each attribute in a single vertex.
-		attributeSizes.push_back(getAttribFormatSize(format));
-		stride += attributeSizes.back();
+		attributeSizes.push_back(size);
+		stride += size;
 	}
 	}
 
 
 	vertexStride = stride;
 	vertexStride = stride;
@@ -258,15 +260,13 @@ const std::vector<Mesh::AttribFormat> &Mesh::getVertexFormat() const
 	return vertexFormat;
 	return vertexFormat;
 }
 }
 
 
-Mesh::DataType Mesh::getAttributeInfo(int attribindex, int &components) const
+vertex::DataType Mesh::getAttributeInfo(int attribindex, int &components) const
 {
 {
 	if (attribindex < 0 || attribindex >= (int) vertexFormat.size())
 	if (attribindex < 0 || attribindex >= (int) vertexFormat.size())
 		throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
 		throw love::Exception("Invalid vertex attribute index: %d", attribindex + 1);
 
 
-	DataType type = vertexFormat[attribindex].type;
 	components = vertexFormat[attribindex].components;
 	components = vertexFormat[attribindex].components;
-
-	return type;
+	return vertexFormat[attribindex].type;
 }
 }
 
 
 int Mesh::getAttributeIndex(const std::string &name) const
 int Mesh::getAttributeIndex(const std::string &name) const
@@ -417,9 +417,9 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
 	}
 	}
 
 
 	useIndexBuffer = true;
 	useIndexBuffer = true;
-	elementCount = map.size();
+	indexCount = map.size();
 
 
-	if (!ibo || elementCount == 0)
+	if (!ibo || indexCount == 0)
 		return;
 		return;
 
 
 	Buffer::Mapper ibomap(*ibo);
 	Buffer::Mapper ibomap(*ibo);
@@ -436,7 +436,7 @@ void Mesh::setVertexMap(const std::vector<uint32> &map)
 		break;
 		break;
 	}
 	}
 
 
-	elementDataType = datatype;
+	indexDataType = datatype;
 }
 }
 
 
 void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize)
 void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasize)
@@ -453,16 +453,16 @@ void Mesh::setVertexMap(IndexDataType datatype, const void *data, size_t datasiz
 		ibo = gfx->newBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ);
 		ibo = gfx->newBuffer(datasize, nullptr, BUFFER_INDEX, vbo->getUsage(), Buffer::MAP_READ);
 	}
 	}
 
 
-	elementCount = datasize / vertex::getIndexDataSize(datatype);
+	indexCount = datasize / vertex::getIndexDataSize(datatype);
 
 
-	if (!ibo || elementCount == 0)
+	if (!ibo || indexCount == 0)
 		return;
 		return;
 
 
 	Buffer::Mapper ibomap(*ibo);
 	Buffer::Mapper ibomap(*ibo);
 	memcpy(ibomap.get(), data, datasize);
 	memcpy(ibomap.get(), data, datasize);
 
 
 	useIndexBuffer = true;
 	useIndexBuffer = true;
-	elementDataType = datatype;
+	indexDataType = datatype;
 }
 }
 
 
 void Mesh::setVertexMap()
 void Mesh::setVertexMap()
@@ -487,23 +487,23 @@ bool Mesh::getVertexMap(std::vector<uint32> &map) const
 		return false;
 		return false;
 
 
 	map.clear();
 	map.clear();
-	map.reserve(elementCount);
+	map.reserve(indexCount);
 
 
-	if (!ibo || elementCount == 0)
+	if (!ibo || indexCount == 0)
 		return true;
 		return true;
 
 
 	// We unmap the buffer in Mesh::draw, Mesh::setVertexMap, and Mesh::flush.
 	// We unmap the buffer in Mesh::draw, Mesh::setVertexMap, and Mesh::flush.
 	void *buffer = ibo->map();
 	void *buffer = ibo->map();
 
 
 	// Fill the vector from the buffer.
 	// Fill the vector from the buffer.
-	switch (elementDataType)
+	switch (indexDataType)
 	{
 	{
 	case INDEX_UINT16:
 	case INDEX_UINT16:
-		copyFromIndexBuffer<uint16>(buffer, elementCount, map);
+		copyFromIndexBuffer<uint16>(buffer, indexCount, map);
 		break;
 		break;
 	case INDEX_UINT32:
 	case INDEX_UINT32:
 	default:
 	default:
-		copyFromIndexBuffer<uint32>(buffer, elementCount, map);
+		copyFromIndexBuffer<uint32>(buffer, indexCount, map);
 		break;
 		break;
 	}
 	}
 
 
@@ -512,7 +512,7 @@ bool Mesh::getVertexMap(std::vector<uint32> &map) const
 
 
 size_t Mesh::getVertexMapCount() const
 size_t Mesh::getVertexMapCount() const
 {
 {
-	return elementCount;
+	return indexCount;
 }
 }
 
 
 void Mesh::setTexture(Texture *tex)
 void Mesh::setTexture(Texture *tex)
@@ -530,14 +530,14 @@ Texture *Mesh::getTexture() const
 	return texture.get();
 	return texture.get();
 }
 }
 
 
-void Mesh::setDrawMode(DrawMode mode)
+void Mesh::setDrawMode(PrimitiveType mode)
 {
 {
-	drawMode = mode;
+	primitiveType = mode;
 }
 }
 
 
-Mesh::DrawMode Mesh::getDrawMode() const
+PrimitiveType Mesh::getDrawMode() const
 {
 {
-	return drawMode;
+	return primitiveType;
 }
 }
 
 
 void Mesh::setDrawRange(int start, int count)
 void Mesh::setDrawRange(int start, int count)
@@ -611,7 +611,7 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
 	if (!(enabledattribs & ATTRIBFLAG_POS))
 	if (!(enabledattribs & ATTRIBFLAG_POS))
 		throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
 		throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn.");
 
 
-	bool useindexbuffer = useIndexBuffer && ibo != nullptr && elementCount > 0;
+	bool useindexbuffer = useIndexBuffer && ibo != nullptr && indexCount > 0;
 
 
 	int start = 0;
 	int start = 0;
 	int count = 0;
 	int count = 0;
@@ -621,13 +621,13 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
 		// Make sure the index buffer isn't mapped (sends data to GPU if needed.)
 		// Make sure the index buffer isn't mapped (sends data to GPU if needed.)
 		ibo->unmap();
 		ibo->unmap();
 
 
-		start = std::min(std::max(0, rangeStart), (int) elementCount - 1);
+		start = std::min(std::max(0, rangeStart), (int) indexCount - 1);
 
 
-		count = (int) elementCount;
+		count = (int) indexCount;
 		if (rangeCount > 0)
 		if (rangeCount > 0)
 			count = std::min(count, rangeCount);
 			count = std::min(count, rangeCount);
 
 
-		count = std::min(count, (int) elementCount - start);
+		count = std::min(count, (int) indexCount - start);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -646,89 +646,5 @@ void Mesh::drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount)
 		drawInternal(start, count, instancecount, useindexbuffer, enabledattribs, instancedattribs);
 		drawInternal(start, count, instancecount, useindexbuffer, enabledattribs, instancedattribs);
 }
 }
 
 
-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;
-	}
-}
-
-bool Mesh::getConstant(const char *in, DrawMode &out)
-{
-	return drawModes.find(in, out);
-}
-
-bool Mesh::getConstant(DrawMode in, const char *&out)
-{
-	return drawModes.find(in, out);
-}
-
-std::vector<std::string> Mesh::getConstants(DrawMode)
-{
-	return drawModes.getNames();
-}
-
-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);
-}
-
-std::vector<std::string> Mesh::getConstants(DataType)
-{
-	return dataTypes.getNames();
-}
-
-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);
-}
-
-std::vector<std::string> Mesh::getConstants(AttributeStep)
-{
-	return attributeSteps.getNames();
-}
-
-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));
-
 } // graphics
 } // graphics
 } // love
 } // love

+ 14 - 64
src/modules/graphics/Mesh.h

@@ -52,41 +52,15 @@ public:
 
 
 	static love::Type type;
 	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
 	struct AttribFormat
 	{
 	{
 		std::string name;
 		std::string name;
-		DataType type;
+		vertex::DataType type;
 		int components; // max 4
 		int components; // max 4
 	};
 	};
 
 
-	Mesh(Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage);
-	Mesh(Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage);
+	Mesh(Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage);
+	Mesh(Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage);
 
 
 	virtual ~Mesh();
 	virtual ~Mesh();
 
 
@@ -122,7 +96,7 @@ public:
 	 * Gets the format of each vertex attribute stored in the Mesh.
 	 * Gets the format of each vertex attribute stored in the Mesh.
 	 **/
 	 **/
 	const std::vector<AttribFormat> &getVertexFormat() const;
 	const std::vector<AttribFormat> &getVertexFormat() const;
-	DataType getAttributeInfo(int attribindex, int &components) const;
+	vertex::DataType getAttributeInfo(int attribindex, int &components) const;
 	int getAttributeIndex(const std::string &name) const;
 	int getAttributeIndex(const std::string &name) const;
 
 
 	/**
 	/**
@@ -186,8 +160,8 @@ public:
 	/**
 	/**
 	 * Sets the draw mode used when drawing the Mesh.
 	 * Sets the draw mode used when drawing the Mesh.
 	 **/
 	 **/
-	void setDrawMode(DrawMode mode);
-	DrawMode getDrawMode() const;
+	void setDrawMode(PrimitiveType mode);
+	PrimitiveType getDrawMode() const;
 
 
 	void setDrawRange(int start, int count);
 	void setDrawRange(int start, int count);
 	void setDrawRange();
 	void setDrawRange();
@@ -200,17 +174,7 @@ public:
 
 
 	void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount);
 	void drawInstanced(Graphics *gfx, const Matrix4 &m, int instancecount);
 
 
-	static bool getConstant(const char *in, DrawMode &out);
-	static bool getConstant(DrawMode in, const char *&out);
-	static std::vector<std::string> getConstants(DrawMode);
-
-	static bool getConstant(const char *in, DataType &out);
-	static bool getConstant(DataType in, const char *&out);
-	static std::vector<std::string> getConstants(DataType);
-
-	static bool getConstant(const char *in, AttributeStep &out);
-	static bool getConstant(AttributeStep in, const char *&out);
-	static std::vector<std::string> getConstants(AttributeStep);
+	static std::vector<AttribFormat> getDefaultVertexFormat();
 
 
 protected:
 protected:
 
 
@@ -228,9 +192,6 @@ protected:
 
 
 	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, uint32 attribflags, uint32 instancedattribflags) const = 0;
 
 
-	static size_t getAttribFormatSize(const AttribFormat &format);
-	static std::vector<AttribFormat> getDefaultVertexFormat();
-
 	std::vector<AttribFormat> vertexFormat;
 	std::vector<AttribFormat> vertexFormat;
 	std::vector<size_t> attributeSizes;
 	std::vector<size_t> attributeSizes;
 
 
@@ -245,30 +206,19 @@ protected:
 	// avoid memory allocations when using Mesh::setVertex etc.
 	// avoid memory allocations when using Mesh::setVertex etc.
 	char *vertexScratchBuffer;
 	char *vertexScratchBuffer;
 
 
-	// Element (vertex index) buffer, for the vertex map.
+	// Index buffer, for the vertex map.
 	Buffer *ibo;
 	Buffer *ibo;
 	bool useIndexBuffer;
 	bool useIndexBuffer;
-	size_t elementCount;
-	IndexDataType elementDataType;
-	
-	DrawMode drawMode;
-	
+	size_t indexCount;
+	IndexDataType indexDataType;
+
+	PrimitiveType primitiveType;
+
 	int rangeStart;
 	int rangeStart;
 	int rangeCount;
 	int rangeCount;
-	
+
 	StrongRef<Texture> texture;
 	StrongRef<Texture> texture;
 
 
-private:
-	
-	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
 }; // Mesh
 
 
 } // graphics
 } // graphics

+ 2 - 0
src/modules/graphics/Shader.h

@@ -161,6 +161,8 @@ public:
 	 **/
 	 **/
 	virtual std::string getWarnings() const = 0;
 	virtual std::string getWarnings() const = 0;
 
 
+	virtual int getVertexAttributeIndex(const std::string &name) = 0;
+
 	virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0;
 	virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0;
 	virtual const UniformInfo *getUniformInfo(BuiltinUniform builtin) const = 0;
 	virtual const UniformInfo *getUniformInfo(BuiltinUniform builtin) const = 0;
 
 

+ 6 - 26
src/modules/graphics/opengl/Graphics.cpp

@@ -142,22 +142,12 @@ love::graphics::Buffer *Graphics::newBuffer(size_t size, const void *data, Buffe
 	return new Buffer(size, data, type, usage, mapflags);
 	return new Buffer(size, data, type, usage, mapflags);
 }
 }
 
 
-love::graphics::Mesh *Graphics::newMesh(const std::vector<Vertex> &vertices, Mesh::DrawMode drawmode, vertex::Usage usage)
-{
-	return new Mesh(this, vertices, drawmode, usage);
-}
-
-love::graphics::Mesh *Graphics::newMesh(int vertexcount, Mesh::DrawMode drawmode, vertex::Usage usage)
-{
-	return new Mesh(this, vertexcount, drawmode, usage);
-}
-
-love::graphics::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, PrimitiveType drawmode, vertex::Usage usage)
 {
 {
 	return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
 	return new Mesh(this, vertexformat, vertexcount, drawmode, usage);
 }
 }
 
 
-love::graphics::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, PrimitiveType drawmode, vertex::Usage usage)
 {
 {
 	return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
 	return new Mesh(this, vertexformat, data, datasize, drawmode, usage);
 }
 }
@@ -387,17 +377,7 @@ void Graphics::flushStreamDraws()
 	if (attribs == 0)
 	if (attribs == 0)
 		return;
 		return;
 
 
-	GLenum glmode = GL_ZERO;
-
-	switch (sbstate.primitiveMode)
-	{
-	case PrimitiveMode::TRIANGLES:
-		glmode = GL_TRIANGLES;
-		break;
-	case PrimitiveMode::POINTS:
-		glmode = GL_POINTS;
-		break;
-	}
+	GLenum glprimitivetype = OpenGL::getGLPrimitiveType(sbstate.primitiveMode);
 
 
 	Colorf nc = gl.getConstantColor();
 	Colorf nc = gl.getConstantColor();
 	if (attribs & ATTRIBFLAG_COLOR)
 	if (attribs & ATTRIBFLAG_COLOR)
@@ -419,10 +399,10 @@ void Graphics::flushStreamDraws()
 
 
 		sbstate.indexBufferMap = StreamBuffer::MapInfo();
 		sbstate.indexBufferMap = StreamBuffer::MapInfo();
 
 
-		gl.drawElements(glmode, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset));
+		gl.drawElements(glprimitivetype, sbstate.indexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(offset));
 	}
 	}
 	else
 	else
-		gl.drawArrays(glmode, 0, sbstate.vertexCount);
+		gl.drawArrays(glprimitivetype, 0, sbstate.vertexCount);
 
 
 	for (int i = 0; i < 2; i++)
 	for (int i = 0; i < 2; i++)
 	{
 	{
@@ -1266,7 +1246,7 @@ void Graphics::setBlendMode(BlendMode mode, BlendAlpha alphamode)
 
 
 void Graphics::setPointSize(float size)
 void Graphics::setPointSize(float size)
 {
 {
-	if (streamBufferState.primitiveMode == vertex::PrimitiveMode::POINTS)
+	if (streamBufferState.primitiveMode == PRIMITIVE_POINTS)
 		flushStreamDraws();
 		flushStreamDraws();
 
 
 	gl.setPointSize(size * getCurrentDPIScale());
 	gl.setPointSize(size * getCurrentDPIScale());

+ 2 - 5
src/modules/graphics/opengl/Graphics.h

@@ -71,11 +71,8 @@ public:
 
 
 	love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override;
 	love::graphics::Buffer *newBuffer(size_t size, const void *data, BufferType type, vertex::Usage usage, uint32 mapflags) override;
 
 
-	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;
-
-	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::Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage) override;
+	love::graphics::Mesh *newMesh(const std::vector<Mesh::AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage) override;
 
 
 	love::graphics::Text *newText(love::graphics::Font *font, const std::vector<Font::ColoredString> &text = {}) override;
 	love::graphics::Text *newText(love::graphics::Font *font, const std::vector<Font::ColoredString> &text = {}) override;
 
 

+ 12 - 50
src/modules/graphics/opengl/Mesh.cpp

@@ -35,26 +35,16 @@ namespace graphics
 namespace opengl
 namespace opengl
 {
 {
 
 
-Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, DrawMode drawmode, vertex::Usage usage)
+Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, const void *data, size_t datasize, PrimitiveType drawmode, vertex::Usage usage)
 	: love::graphics::Mesh(gfx, vertexformat, data, datasize, drawmode, usage)
 	: love::graphics::Mesh(gfx, vertexformat, data, datasize, drawmode, usage)
 {
 {
 }
 }
 
 
-Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawMode drawmode, vertex::Usage usage)
+Mesh::Mesh(graphics::Graphics *gfx, const std::vector<AttribFormat> &vertexformat, int vertexcount, PrimitiveType drawmode, vertex::Usage usage)
 	: love::graphics::Mesh(gfx, vertexformat, vertexcount, drawmode, usage)
 	: love::graphics::Mesh(gfx, vertexformat, vertexcount, drawmode, usage)
 {
 {
 }
 }
 
 
-Mesh::Mesh(graphics::Graphics *gfx, const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage)
-	: Mesh(gfx, getDefaultVertexFormat(), &vertices[0], vertices.size() * sizeof(Vertex), drawmode, usage)
-{
-}
-
-Mesh::Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage)
-	: Mesh(gfx, getDefaultVertexFormat(), vertexcount, drawmode, usage)
-{
-}
-
 Mesh::~Mesh()
 Mesh::~Mesh()
 {
 {
 }
 }
@@ -71,7 +61,7 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu
 	if (vertex::getConstant(inputname.c_str(), builtinattrib))
 	if (vertex::getConstant(inputname.c_str(), builtinattrib))
 		attriblocation = (GLint) builtinattrib;
 		attriblocation = (GLint) builtinattrib;
 	else if (Shader::current)
 	else if (Shader::current)
-		attriblocation = ((Shader *) Shader::current)->getAttribLocation(inputname);
+		attriblocation = Shader::current->getVertexAttributeIndex(inputname);
 
 
 	// The active shader might not use this vertex attribute name.
 	// The active shader might not use this vertex attribute name.
 	if (attriblocation < 0)
 	if (attriblocation < 0)
@@ -81,23 +71,11 @@ int Mesh::bindAttributeToShaderInput(int attributeindex, const std::string &inpu
 	vbo->unmap();
 	vbo->unmap();
 
 
 	gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle());
 	gl.bindBuffer(BUFFER_VERTEX, (GLuint) vbo->getHandle());
-	
-	GLenum datatype = 0;
-	switch (format.type)
-	{
-	case DATA_BYTE:
-		datatype = GL_UNSIGNED_BYTE;
-		break;
-	case DATA_FLOAT:
-		datatype = GL_FLOAT;
-		break;
-	default:
-		datatype = 0;
-		break;
-	}
+
+	GLboolean normalized = GL_FALSE;
+	GLenum datatype = OpenGL::getGLVertexDataType(format.type, normalized);
 
 
 	const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex));
 	const void *gloffset = BUFFER_OFFSET(getAttributeOffset(attributeindex));
-	GLboolean normalized = (datatype == GL_UNSIGNED_BYTE);
 
 
 	glVertexAttribPointer(attriblocation, format.components, datatype, normalized, (GLsizei) vertexStride, gloffset);
 	glVertexAttribPointer(attriblocation, format.components, datatype, normalized, (GLsizei) vertexStride, gloffset);
 
 
@@ -111,37 +89,21 @@ void Mesh::drawInternal(int start, int count, int instancecount, bool useindexbu
 	gl.useVertexAttribArrays(attribflags, instancedattribflags);
 	gl.useVertexAttribArrays(attribflags, instancedattribflags);
 	gl.bindTextureToUnit(texture, 0, false);
 	gl.bindTextureToUnit(texture, 0, false);
 	gl.prepareDraw();
 	gl.prepareDraw();
-	
-	GLenum gldrawmode = GL_TRIANGLES;
-	switch (drawMode)
-	{
-	case DRAWMODE_FAN:
-		gldrawmode = GL_TRIANGLE_FAN;
-		break;
-	case DRAWMODE_STRIP:
-		gldrawmode = GL_TRIANGLE_STRIP;
-		break;
-	case DRAWMODE_TRIANGLES:
-	default:
-		gldrawmode = GL_TRIANGLES;
-		break;
-	case DRAWMODE_POINTS:
-		gldrawmode = GL_POINTS;
-		break;
-	}
+
+	GLenum glprimitivetype = OpenGL::getGLPrimitiveType(primitiveType);
 
 
 	if (useindexbuffer)
 	if (useindexbuffer)
 	{
 	{
-		size_t elementsize = vertex::getIndexDataSize(elementDataType);
+		size_t elementsize = vertex::getIndexDataSize(indexDataType);
 		const void *indices = BUFFER_OFFSET(start * elementsize);
 		const void *indices = BUFFER_OFFSET(start * elementsize);
-		GLenum type = OpenGL::getGLIndexDataType(elementDataType);
+		GLenum indextype = OpenGL::getGLIndexDataType(indexDataType);
 
 
 		gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle());
 		gl.bindBuffer(BUFFER_INDEX, (GLuint) ibo->getHandle());
-		gl.drawElements(gldrawmode, count, type, indices, instancecount);
+		gl.drawElements(glprimitivetype, count, indextype, indices, instancecount);
 	}
 	}
 	else
 	else
 	{
 	{
-		gl.drawArrays(gldrawmode, start, count, instancecount);
+		gl.drawArrays(glprimitivetype, start, count, instancecount);
 	}
 	}
 }
 }
 
 

+ 2 - 5
src/modules/graphics/opengl/Mesh.h

@@ -35,11 +35,8 @@ class Mesh final : public love::graphics::Mesh
 {
 {
 public:
 public:
 
 
-	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);
-
-	Mesh(graphics::Graphics *gfx, const std::vector<Vertex> &vertices, DrawMode drawmode, vertex::Usage usage);
-	Mesh(graphics::Graphics *gfx, int vertexcount, DrawMode drawmode, vertex::Usage usage);
+	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();
 	virtual ~Mesh();
 
 

+ 41 - 0
src/modules/graphics/opengl/OpenGL.cpp

@@ -504,6 +504,25 @@ void OpenGL::prepareDraw()
 	}
 	}
 }
 }
 
 
+GLenum OpenGL::getGLPrimitiveType(PrimitiveType type)
+{
+	switch (type)
+	{
+	case PRIMITIVE_TRIANGLES:
+		return GL_TRIANGLES;
+	case PRIMITIVE_TRIANGLE_STRIP:
+		return GL_TRIANGLE_STRIP;
+	case PRIMITIVE_TRIANGLE_FAN:
+		return GL_TRIANGLE_FAN;
+	case PRIMITIVE_POINTS:
+		return GL_POINTS;
+	case PRIMITIVE_MAX_ENUM:
+		return GL_ZERO;
+	}
+
+	return GL_ZERO;
+}
+
 GLenum OpenGL::getGLBufferType(BufferType type)
 GLenum OpenGL::getGLBufferType(BufferType type)
 {
 {
 	switch (type)
 	switch (type)
@@ -551,6 +570,28 @@ GLenum OpenGL::getGLIndexDataType(IndexDataType type)
 	}
 	}
 }
 }
 
 
+GLenum OpenGL::getGLVertexDataType(vertex::DataType type, GLboolean &normalized)
+{
+	normalized = GL_FALSE;
+
+	switch (type)
+	{
+	case vertex::DATA_UNORM8:
+		normalized = GL_TRUE;
+		return GL_UNSIGNED_BYTE;
+	case vertex::DATA_UNORM16:
+		normalized = GL_TRUE;
+		return GL_UNSIGNED_SHORT;
+	case vertex::DATA_FLOAT:
+		normalized = GL_FALSE;
+		return GL_FLOAT;
+	case vertex::DATA_MAX_ENUM:
+		return GL_ZERO;
+	}
+
+	return GL_ZERO;
+}
+
 GLenum OpenGL::getGLBufferUsage(vertex::Usage usage)
 GLenum OpenGL::getGLBufferUsage(vertex::Usage usage)
 {
 {
 	switch (usage)
 	switch (usage)

+ 2 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -380,8 +380,10 @@ public:
 	 **/
 	 **/
 	Vendor getVendor() const;
 	Vendor getVendor() const;
 
 
+	static GLenum getGLPrimitiveType(PrimitiveType type);
 	static GLenum getGLBufferType(BufferType type);
 	static GLenum getGLBufferType(BufferType type);
 	static GLenum getGLIndexDataType(IndexDataType type);
 	static GLenum getGLIndexDataType(IndexDataType type);
+	static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized);
 	static GLenum getGLBufferUsage(vertex::Usage usage);
 	static GLenum getGLBufferUsage(vertex::Usage usage);
 	static GLenum getGLTextureType(TextureType type);
 	static GLenum getGLTextureType(TextureType type);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);

+ 1 - 1
src/modules/graphics/opengl/Shader.cpp

@@ -669,7 +669,7 @@ ptrdiff_t Shader::getHandle() const
 	return program;
 	return program;
 }
 }
 
 
-GLint Shader::getAttribLocation(const std::string &name)
+int Shader::getVertexAttributeIndex(const std::string &name)
 {
 {
 	auto it = attributes.find(name);
 	auto it = attributes.find(name);
 	if (it != attributes.end())
 	if (it != attributes.end())

+ 1 - 2
src/modules/graphics/opengl/Shader.h

@@ -57,6 +57,7 @@ public:
 	// Implements Shader.
 	// Implements Shader.
 	void attach() override;
 	void attach() override;
 	std::string getWarnings() const override;
 	std::string getWarnings() const override;
+	int getVertexAttributeIndex(const std::string &name) override;
 	const UniformInfo *getUniformInfo(const std::string &name) const override;
 	const UniformInfo *getUniformInfo(const std::string &name) const override;
 	const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
 	const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
 	void updateUniform(const UniformInfo *info, int count) override;
 	void updateUniform(const UniformInfo *info, int count) override;
@@ -65,8 +66,6 @@ public:
 	ptrdiff_t getHandle() const override;
 	ptrdiff_t getHandle() const override;
 	void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override;
 	void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) override;
 
 
-	GLint getAttribLocation(const std::string &name);
-
 	void updateScreenParams();
 	void updateScreenParams();
 	void updatePointSize(float size);
 	void updatePointSize(float size);
 	void updateBuiltinUniforms();
 	void updateBuiltinUniforms();

+ 72 - 0
src/modules/graphics/vertex.cpp

@@ -124,6 +124,21 @@ size_t getIndexDataSize(IndexDataType type)
 	}
 	}
 }
 }
 
 
+size_t getDataTypeSize(DataType datatype)
+{
+	switch (datatype)
+	{
+	case DATA_UNORM8:
+		return sizeof(uint8);
+	case DATA_UNORM16:
+		return sizeof(uint16);
+	case DATA_FLOAT:
+		return sizeof(float);
+	default:
+		return 0;
+	}
+}
+
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue)
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue)
 {
 {
 	IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32};
 	IndexDataType types[] = {INDEX_UINT16, INDEX_UINT32};
@@ -234,6 +249,33 @@ static StringMap<Usage, USAGE_MAX_ENUM>::Entry usageEntries[] =
 
 
 static StringMap<Usage, USAGE_MAX_ENUM> usages(usageEntries, sizeof(usageEntries));
 static StringMap<Usage, USAGE_MAX_ENUM> usages(usageEntries, sizeof(usageEntries));
 
 
+static StringMap<PrimitiveType, PRIMITIVE_MAX_ENUM>::Entry primitiveTypeEntries[] =
+{
+	{ "fan",       PRIMITIVE_TRIANGLE_FAN   },
+	{ "strip",     PRIMITIVE_TRIANGLE_STRIP },
+	{ "triangles", PRIMITIVE_TRIANGLES      },
+	{ "points",    PRIMITIVE_POINTS         },
+};
+
+static StringMap<PrimitiveType, PRIMITIVE_MAX_ENUM> primitiveTypes(primitiveTypeEntries, sizeof(primitiveTypeEntries));
+
+static StringMap<AttributeStep, STEP_MAX_ENUM>::Entry attributeStepEntries[] =
+{
+	{ "pervertex",   STEP_PER_VERTEX   },
+	{ "perinstance", STEP_PER_INSTANCE },
+};
+
+static StringMap<AttributeStep, STEP_MAX_ENUM> attributeSteps(attributeStepEntries, sizeof(attributeStepEntries));
+
+static StringMap<DataType, DATA_MAX_ENUM>::Entry dataTypeEntries[] =
+{
+	{ "byte",    DATA_UNORM8  }, // Legacy / more user-friendly name...
+	{ "unorm16", DATA_UNORM16 },
+	{ "float",   DATA_FLOAT   },
+};
+
+static StringMap<DataType, DATA_MAX_ENUM> dataTypes(dataTypeEntries, sizeof(dataTypeEntries));
+
 bool getConstant(const char *in, VertexAttribID &out)
 bool getConstant(const char *in, VertexAttribID &out)
 {
 {
 	return attribNames.find(in, out);
 	return attribNames.find(in, out);
@@ -274,6 +316,36 @@ std::vector<std::string> getConstants(Usage)
 	return usages.getNames();
 	return usages.getNames();
 }
 }
 
 
+bool getConstant(const char *in, PrimitiveType &out)
+{
+	return primitiveTypes.find(in, out);
+}
+
+bool getConstant(PrimitiveType in, const char *&out)
+{
+	return primitiveTypes.find(in, out);
+}
+
+std::vector<std::string> getConstants(PrimitiveType)
+{
+	return primitiveTypes.getNames();
+}
+
+bool getConstant(const char *in, AttributeStep &out)
+{
+	return attributeSteps.find(in, out);
+}
+
+bool getConstant(AttributeStep in, const char *&out)
+{
+	return attributeSteps.find(in, out);
+}
+
+std::vector<std::string> getConstants(AttributeStep)
+{
+	return attributeSteps.getNames();
+}
+
 } // vertex
 } // vertex
 } // graphics
 } // graphics
 } // love
 } // love

+ 35 - 3
src/modules/graphics/vertex.h

@@ -67,6 +67,23 @@ enum IndexDataType
 	INDEX_MAX_ENUM
 	INDEX_MAX_ENUM
 };
 };
 
 
+// http://escience.anu.edu.au/lecture/cg/surfaceModeling/image/surfaceModeling015.png
+enum PrimitiveType
+{
+	PRIMITIVE_TRIANGLES,
+	PRIMITIVE_TRIANGLE_STRIP,
+	PRIMITIVE_TRIANGLE_FAN,
+	PRIMITIVE_POINTS,
+	PRIMITIVE_MAX_ENUM
+};
+
+enum AttributeStep
+{
+	STEP_PER_VERTEX,
+	STEP_PER_INSTANCE,
+	STEP_MAX_ENUM
+};
+
 namespace vertex
 namespace vertex
 {
 {
 
 
@@ -79,10 +96,12 @@ enum Usage
 	USAGE_MAX_ENUM
 	USAGE_MAX_ENUM
 };
 };
 
 
-enum class PrimitiveMode
+enum DataType
 {
 {
-	TRIANGLES,
-	POINTS,
+	DATA_UNORM8,
+	DATA_UNORM16,
+	DATA_FLOAT,
+	DATA_MAX_ENUM
 };
 };
 
 
 enum class TriangleIndexMode
 enum class TriangleIndexMode
@@ -165,6 +184,7 @@ inline CommonFormat getSinglePositionFormat(bool is2D)
 }
 }
 
 
 size_t getIndexDataSize(IndexDataType type);
 size_t getIndexDataSize(IndexDataType type);
+size_t getDataTypeSize(DataType datatype);
 
 
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
 IndexDataType getIndexDataTypeFromMax(size_t maxvalue);
 
 
@@ -184,6 +204,18 @@ bool getConstant(const char *in, Usage &out);
 bool getConstant(Usage in, const char *&out);
 bool getConstant(Usage in, const char *&out);
 std::vector<std::string> getConstants(Usage);
 std::vector<std::string> getConstants(Usage);
 
 
+bool getConstant(const char *in, PrimitiveType &out);
+bool getConstant(PrimitiveType in, const char *&out);
+std::vector<std::string> getConstants(PrimitiveType);
+
+bool getConstant(const char *in, AttributeStep &out);
+bool getConstant(AttributeStep in, const char *&out);
+std::vector<std::string> getConstants(AttributeStep);
+
+bool getConstant(const char *in, DataType &out);
+bool getConstant(DataType in, const char *&out);
+std::vector<std::string> getConstants(DataType);
+
 } // vertex
 } // vertex
 
 
 typedef vertex::XYf_STf_RGBAub Vertex;
 typedef vertex::XYf_STf_RGBAub Vertex;

+ 7 - 7
src/modules/graphics/wrap_Graphics.cpp

@@ -1408,12 +1408,12 @@ static vertex::Usage luax_optmeshusage(lua_State *L, int idx, vertex::Usage def)
 	return def;
 	return def;
 }
 }
 
 
-static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode def)
+static PrimitiveType luax_optmeshdrawmode(lua_State *L, int idx, PrimitiveType def)
 {
 {
 	const char *modestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
 	const char *modestr = lua_isnoneornil(L, idx) ? nullptr : luaL_checkstring(L, idx);
 
 
-	if (modestr && !Mesh::getConstant(modestr, def))
-		luax_enumerror(L, "mesh draw mode", Mesh::getConstants(def), modestr);
+	if (modestr && !vertex::getConstant(modestr, def))
+		luax_enumerror(L, "mesh draw mode", vertex::getConstants(def), modestr);
 
 
 	return def;
 	return def;
 }
 }
@@ -1422,7 +1422,7 @@ static Mesh *newStandardMesh(lua_State *L)
 {
 {
 	Mesh *t = nullptr;
 	Mesh *t = nullptr;
 
 
-	Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 2, Mesh::DRAWMODE_FAN);
+	PrimitiveType drawmode = luax_optmeshdrawmode(L, 2, PRIMITIVE_TRIANGLE_FAN);
 	vertex::Usage usage = luax_optmeshusage(L, 3, vertex::USAGE_DYNAMIC);
 	vertex::Usage usage = luax_optmeshusage(L, 3, vertex::USAGE_DYNAMIC);
 
 
 	// First argument is a table of standard vertices, or the number of
 	// First argument is a table of standard vertices, or the number of
@@ -1482,7 +1482,7 @@ static Mesh *newCustomMesh(lua_State *L)
 	// the number of vertices.
 	// the number of vertices.
 	std::vector<Mesh::AttribFormat> vertexformat;
 	std::vector<Mesh::AttribFormat> vertexformat;
 
 
-	Mesh::DrawMode drawmode = luax_optmeshdrawmode(L, 3, Mesh::DRAWMODE_FAN);
+	PrimitiveType drawmode = luax_optmeshdrawmode(L, 3, PRIMITIVE_TRIANGLE_FAN);
 	vertex::Usage usage = luax_optmeshusage(L, 4, vertex::USAGE_DYNAMIC);
 	vertex::Usage usage = luax_optmeshusage(L, 4, vertex::USAGE_DYNAMIC);
 
 
 	lua_rawgeti(L, 1, 1);
 	lua_rawgeti(L, 1, 1);
@@ -1506,9 +1506,9 @@ static Mesh *newCustomMesh(lua_State *L)
 		format.name = luaL_checkstring(L, -3);
 		format.name = luaL_checkstring(L, -3);
 
 
 		const char *tname = luaL_checkstring(L, -2);
 		const char *tname = luaL_checkstring(L, -2);
-		if (!Mesh::getConstant(tname, format.type))
+		if (!vertex::getConstant(tname, format.type))
 		{
 		{
-			luax_enumerror(L, "Mesh vertex data type name", Mesh::getConstants(format.type), tname);
+			luax_enumerror(L, "Mesh vertex data type name", vertex::getConstants(format.type), tname);
 			return nullptr;
 			return nullptr;
 		}
 		}
 
 

+ 46 - 22
src/modules/graphics/wrap_Mesh.cpp

@@ -37,7 +37,7 @@ Mesh *luax_checkmesh(lua_State *L, int idx)
 	return luax_checktype<Mesh>(L, idx);
 	return luax_checktype<Mesh>(L, idx);
 }
 }
 
 
-static inline size_t writeByteData(lua_State *L, int startidx, int components, char *data)
+static inline size_t writeUnorm8Data(lua_State *L, int startidx, int components, char *data)
 {
 {
 	uint8 *componentdata = (uint8 *) data;
 	uint8 *componentdata = (uint8 *) data;
 
 
@@ -47,6 +47,16 @@ static inline size_t writeByteData(lua_State *L, int startidx, int components, c
 	return sizeof(uint8) * components;
 	return sizeof(uint8) * components;
 }
 }
 
 
+static inline size_t writeUnorm16Data(lua_State *L, int startidx, int components, char *data)
+{
+	uint16 *componentdata = (uint16 *) data;
+
+	for (int i = 0; i < components; i++)
+		componentdata[i] = (uint16) (luaL_optnumber(L, startidx + i, 1.0) * 65535.0);
+
+	return sizeof(uint16) * components;
+}
+
 static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data)
 static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data)
 {
 {
 	float *componentdata = (float *) data;
 	float *componentdata = (float *) data;
@@ -57,20 +67,22 @@ static inline size_t writeFloatData(lua_State *L, int startidx, int components,
 	return sizeof(float) * components;
 	return sizeof(float) * components;
 }
 }
 
 
-char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data)
+char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data)
 {
 {
 	switch (type)
 	switch (type)
 	{
 	{
-	case Mesh::DATA_BYTE:
-		return data + writeByteData(L, startidx, components, data);
-	case Mesh::DATA_FLOAT:
+	case vertex::DATA_UNORM8:
+		return data + writeUnorm8Data(L, startidx, components, data);
+	case vertex::DATA_UNORM16:
+		return data + writeUnorm16Data(L, startidx, components, data);
+	case vertex::DATA_FLOAT:
 		return data + writeFloatData(L, startidx, components, data);
 		return data + writeFloatData(L, startidx, components, data);
 	default:
 	default:
 		return data;
 		return data;
 	}
 	}
 }
 }
 
 
-static inline size_t readByteData(lua_State *L, int components, const char *data)
+static inline size_t readUnorm8Data(lua_State *L, int components, const char *data)
 {
 {
 	const uint8 *componentdata = (const uint8 *) data;
 	const uint8 *componentdata = (const uint8 *) data;
 
 
@@ -80,6 +92,16 @@ static inline size_t readByteData(lua_State *L, int components, const char *data
 	return sizeof(uint8) * components;
 	return sizeof(uint8) * components;
 }
 }
 
 
+static inline size_t readUnorm16Data(lua_State *L, int components, const char *data)
+{
+	const uint16 *componentdata = (const uint16 *) data;
+
+	for (int i = 0; i < components; i++)
+		lua_pushnumber(L, (lua_Number) componentdata[i] / 65535.0);
+
+	return sizeof(uint16) * components;
+}
+
 static inline size_t readFloatData(lua_State *L, int components, const char *data)
 static inline size_t readFloatData(lua_State *L, int components, const char *data)
 {
 {
 	const float *componentdata = (const float *) data;
 	const float *componentdata = (const float *) data;
@@ -90,13 +112,15 @@ static inline size_t readFloatData(lua_State *L, int components, const char *dat
 	return sizeof(float) * components;
 	return sizeof(float) * components;
 }
 }
 
 
-const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data)
+const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data)
 {
 {
 	switch (type)
 	switch (type)
 	{
 	{
-	case Mesh::DATA_BYTE:
-		return data + readByteData(L, components, data);
-	case Mesh::DATA_FLOAT:
+	case vertex::DATA_UNORM8:
+		return data + readUnorm8Data(L, components, data);
+	case vertex::DATA_UNORM16:
+		return data + readUnorm16Data(L, components, data);
+	case vertex::DATA_FLOAT:
 		return data + readFloatData(L, components, data);
 		return data + readFloatData(L, components, data);
 	default:
 	default:
 		return data;
 		return data;
@@ -239,7 +263,7 @@ int w_Mesh_setVertexAttribute(lua_State *L)
 	size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
 	size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
 	int attribindex = (int) luaL_checkinteger(L, 3) - 1;
 	int attribindex = (int) luaL_checkinteger(L, 3) - 1;
 
 
-	Mesh::DataType type;
+	vertex::DataType type;
 	int components;
 	int components;
 	luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
 	luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
 
 
@@ -259,7 +283,7 @@ int w_Mesh_getVertexAttribute(lua_State *L)
 	size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
 	size_t vertindex = (size_t) luaL_checkinteger(L, 2) - 1;
 	int attribindex = (int) luaL_checkinteger(L, 3) - 1;
 	int attribindex = (int) luaL_checkinteger(L, 3) - 1;
 
 
-	Mesh::DataType type;
+	vertex::DataType type;
 	int components;
 	int components;
 	luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
 	luax_catchexcept(L, [&](){ type = t->getAttributeInfo(attribindex, components); });
 
 
@@ -290,8 +314,8 @@ int w_Mesh_getVertexFormat(lua_State *L)
 
 
 	for (size_t i = 0; i < vertexformat.size(); i++)
 	for (size_t i = 0; i < vertexformat.size(); i++)
 	{
 	{
-		if (!Mesh::getConstant(vertexformat[i].type, tname))
-			return luax_enumerror(L, "vertex attribute data type", Mesh::getConstants(vertexformat[i].type), tname);
+		if (!vertex::getConstant(vertexformat[i].type, tname))
+			return luax_enumerror(L, "vertex attribute data type", vertex::getConstants(vertexformat[i].type), tname);
 
 
 		lua_createtable(L, 3, 0);
 		lua_createtable(L, 3, 0);
 
 
@@ -336,10 +360,10 @@ int w_Mesh_attachAttribute(lua_State *L)
 	const char *name = luaL_checkstring(L, 2);
 	const char *name = luaL_checkstring(L, 2);
 	Mesh *mesh = luax_checkmesh(L, 3);
 	Mesh *mesh = luax_checkmesh(L, 3);
 
 
-	Mesh::AttributeStep step = Mesh::STEP_PER_VERTEX;
+	AttributeStep step = STEP_PER_VERTEX;
 	const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
 	const char *stepstr = lua_isnoneornil(L, 4) ? nullptr : luaL_checkstring(L, 4);
-	if (stepstr != nullptr && !Mesh::getConstant(stepstr, step))
-		return luax_enumerror(L, "vertex attribute step", Mesh::getConstants(step), stepstr);
+	if (stepstr != nullptr && !vertex::getConstant(stepstr, step))
+		return luax_enumerror(L, "vertex attribute step", vertex::getConstants(step), stepstr);
 
 
 	const char *attachname = luaL_optstring(L, 5, name);
 	const char *attachname = luaL_optstring(L, 5, name);
 
 
@@ -485,10 +509,10 @@ int w_Mesh_setDrawMode(lua_State *L)
 {
 {
 	Mesh *t = luax_checkmesh(L, 1);
 	Mesh *t = luax_checkmesh(L, 1);
 	const char *str = luaL_checkstring(L, 2);
 	const char *str = luaL_checkstring(L, 2);
-	Mesh::DrawMode mode;
+	PrimitiveType mode;
 
 
-	if (!Mesh::getConstant(str, mode))
-		return luax_enumerror(L, "mesh draw mode", Mesh::getConstants(mode), str);
+	if (!vertex::getConstant(str, mode))
+		return luax_enumerror(L, "mesh draw mode", vertex::getConstants(mode), str);
 
 
 	t->setDrawMode(mode);
 	t->setDrawMode(mode);
 	return 0;
 	return 0;
@@ -497,10 +521,10 @@ int w_Mesh_setDrawMode(lua_State *L)
 int w_Mesh_getDrawMode(lua_State *L)
 int w_Mesh_getDrawMode(lua_State *L)
 {
 {
 	Mesh *t = luax_checkmesh(L, 1);
 	Mesh *t = luax_checkmesh(L, 1);
-	Mesh::DrawMode mode = t->getDrawMode();
+	PrimitiveType mode = t->getDrawMode();
 	const char *str;
 	const char *str;
 
 
-	if (!Mesh::getConstant(mode, str))
+	if (!vertex::getConstant(mode, str))
 		return luaL_error(L, "Unknown mesh draw mode.");
 		return luaL_error(L, "Unknown mesh draw mode.");
 
 
 	lua_pushstring(L, str);
 	lua_pushstring(L, str);

+ 2 - 2
src/modules/graphics/wrap_Mesh.h

@@ -30,8 +30,8 @@ namespace love
 namespace graphics
 namespace graphics
 {
 {
 
 
-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);
+char *luax_writeAttributeData(lua_State *L, int startidx, vertex::DataType type, int components, char *data);
+const char *luax_readAttributeData(lua_State *L, vertex::DataType type, int components, const char *data);
 
 
 Mesh *luax_checkmesh(lua_State *L, int idx);
 Mesh *luax_checkmesh(lua_State *L, int idx);
 extern "C" int luaopen_mesh(lua_State *L);
 extern "C" int luaopen_mesh(lua_State *L);