mirror of
https://github.com/love2d/love.git
synced 2026-08-20 12:40:20 +02:00
Allow rendering to integer textures.
This commit is contained in:
@@ -137,6 +137,7 @@ ColorT<T> operator/(const ColorT<T> &a, T s)
|
|||||||
|
|
||||||
typedef ColorT<unsigned char> Color32;
|
typedef ColorT<unsigned char> Color32;
|
||||||
typedef ColorT<float> Colorf;
|
typedef ColorT<float> Colorf;
|
||||||
|
typedef ColorT<double> ColorD;
|
||||||
|
|
||||||
inline Color32 toColor32(Colorf cf)
|
inline Color32 toColor32(Colorf cf)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -693,9 +693,6 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
|
|||||||
if (!firsttex->isValidSlice(firsttarget.slice))
|
if (!firsttex->isValidSlice(firsttarget.slice))
|
||||||
throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
|
throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
|
||||||
|
|
||||||
if (isPixelFormatInteger(firstcolorformat))
|
|
||||||
throw love::Exception("Textures with integer pixel formats cannot be rendered to, currently.");
|
|
||||||
|
|
||||||
bool hasSRGBtexture = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM;
|
bool hasSRGBtexture = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM;
|
||||||
int pixelw = firsttex->getPixelWidth(firsttarget.mipmap);
|
int pixelw = firsttex->getPixelWidth(firsttarget.mipmap);
|
||||||
int pixelh = firsttex->getPixelHeight(firsttarget.mipmap);
|
int pixelh = firsttex->getPixelHeight(firsttarget.mipmap);
|
||||||
@@ -729,9 +726,6 @@ void Graphics::setRenderTargets(const RenderTargets &rts)
|
|||||||
if (isPixelFormatDepthStencil(format))
|
if (isPixelFormatDepthStencil(format))
|
||||||
throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets.");
|
throw love::Exception("Depth/stencil format textures must be used with the 'depthstencil' field of the table passed into setRenderTargets.");
|
||||||
|
|
||||||
if (isPixelFormatInteger(format))
|
|
||||||
throw love::Exception("Textures with integer pixel formats cannot be rendered to, currently.");
|
|
||||||
|
|
||||||
if (format == PIXELFORMAT_sRGBA8_UNORM)
|
if (format == PIXELFORMAT_sRGBA8_UNORM)
|
||||||
hasSRGBtexture = true;
|
hasSRGBtexture = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Text;
|
|||||||
class Video;
|
class Video;
|
||||||
class Buffer;
|
class Buffer;
|
||||||
|
|
||||||
typedef Optional<Colorf> OptionalColorf;
|
typedef Optional<ColorD> OptionalColorD;
|
||||||
|
|
||||||
const int MAX_COLOR_RENDER_TARGETS = 8;
|
const int MAX_COLOR_RENDER_TARGETS = 8;
|
||||||
|
|
||||||
@@ -457,8 +457,8 @@ public:
|
|||||||
**/
|
**/
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
virtual void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) = 0;
|
virtual void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) = 0;
|
||||||
virtual void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) = 0;
|
virtual void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) = 0;
|
||||||
|
|
||||||
virtual void discard(const std::vector<bool> &colorbuffers, bool depthstencil) = 0;
|
virtual void discard(const std::vector<bool> &colorbuffers, bool depthstencil) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -640,6 +640,40 @@ const Shader::UniformInfo *Shader::getMainTextureInfo() const
|
|||||||
return getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
return getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataBaseType Shader::getDataBaseType(PixelFormat format)
|
||||||
|
{
|
||||||
|
switch (getPixelFormatInfo(format).dataType)
|
||||||
|
{
|
||||||
|
case PIXELFORMATTYPE_UNORM:
|
||||||
|
return DATA_BASETYPE_UNORM;
|
||||||
|
case PIXELFORMATTYPE_SNORM:
|
||||||
|
return DATA_BASETYPE_SNORM;
|
||||||
|
case PIXELFORMATTYPE_UFLOAT:
|
||||||
|
case PIXELFORMATTYPE_SFLOAT:
|
||||||
|
return DATA_BASETYPE_FLOAT;
|
||||||
|
case PIXELFORMATTYPE_SINT:
|
||||||
|
return DATA_BASETYPE_INT;
|
||||||
|
case PIXELFORMATTYPE_UINT:
|
||||||
|
return DATA_BASETYPE_UINT;
|
||||||
|
default:
|
||||||
|
return DATA_BASETYPE_FLOAT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shader::isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b)
|
||||||
|
{
|
||||||
|
if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
|
||||||
|
return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
|
||||||
|
|
||||||
|
if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
|
void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
|
||||||
{
|
{
|
||||||
if ((primtype == PRIMITIVE_POINTS) != validationReflection.usesPointSize)
|
if ((primtype == PRIMITIVE_POINTS) != validationReflection.usesPointSize)
|
||||||
@@ -672,6 +706,9 @@ void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const
|
|||||||
throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
|
throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isResourceBaseTypeCompatible(info->dataBaseType, getDataBaseType(maintex->getPixelFormat())))
|
||||||
|
throw love::Exception("Texture's data format base type must match the uniform variable declared in the shader (float, int, or uint).");
|
||||||
|
|
||||||
if (info->isDepthSampler != maintex->getSamplerState().depthSampleMode.hasValue)
|
if (info->isDepthSampler != maintex->getSamplerState().depthSampleMode.hasValue)
|
||||||
{
|
{
|
||||||
if (info->isDepthSampler)
|
if (info->isDepthSampler)
|
||||||
|
|||||||
@@ -259,6 +259,8 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, ValidationReflection &reflection);
|
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, ValidationReflection &reflection);
|
||||||
|
static DataBaseType getDataBaseType(PixelFormat format);
|
||||||
|
static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b);
|
||||||
|
|
||||||
StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM];
|
StrongRef<ShaderStage> stages[SHADERSTAGE_MAX_ENUM];
|
||||||
|
|
||||||
|
|||||||
@@ -835,7 +835,7 @@ void Graphics::endPass()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
|
void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth)
|
||||||
{
|
{
|
||||||
if (c.hasValue || stencil.hasValue || depth.hasValue)
|
if (c.hasValue || stencil.hasValue || depth.hasValue)
|
||||||
flushBatchedDraws();
|
flushBatchedDraws();
|
||||||
@@ -844,8 +844,9 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
|||||||
|
|
||||||
if (c.hasValue)
|
if (c.hasValue)
|
||||||
{
|
{
|
||||||
gammaCorrectColor(c.value);
|
Colorf cf((float)c.value.r, (float)c.value.g, (float)c.value.b, (float)c.value.b);
|
||||||
glClearColor(c.value.r, c.value.g, c.value.b, c.value.a);
|
gammaCorrectColor(cf);
|
||||||
|
glClearColor(cf.r, cf.g, cf.b, cf.a);
|
||||||
flags |= GL_COLOR_BUFFER_BIT;
|
flags |= GL_COLOR_BUFFER_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,17 +882,19 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth)
|
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
|
||||||
{
|
{
|
||||||
if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
|
if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int ncolorRTs = (int) states.back().renderTargets.colors.size();
|
const auto &rts = states.back().renderTargets.colors;
|
||||||
|
|
||||||
|
int ncolorRTs = (int) rts.size();
|
||||||
int ncolors = (int) colors.size();
|
int ncolors = (int) colors.size();
|
||||||
|
|
||||||
if (ncolors <= 1 && ncolorRTs <= 1)
|
if (ncolors <= 1 && (ncolorRTs == 0 || (ncolorRTs == 1 && rts[0].texture != nullptr && !isPixelFormatInteger(rts[0].texture->getPixelFormat()))))
|
||||||
{
|
{
|
||||||
clear(ncolors > 0 ? colors[0] : OptionalColorf(), stencil, depth);
|
clear(ncolors > 0 ? colors[0] : OptionalColorD(), stencil, depth);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -905,18 +908,39 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
|
|||||||
if (!colors[i].hasValue)
|
if (!colors[i].hasValue)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Colorf c = colors[i].value;
|
PixelFormatType datatype = PIXELFORMATTYPE_UNORM;
|
||||||
gammaCorrectColor(c);
|
if (rts[i].texture != nullptr)
|
||||||
|
datatype = getPixelFormatInfo(rts[i].texture->getPixelFormat()).dataType;
|
||||||
|
|
||||||
|
ColorD c = colors[i].value;
|
||||||
|
|
||||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
|
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
|
||||||
{
|
{
|
||||||
const GLfloat carray[] = {c.r, c.g, c.b, c.a};
|
if (datatype == PIXELFORMATTYPE_SINT)
|
||||||
glClearBufferfv(GL_COLOR, i, carray);
|
{
|
||||||
|
const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a};
|
||||||
|
glClearBufferiv(GL_COLOR, i, carray);
|
||||||
|
}
|
||||||
|
else if (datatype == PIXELFORMATTYPE_UINT)
|
||||||
|
{
|
||||||
|
const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a};
|
||||||
|
glClearBufferuiv(GL_COLOR, i, carray);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
|
||||||
|
gammaCorrectColor(cf);
|
||||||
|
const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a};
|
||||||
|
glClearBufferfv(GL_COLOR, i, carray);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
|
||||||
|
gammaCorrectColor(cf);
|
||||||
|
|
||||||
glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
|
glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
|
||||||
glClearColor(c.r, c.g, c.b, c.a);
|
glClearColor(cf.r, cf.g, cf.b, cf.a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
drawbuffersmodified = true;
|
drawbuffersmodified = true;
|
||||||
|
|||||||
@@ -74,8 +74,8 @@ public:
|
|||||||
void draw(const DrawIndexedCommand &cmd) override;
|
void draw(const DrawIndexedCommand &cmd) override;
|
||||||
void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture) override;
|
void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture) override;
|
||||||
|
|
||||||
void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
|
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
|
||||||
void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||||
|
|
||||||
void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
|
void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
|
||||||
|
|
||||||
|
|||||||
@@ -710,40 +710,6 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b)
|
|
||||||
{
|
|
||||||
if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
|
|
||||||
return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
|
|
||||||
|
|
||||||
if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DataBaseType getDataBaseType(PixelFormat format)
|
|
||||||
{
|
|
||||||
switch (getPixelFormatInfo(format).dataType)
|
|
||||||
{
|
|
||||||
case PIXELFORMATTYPE_UNORM:
|
|
||||||
return DATA_BASETYPE_UNORM;
|
|
||||||
case PIXELFORMATTYPE_SNORM:
|
|
||||||
return DATA_BASETYPE_SNORM;
|
|
||||||
case PIXELFORMATTYPE_UFLOAT:
|
|
||||||
case PIXELFORMATTYPE_SFLOAT:
|
|
||||||
return DATA_BASETYPE_FLOAT;
|
|
||||||
case PIXELFORMATTYPE_SINT:
|
|
||||||
return DATA_BASETYPE_INT;
|
|
||||||
case PIXELFORMATTYPE_UINT:
|
|
||||||
return DATA_BASETYPE_UINT;
|
|
||||||
default:
|
|
||||||
return DATA_BASETYPE_FLOAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
||||||
{
|
{
|
||||||
Shader::sendTextures(info, textures, count, false);
|
Shader::sendTextures(info, textures, count, false);
|
||||||
|
|||||||
@@ -68,8 +68,8 @@ int w_reset(lua_State *)
|
|||||||
|
|
||||||
int w_clear(lua_State *L)
|
int w_clear(lua_State *L)
|
||||||
{
|
{
|
||||||
OptionalColorf color(Colorf(0.0f, 0.0f, 0.0f, 0.0f));
|
OptionalColorD color(ColorD(0.0, 0.0, 0.0, 0.0));
|
||||||
std::vector<OptionalColorf> colors;
|
std::vector<OptionalColorD> colors;
|
||||||
|
|
||||||
OptionalInt stencil(0);
|
OptionalInt stencil(0);
|
||||||
OptionalDouble depth(1.0);
|
OptionalDouble depth(1.0);
|
||||||
@@ -93,19 +93,19 @@ int w_clear(lua_State *L)
|
|||||||
}
|
}
|
||||||
else if (argtype == LUA_TNIL || argtype == LUA_TNONE || luax_objlen(L, i + 1) == 0)
|
else if (argtype == LUA_TNIL || argtype == LUA_TNONE || luax_objlen(L, i + 1) == 0)
|
||||||
{
|
{
|
||||||
colors.push_back(OptionalColorf());
|
colors.push_back(OptionalColorD());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 1; j <= 4; j++)
|
for (int j = 1; j <= 4; j++)
|
||||||
lua_rawgeti(L, i + 1, j);
|
lua_rawgeti(L, i + 1, j);
|
||||||
|
|
||||||
OptionalColorf c;
|
OptionalColorD c;
|
||||||
c.hasValue = true;
|
c.hasValue = true;
|
||||||
c.value.r = (float) luaL_checknumber(L, -4);
|
c.value.r = luaL_checknumber(L, -4);
|
||||||
c.value.g = (float) luaL_checknumber(L, -3);
|
c.value.g = luaL_checknumber(L, -3);
|
||||||
c.value.b = (float) luaL_checknumber(L, -2);
|
c.value.b = luaL_checknumber(L, -2);
|
||||||
c.value.a = (float) luaL_optnumber(L, -1, 1.0);
|
c.value.a = luaL_optnumber(L, -1, 1.0);
|
||||||
colors.push_back(c);
|
colors.push_back(c);
|
||||||
|
|
||||||
lua_pop(L, 4);
|
lua_pop(L, 4);
|
||||||
@@ -627,7 +627,7 @@ int w_stencil(lua_State *L)
|
|||||||
luaL_checktype(L, 4, LUA_TBOOLEAN);
|
luaL_checktype(L, 4, LUA_TBOOLEAN);
|
||||||
|
|
||||||
if (stencilclear.hasValue)
|
if (stencilclear.hasValue)
|
||||||
instance()->clear(OptionalColorf(), stencilclear, OptionalDouble());
|
instance()->clear(OptionalColorD(), stencilclear, OptionalDouble());
|
||||||
|
|
||||||
luax_catchexcept(L, [&](){ instance()->drawToStencilBuffer(action, stencilvalue); });
|
luax_catchexcept(L, [&](){ instance()->drawToStencilBuffer(action, stencilvalue); });
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user