Browse Source

Add love.graphics.drawShaderVertices (name subject to change).

It draws a number of vertices, or a number of indices from an index buffer, without using any vertex data from a vertex buffer. A custom shader is required while using it.

It is useful when a custom GLSL3 vertex shader which uses love_VertexID is used to pull or compute per-vertex information from other sources.
Alex Szpakowski 3 years ago
parent
commit
0c4be3d5e3

+ 69 - 0
src/modules/graphics/Graphics.cpp

@@ -1516,6 +1516,75 @@ void Graphics::drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount)
 	mesh->drawInstanced(this, m, instancecount);
 	mesh->drawInstanced(this, m, instancecount);
 }
 }
 
 
+void Graphics::drawShaderVertices(PrimitiveType primtype, int vertexcount, int instancecount, Texture *maintexture)
+{
+	flushBatchedDraws();
+
+	if (!capabilities.features[FEATURE_GLSL3])
+		throw love::Exception("drawShaderVertices is not supported on this system (GLSL3 support is required.)");
+
+	if (Shader::isDefaultActive() || !Shader::current)
+		throw love::Exception("drawShaderVertices can only be used with a custom shader.");
+
+	if (vertexcount < 0 || instancecount < 0)
+		throw love::Exception("drawShaderVertices vertex and instance count parameters must not be negative.");
+
+	Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, maintexture);
+
+	VertexAttributes attributes;
+	BufferBindings buffers;
+
+	DrawCommand cmd(&attributes, &buffers);
+
+	cmd.primitiveType = primtype;
+	cmd.vertexCount = vertexcount;
+	cmd.instanceCount = std::max(1, instancecount);
+	cmd.texture = maintexture;
+
+	draw(cmd);
+}
+
+void Graphics::drawShaderVertices(Buffer *indexbuffer, int indexcount, int instancecount, int startindex, Texture *maintexture)
+{
+	flushBatchedDraws();
+
+	if (!capabilities.features[FEATURE_GLSL3])
+		throw love::Exception("drawShaderVertices is not supported on this system (GLSL3 support is required.)");
+
+	if (!(indexbuffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX))
+		throw love::Exception("The buffer passed to drawShaderVertices must be an index buffer.");
+
+	if (startindex < 0)
+		throw love::Exception("drawShaderVertices startindex parameter must not be negative.");
+
+	if (indexcount < 0 || instancecount < 0)
+		throw love::Exception("drawShaderVertices index and instance count parameters must not be negative.");
+
+	if ((size_t)(startindex + indexcount) > indexbuffer->getArrayLength())
+		throw love::Exception("drawShaderVertices startindex and index count parameters do not fit in the given index buffer.");
+
+	if (Shader::isDefaultActive() || !Shader::current)
+		throw love::Exception("drawShaderVertices can only be used with a custom shader.");
+
+	Shader::current->validateDrawState(PRIMITIVE_TRIANGLES, maintexture);
+
+	VertexAttributes attributes;
+	BufferBindings buffers;
+
+	DrawIndexedCommand cmd(&attributes, &buffers, indexbuffer);
+
+	cmd.primitiveType = PRIMITIVE_TRIANGLES;
+	cmd.indexCount = indexcount;
+	cmd.instanceCount = std::max(1, instancecount);
+
+	cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format);
+	cmd.indexBufferOffset = startindex * getIndexDataSize(cmd.indexType);
+
+	cmd.texture = maintexture;
+
+	draw(cmd);
+}
+
 void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
 void Graphics::print(const std::vector<Font::ColoredString> &str, const Matrix4 &m)
 {
 {
 	checkSetDefaultFont();
 	checkSetDefaultFont();

+ 3 - 0
src/modules/graphics/Graphics.h

@@ -688,6 +688,9 @@ public:
 	void drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m);
 	void drawLayer(Texture *texture, int layer, Quad *quad, const Matrix4 &m);
 	void drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount);
 	void drawInstanced(Mesh *mesh, const Matrix4 &m, int instancecount);
 
 
+	void drawShaderVertices(PrimitiveType primtype, int vertexcount, int instancecount, Texture *maintexture);
+	void drawShaderVertices(Buffer *indexbuffer, int indexcount, int instancecount, int startindex, Texture *maintexture);
+
 	/**
 	/**
 	 * Draws text at the specified coordinates
 	 * Draws text at the specified coordinates
 	 **/
 	 **/

+ 37 - 0
src/modules/graphics/wrap_Graphics.cpp

@@ -2938,6 +2938,42 @@ int w_drawInstanced(lua_State *L)
 	return 0;
 	return 0;
 }
 }
 
 
+int w_drawShaderVertices(lua_State *L)
+{
+	if (luax_istype(L, 1, Buffer::type))
+	{
+		// Indexed drawing.
+		Buffer *t = luax_checkbuffer(L, 1);
+
+		int indexcount = (int) luaL_checkinteger(L, 2);
+		int instancecount = (int) luaL_optinteger(L, 3, 1);
+		int indexstart = (int) luaL_optinteger(L, 4, 1) - 1;
+
+		Texture *tex = nullptr;
+		if (!lua_isnoneornil(L, 5))
+			tex = luax_checktexture(L, 5);
+
+		luax_catchexcept(L, [&]() { instance()->drawShaderVertices(t, indexcount, instancecount, indexstart, tex); });
+	}
+	else
+	{
+		const char *primstr = luaL_checkstring(L, 1);
+		PrimitiveType primtype = PRIMITIVE_TRIANGLES;
+		if (!getConstant(primstr, primtype))
+			return luax_enumerror(L, "primitive type", getConstants(primtype), primstr);
+
+		int vertexcount = (int) luaL_checkinteger(L, 2);
+		int instancecount = (int) luaL_optinteger(L, 3, 1);
+
+		Texture *tex = nullptr;
+		if (!lua_isnoneornil(L, 4))
+			tex = luax_checktexture(L, 4);
+
+		luax_catchexcept(L, [&]() { instance()->drawShaderVertices(primtype, vertexcount, instancecount, tex); });
+	}
+	return 0;
+}
+
 int w_print(lua_State *L)
 int w_print(lua_State *L)
 {
 {
 	std::vector<Font::ColoredString> str;
 	std::vector<Font::ColoredString> str;
@@ -3614,6 +3650,7 @@ static const luaL_Reg functions[] =
 	{ "draw", w_draw },
 	{ "draw", w_draw },
 	{ "drawLayer", w_drawLayer },
 	{ "drawLayer", w_drawLayer },
 	{ "drawInstanced", w_drawInstanced },
 	{ "drawInstanced", w_drawInstanced },
+	{ "drawShaderVertices", w_drawShaderVertices },
 
 
 	{ "print", w_print },
 	{ "print", w_print },
 	{ "printf", w_printf },
 	{ "printf", w_printf },