mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
Shader uniforms keep their values after love.window.setMode (resolves issue #1174).
Also allow arrays of images/samplers in shaders, although driver support is iffy and you have to index into the array using a compile-time constant (which might exclude loop indexing). --HG-- branch : minor
This commit is contained in:
@@ -151,6 +151,9 @@ Canvas::~Canvas()
|
|||||||
|
|
||||||
bool Canvas::loadVolatile()
|
bool Canvas::loadVolatile()
|
||||||
{
|
{
|
||||||
|
if (texture != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
OpenGL::TempDebugGroup debuggroup("Canvas load");
|
OpenGL::TempDebugGroup debuggroup("Canvas load");
|
||||||
|
|
||||||
fbo = texture = 0;
|
fbo = texture = 0;
|
||||||
|
|||||||
@@ -281,6 +281,9 @@ void Image::loadFromImageData()
|
|||||||
|
|
||||||
bool Image::loadVolatile()
|
bool Image::loadVolatile()
|
||||||
{
|
{
|
||||||
|
if (texture != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
OpenGL::TempDebugGroup debuggroup("Image load");
|
OpenGL::TempDebugGroup debuggroup("Image load");
|
||||||
|
|
||||||
if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB))
|
if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB))
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ public:
|
|||||||
|
|
||||||
enum FramebufferTarget
|
enum FramebufferTarget
|
||||||
{
|
{
|
||||||
FRAMEBUFFER_READ = (1 << 1),
|
FRAMEBUFFER_READ = (1 << 0),
|
||||||
FRAMEBUFFER_DRAW = (1 << 2),
|
FRAMEBUFFER_DRAW = (1 << 1),
|
||||||
FRAMEBUFFER_ALL = (FRAMEBUFFER_READ | FRAMEBUFFER_DRAW),
|
FRAMEBUFFER_ALL = (FRAMEBUFFER_READ | FRAMEBUFFER_DRAW),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,11 +41,12 @@ namespace
|
|||||||
// reattaches the originally active program when destroyed
|
// reattaches the originally active program when destroyed
|
||||||
struct TemporaryAttacher
|
struct TemporaryAttacher
|
||||||
{
|
{
|
||||||
TemporaryAttacher(Shader *shader)
|
TemporaryAttacher(Shader *shader, bool attachNow)
|
||||||
: curShader(shader)
|
: curShader(shader)
|
||||||
, prevShader(Shader::current)
|
, prevShader(Shader::current)
|
||||||
{
|
{
|
||||||
curShader->attach(true);
|
if (attachNow)
|
||||||
|
attach();
|
||||||
}
|
}
|
||||||
|
|
||||||
~TemporaryAttacher()
|
~TemporaryAttacher()
|
||||||
@@ -56,6 +57,11 @@ namespace
|
|||||||
curShader->detach();
|
curShader->detach();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void attach()
|
||||||
|
{
|
||||||
|
curShader->attach(true);
|
||||||
|
}
|
||||||
|
|
||||||
Shader *curShader;
|
Shader *curShader;
|
||||||
Shader *prevShader;
|
Shader *prevShader;
|
||||||
};
|
};
|
||||||
@@ -69,8 +75,6 @@ Shader *Shader::defaultVideoShader = nullptr;
|
|||||||
Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
|
Shader::ShaderSource Shader::defaultCode[Graphics::RENDERER_MAX_ENUM][2];
|
||||||
Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
|
Shader::ShaderSource Shader::defaultVideoCode[Graphics::RENDERER_MAX_ENUM][2];
|
||||||
|
|
||||||
std::vector<int> Shader::textureCounters;
|
|
||||||
|
|
||||||
Shader::Shader(const ShaderSource &source)
|
Shader::Shader(const ShaderSource &source)
|
||||||
: shaderSource(source)
|
: shaderSource(source)
|
||||||
, program(0)
|
, program(0)
|
||||||
@@ -84,10 +88,6 @@ Shader::Shader(const ShaderSource &source)
|
|||||||
if (source.vertex.empty() && source.pixel.empty())
|
if (source.vertex.empty() && source.pixel.empty())
|
||||||
throw love::Exception("Cannot create shader: no source code!");
|
throw love::Exception("Cannot create shader: no source code!");
|
||||||
|
|
||||||
// initialize global texture id counters if needed
|
|
||||||
if ((int) textureCounters.size() < gl.getMaxTextureUnits() - 1)
|
|
||||||
textureCounters.resize(gl.getMaxTextureUnits() - 1, 0);
|
|
||||||
|
|
||||||
// load shader source and create program object
|
// load shader source and create program object
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
}
|
}
|
||||||
@@ -97,12 +97,25 @@ Shader::~Shader()
|
|||||||
if (current == this)
|
if (current == this)
|
||||||
detach();
|
detach();
|
||||||
|
|
||||||
for (const auto &retainable : boundRetainables)
|
|
||||||
retainable.second->release();
|
|
||||||
|
|
||||||
boundRetainables.clear();
|
|
||||||
|
|
||||||
unloadVolatile();
|
unloadVolatile();
|
||||||
|
|
||||||
|
for (const auto &p : uniforms)
|
||||||
|
{
|
||||||
|
// Allocated with malloc().
|
||||||
|
if (p.second.data != nullptr)
|
||||||
|
free(p.second.data);
|
||||||
|
|
||||||
|
if (p.second.baseType == UNIFORM_SAMPLER)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < p.second.count; i++)
|
||||||
|
{
|
||||||
|
if (p.second.textures[i] != nullptr)
|
||||||
|
p.second.textures[i]->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] p.second.textures;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
|
GLuint Shader::compileCode(ShaderStage stage, const std::string &code)
|
||||||
@@ -176,8 +189,6 @@ void Shader::mapActiveUniforms()
|
|||||||
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
||||||
builtinUniforms[i] = -1;
|
builtinUniforms[i] = -1;
|
||||||
|
|
||||||
uniforms.clear();
|
|
||||||
|
|
||||||
GLint activeprogram = 0;
|
GLint activeprogram = 0;
|
||||||
glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
|
glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram);
|
||||||
|
|
||||||
@@ -189,6 +200,9 @@ void Shader::mapActiveUniforms()
|
|||||||
GLchar cname[256];
|
GLchar cname[256];
|
||||||
const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
|
const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar));
|
||||||
|
|
||||||
|
std::map<std::string, UniformInfo> olduniforms = uniforms;
|
||||||
|
uniforms.clear();
|
||||||
|
|
||||||
for (int i = 0; i < numuniforms; i++)
|
for (int i = 0; i < numuniforms; i++)
|
||||||
{
|
{
|
||||||
GLsizei namelen = 0;
|
GLsizei namelen = 0;
|
||||||
@@ -206,12 +220,6 @@ void Shader::mapActiveUniforms()
|
|||||||
else
|
else
|
||||||
u.components = getUniformTypeComponents(gltype);
|
u.components = getUniformTypeComponents(gltype);
|
||||||
|
|
||||||
// Initialize all samplers to 0. Both GLSL and GLSL ES are supposed to
|
|
||||||
// do this themselves, but some Android devices (galaxy tab 3 and 4)
|
|
||||||
// don't seem to do it...
|
|
||||||
if (u.baseType == UNIFORM_SAMPLER)
|
|
||||||
glUniform1i(u.location, 0);
|
|
||||||
|
|
||||||
// glGetActiveUniform appends "[0]" to the end of array uniform names...
|
// glGetActiveUniform appends "[0]" to the end of array uniform names...
|
||||||
if (u.name.length() > 3)
|
if (u.name.length() > 3)
|
||||||
{
|
{
|
||||||
@@ -225,8 +233,135 @@ void Shader::mapActiveUniforms()
|
|||||||
if (builtinNames.find(u.name.c_str(), builtin))
|
if (builtinNames.find(u.name.c_str(), builtin))
|
||||||
builtinUniforms[int(builtin)] = u.location;
|
builtinUniforms[int(builtin)] = u.location;
|
||||||
|
|
||||||
if (u.location != -1)
|
if (u.location == -1)
|
||||||
uniforms[u.name] = u;
|
continue;
|
||||||
|
|
||||||
|
// Make sure previously set uniform data is preserved, and shader-
|
||||||
|
// initialized values are retrieved.
|
||||||
|
auto oldu = olduniforms.find(u.name);
|
||||||
|
if (oldu != olduniforms.end())
|
||||||
|
{
|
||||||
|
u.data = oldu->second.data;
|
||||||
|
u.textures = oldu->second.textures;
|
||||||
|
|
||||||
|
updateUniform(&u, u.count, true);
|
||||||
|
|
||||||
|
if (u.baseType == UNIFORM_SAMPLER)
|
||||||
|
{
|
||||||
|
// Make sure all stored textures have their Volatiles loaded
|
||||||
|
// before the sendTextures call, since it calls getHandle().
|
||||||
|
for (int i = 0; i < u.count; i++)
|
||||||
|
{
|
||||||
|
if (u.textures[i] == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
|
||||||
|
if (v != nullptr)
|
||||||
|
v->loadVolatile();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTextures(&u, u.textures, u.count, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t datasize = 0;
|
||||||
|
|
||||||
|
switch (u.baseType)
|
||||||
|
{
|
||||||
|
case UNIFORM_FLOAT:
|
||||||
|
datasize = sizeof(float) * u.components * u.count;
|
||||||
|
u.data = malloc(datasize);
|
||||||
|
break;
|
||||||
|
case UNIFORM_INT:
|
||||||
|
case UNIFORM_BOOL:
|
||||||
|
case UNIFORM_SAMPLER:
|
||||||
|
datasize = sizeof(int) * u.components * u.count;
|
||||||
|
u.data = malloc(datasize);
|
||||||
|
break;
|
||||||
|
case UNIFORM_MATRIX:
|
||||||
|
datasize = sizeof(float) * (u.matrix.rows * u.matrix.columns) * u.count;
|
||||||
|
u.data = malloc(datasize);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datasize > 0)
|
||||||
|
{
|
||||||
|
memset(u.data, 0, datasize);
|
||||||
|
|
||||||
|
if (u.baseType == UNIFORM_SAMPLER)
|
||||||
|
{
|
||||||
|
// Initialize all samplers to 0. Both GLSL and GLSL ES are
|
||||||
|
// supposed to do this themselves, but some Android devices
|
||||||
|
// (galaxy tab 3 and 4) don't seem to do it...
|
||||||
|
glUniform1iv(u.location, u.count, u.ints);
|
||||||
|
|
||||||
|
u.textures = new Texture*[u.count];
|
||||||
|
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
// Store any shader-initialized values in our own memory.
|
||||||
|
for (int i = 0; i < u.count; i++)
|
||||||
|
{
|
||||||
|
GLint location = u.location;
|
||||||
|
|
||||||
|
if (u.count > 1)
|
||||||
|
{
|
||||||
|
std::string indexname = u.name + "[" + std::to_string(i) + "]";
|
||||||
|
location = glGetUniformLocation(program, indexname.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (u.baseType)
|
||||||
|
{
|
||||||
|
case UNIFORM_FLOAT:
|
||||||
|
glGetUniformfv(program, location, &u.floats[offset]);
|
||||||
|
offset += u.components;
|
||||||
|
break;
|
||||||
|
case UNIFORM_INT:
|
||||||
|
case UNIFORM_BOOL:
|
||||||
|
glGetUniformiv(program, location, &u.ints[offset]);
|
||||||
|
offset += u.components;
|
||||||
|
break;
|
||||||
|
case UNIFORM_MATRIX:
|
||||||
|
glGetUniformfv(program, location, &u.floats[offset]);
|
||||||
|
offset += u.matrix.rows * u.matrix.columns;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uniforms[u.name] = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure uniforms that existed before but don't exist anymore are
|
||||||
|
// cleaned up. This theoretically shouldn't happen, but...
|
||||||
|
for (const auto &p : olduniforms)
|
||||||
|
{
|
||||||
|
if (uniforms.find(p.first) == uniforms.end())
|
||||||
|
{
|
||||||
|
free(p.second.data);
|
||||||
|
|
||||||
|
if (p.second.baseType != UNIFORM_SAMPLER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (int i = 0; i < p.second.count; i++)
|
||||||
|
{
|
||||||
|
if (p.second.textures[i] != nullptr)
|
||||||
|
p.second.textures[i]->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] p.second.textures;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gl.useProgram(activeprogram);
|
gl.useProgram(activeprogram);
|
||||||
@@ -251,8 +386,8 @@ bool Shader::loadVolatile()
|
|||||||
videoTextureUnits[i] = 0;
|
videoTextureUnits[i] = 0;
|
||||||
|
|
||||||
// zero out active texture list
|
// zero out active texture list
|
||||||
activeTexUnits.clear();
|
textureUnits.clear();
|
||||||
activeTexUnits.insert(activeTexUnits.begin(), gl.getMaxTextureUnits() - 1, 0);
|
textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
|
||||||
|
|
||||||
std::vector<GLuint> shaderids;
|
std::vector<GLuint> shaderids;
|
||||||
|
|
||||||
@@ -348,22 +483,12 @@ void Shader::unloadVolatile()
|
|||||||
program = 0;
|
program = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrement global texture id counters for texture units which had textures bound from this shader
|
|
||||||
for (size_t i = 0; i < activeTexUnits.size(); ++i)
|
|
||||||
{
|
|
||||||
if (activeTexUnits[i] > 0)
|
|
||||||
textureCounters[i] = std::max(textureCounters[i] - 1, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// active texture list is probably invalid, clear it
|
// active texture list is probably invalid, clear it
|
||||||
activeTexUnits.clear();
|
textureUnits.clear();
|
||||||
activeTexUnits.resize(gl.getMaxTextureUnits() - 1, 0);
|
textureUnits.resize(gl.getMaxTextureUnits(), TextureUnit());
|
||||||
|
|
||||||
attributes.clear();
|
attributes.clear();
|
||||||
|
|
||||||
// same with uniform location list
|
|
||||||
uniforms.clear();
|
|
||||||
|
|
||||||
// And the locations of any built-in uniform variables.
|
// And the locations of any built-in uniform variables.
|
||||||
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
for (int i = 0; i < int(BUILTIN_MAX_ENUM); i++)
|
||||||
builtinUniforms[i] = -1;
|
builtinUniforms[i] = -1;
|
||||||
@@ -420,10 +545,10 @@ void Shader::attach(bool temporary)
|
|||||||
{
|
{
|
||||||
// make sure all sent textures are properly bound to their respective texture units
|
// make sure all sent textures are properly bound to their respective texture units
|
||||||
// note: list potentially contains texture ids of deleted/invalid textures!
|
// note: list potentially contains texture ids of deleted/invalid textures!
|
||||||
for (int i = 0; i < (int) activeTexUnits.size(); ++i)
|
for (int i = 1; i < (int) textureUnits.size(); ++i)
|
||||||
{
|
{
|
||||||
if (activeTexUnits[i] > 0)
|
if (textureUnits[i].active)
|
||||||
gl.bindTextureToUnit(activeTexUnits[i], i + 1, false);
|
gl.bindTextureToUnit(textureUnits[i].texture, i, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,160 +580,148 @@ const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const
|
|||||||
return &(it->second);
|
return &(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::sendInts(const UniformInfo *info, const int *vec, int count)
|
void Shader::updateUniform(const UniformInfo *info, int count, bool internalUpdate)
|
||||||
{
|
{
|
||||||
if (info->baseType != UNIFORM_INT && info->baseType != UNIFORM_BOOL)
|
TemporaryAttacher attacher(this, !internalUpdate);
|
||||||
return;
|
|
||||||
|
|
||||||
TemporaryAttacher attacher(this);
|
|
||||||
|
|
||||||
int location = info->location;
|
int location = info->location;
|
||||||
|
UniformType type = info->baseType;
|
||||||
|
|
||||||
switch (info->components)
|
if (type == UNIFORM_FLOAT)
|
||||||
{
|
{
|
||||||
case 4:
|
switch (info->components)
|
||||||
glUniform4iv(location, count, vec);
|
{
|
||||||
break;
|
case 1:
|
||||||
case 3:
|
glUniform1fv(location, count, info->floats);
|
||||||
glUniform3iv(location, count, vec);
|
break;
|
||||||
break;
|
case 2:
|
||||||
case 2:
|
glUniform2fv(location, count, info->floats);
|
||||||
glUniform2iv(location, count, vec);
|
break;
|
||||||
break;
|
case 3:
|
||||||
case 1:
|
glUniform3fv(location, count, info->floats);
|
||||||
default:
|
break;
|
||||||
glUniform1iv(location, count, vec);
|
case 4:
|
||||||
break;
|
glUniform4fv(location, count, info->floats);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
|
||||||
|
{
|
||||||
|
switch (info->components)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
glUniform1iv(location, count, info->ints);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
glUniform2iv(location, count, info->ints);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
glUniform3iv(location, count, info->ints);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
glUniform4iv(location, count, info->ints);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (type == UNIFORM_MATRIX)
|
||||||
|
{
|
||||||
|
int columns = info->matrix.columns;
|
||||||
|
int rows = info->matrix.rows;
|
||||||
|
|
||||||
|
if (columns == 2 && rows == 2)
|
||||||
|
glUniformMatrix2fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 3 && rows == 3)
|
||||||
|
glUniformMatrix3fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 4 && rows == 4)
|
||||||
|
glUniformMatrix4fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 2 && rows == 3)
|
||||||
|
glUniformMatrix2x3fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 2 && rows == 4)
|
||||||
|
glUniformMatrix2x4fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 3 && rows == 2)
|
||||||
|
glUniformMatrix3x2fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 3 && rows == 4)
|
||||||
|
glUniformMatrix3x4fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 4 && rows == 2)
|
||||||
|
glUniformMatrix4x2fv(location, count, GL_FALSE, info->floats);
|
||||||
|
else if (columns == 4 && rows == 3)
|
||||||
|
glUniformMatrix4x3fv(location, count, GL_FALSE, info->floats);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::sendFloats(const UniformInfo *info, const float *vec, int count)
|
int Shader::getFreeTextureUnits(int count)
|
||||||
{
|
{
|
||||||
if (info->baseType != UNIFORM_FLOAT && info->baseType != UNIFORM_BOOL)
|
int startunit = -1;
|
||||||
return;
|
|
||||||
|
|
||||||
TemporaryAttacher attacher(this);
|
// Ignore the first texture unit for Shader-local texture bindings.
|
||||||
|
for (int i = 1; i < (int) textureUnits.size(); i++)
|
||||||
int location = info->location;
|
|
||||||
|
|
||||||
switch (info->components)
|
|
||||||
{
|
{
|
||||||
case 4:
|
if (!textureUnits[i].active && i + count <= (int) textureUnits.size())
|
||||||
glUniform4fv(location, count, vec);
|
{
|
||||||
break;
|
startunit = i;
|
||||||
case 3:
|
break;
|
||||||
glUniform3fv(location, count, vec);
|
}
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
glUniform2fv(location, count, vec);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
default:
|
|
||||||
glUniform1fv(location, count, vec);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (startunit == -1)
|
||||||
|
throw love::Exception("No more texture units available for shader.");
|
||||||
|
|
||||||
|
return startunit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::sendMatrices(const UniformInfo *info, const float *m, int count)
|
void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate)
|
||||||
{
|
|
||||||
if (info->baseType != UNIFORM_MATRIX)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TemporaryAttacher attacher(this);
|
|
||||||
|
|
||||||
int location = info->location;
|
|
||||||
|
|
||||||
int columns = info->matrix.columns;
|
|
||||||
int rows = info->matrix.rows;
|
|
||||||
|
|
||||||
if (columns == 2 && rows == 2)
|
|
||||||
glUniformMatrix2fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 3 && rows == 3)
|
|
||||||
glUniformMatrix3fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 4 && rows == 4)
|
|
||||||
glUniformMatrix4fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 2 && rows == 3)
|
|
||||||
glUniformMatrix2x3fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 2 && rows == 4)
|
|
||||||
glUniformMatrix2x4fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 3 && rows == 2)
|
|
||||||
glUniformMatrix3x2fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 3 && rows == 4)
|
|
||||||
glUniformMatrix3x4fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 4 && rows == 2)
|
|
||||||
glUniformMatrix4x2fv(location, count, GL_FALSE, m);
|
|
||||||
else if (columns == 4 && rows == 3)
|
|
||||||
glUniformMatrix4x3fv(location, count, GL_FALSE, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::sendTexture(const UniformInfo *info, Texture *texture)
|
|
||||||
{
|
{
|
||||||
if (info->baseType != UNIFORM_SAMPLER)
|
if (info->baseType != UNIFORM_SAMPLER)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
GLuint gltex = *(GLuint *) texture->getHandle();
|
count = std::min(count, info->count);
|
||||||
|
bool updateuniform = false;
|
||||||
|
|
||||||
TemporaryAttacher attacher(this);
|
// Make sure the shader's samplers are associated with texture units.
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
int texunit = getTextureUnit(info->name);
|
|
||||||
|
|
||||||
// bind texture to assigned texture unit and send uniform to shader program
|
|
||||||
gl.bindTextureToUnit(gltex, texunit, false);
|
|
||||||
|
|
||||||
glUniform1i(info->location, texunit);
|
|
||||||
|
|
||||||
// increment global shader texture id counter for this texture unit, if we haven't already
|
|
||||||
if (activeTexUnits[texunit-1] == 0)
|
|
||||||
++textureCounters[texunit-1];
|
|
||||||
|
|
||||||
// store texture id so it can be re-bound to the proper texture unit later
|
|
||||||
activeTexUnits[texunit-1] = gltex;
|
|
||||||
|
|
||||||
retainObject(info->name, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shader::retainObject(const std::string &name, Object *object)
|
|
||||||
{
|
|
||||||
object->retain();
|
|
||||||
|
|
||||||
auto it = boundRetainables.find(name);
|
|
||||||
if (it != boundRetainables.end())
|
|
||||||
it->second->release();
|
|
||||||
|
|
||||||
boundRetainables[name] = object;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Shader::getTextureUnit(const std::string &name)
|
|
||||||
{
|
|
||||||
auto it = texUnitPool.find(name);
|
|
||||||
|
|
||||||
if (it != texUnitPool.end())
|
|
||||||
return it->second;
|
|
||||||
|
|
||||||
int texunit = 1;
|
|
||||||
|
|
||||||
// prefer texture units which are unused by all other shaders
|
|
||||||
auto freeunit_it = std::find(textureCounters.begin(), textureCounters.end(), 0);
|
|
||||||
|
|
||||||
if (freeunit_it != textureCounters.end())
|
|
||||||
{
|
{
|
||||||
// we don't want to use unit 0
|
if (info->ints[i] == 0 && textures[i] != nullptr)
|
||||||
texunit = (int) std::distance(textureCounters.begin(), freeunit_it) + 1;
|
{
|
||||||
}
|
int texunit = getFreeTextureUnits(1);
|
||||||
else
|
textureUnits[texunit].active = true;
|
||||||
{
|
|
||||||
// no completely unused texture units exist, try to use next free slot in our own list
|
|
||||||
auto nextunit_it = std::find(activeTexUnits.begin(), activeTexUnits.end(), 0);
|
|
||||||
|
|
||||||
if (nextunit_it == activeTexUnits.end())
|
info->ints[i] = texunit;
|
||||||
throw love::Exception("No more texture units available for shader.");
|
updateuniform = true;
|
||||||
|
}
|
||||||
// we don't want to use unit 0
|
|
||||||
texunit = (int) std::distance(activeTexUnits.begin(), nextunit_it) + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
texUnitPool[name] = texunit;
|
if (updateuniform)
|
||||||
return texunit;
|
updateUniform(info, count, internalUpdate);
|
||||||
|
|
||||||
|
// Bind the textures to the texture units.
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (textures[i] != nullptr)
|
||||||
|
textures[i]->retain();
|
||||||
|
|
||||||
|
if (info->textures[i] != nullptr)
|
||||||
|
info->textures[i]->release();
|
||||||
|
|
||||||
|
info->textures[i] = textures[i];
|
||||||
|
|
||||||
|
int texunit = info->ints[i];
|
||||||
|
|
||||||
|
if (textures[i] != nullptr)
|
||||||
|
{
|
||||||
|
GLuint gltex = *(GLuint *) textures[i]->getHandle();
|
||||||
|
|
||||||
|
gl.bindTextureToUnit(gltex, texunit, false);
|
||||||
|
|
||||||
|
// store texture id so it can be re-bound to the proper texture unit later
|
||||||
|
textureUnits[texunit].texture = gltex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gl.bindTextureToUnit(0, texunit, false);
|
||||||
|
textureUnits[texunit].texture = 0;
|
||||||
|
textureUnits[texunit].active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Shader::hasUniform(const std::string &name) const
|
bool Shader::hasUniform(const std::string &name) const
|
||||||
@@ -635,12 +748,12 @@ bool Shader::hasVertexAttrib(VertexAttribID attrib) const
|
|||||||
|
|
||||||
void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
|
void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtexture)
|
||||||
{
|
{
|
||||||
TemporaryAttacher attacher(this);
|
|
||||||
|
|
||||||
// Set up the texture units that will be used by the shader to sample from
|
// Set up the texture units that will be used by the shader to sample from
|
||||||
// the textures, if they haven't been set up yet.
|
// the textures, if they haven't been set up yet.
|
||||||
if (videoTextureUnits[0] == 0)
|
if (videoTextureUnits[0] == 0)
|
||||||
{
|
{
|
||||||
|
TemporaryAttacher attacher(this, true);
|
||||||
|
|
||||||
const GLint locs[3] = {
|
const GLint locs[3] = {
|
||||||
builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
|
builtinUniforms[BUILTIN_VIDEO_Y_CHANNEL],
|
||||||
builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
|
builtinUniforms[BUILTIN_VIDEO_CB_CHANNEL],
|
||||||
@@ -656,14 +769,15 @@ void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtextur
|
|||||||
{
|
{
|
||||||
if (locs[i] >= 0 && names[i] != nullptr)
|
if (locs[i] >= 0 && names[i] != nullptr)
|
||||||
{
|
{
|
||||||
videoTextureUnits[i] = getTextureUnit(names[i]);
|
const UniformInfo *info = getUniformInfo(names[i]);
|
||||||
|
if (info != nullptr)
|
||||||
|
{
|
||||||
|
videoTextureUnits[i] = getFreeTextureUnits(1);
|
||||||
|
textureUnits[videoTextureUnits[i]].active = true;
|
||||||
|
|
||||||
// Increment global shader texture id counter for this texture
|
info->ints[0] = videoTextureUnits[i];
|
||||||
// unit, if we haven't already.
|
updateUniform(info, 1);
|
||||||
if (activeTexUnits[videoTextureUnits[i] - 1] == 0)
|
}
|
||||||
++textureCounters[videoTextureUnits[i] - 1];
|
|
||||||
|
|
||||||
glUniform1i(locs[i], videoTextureUnits[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -676,7 +790,7 @@ void Shader::setVideoTextures(GLuint ytexture, GLuint cbtexture, GLuint crtextur
|
|||||||
if (videoTextureUnits[i] != 0)
|
if (videoTextureUnits[i] != 0)
|
||||||
{
|
{
|
||||||
// Store texture id so it can be re-bound later.
|
// Store texture id so it can be re-bound later.
|
||||||
activeTexUnits[videoTextureUnits[i] - 1] = textures[i];
|
textureUnits[videoTextureUnits[i]].texture = textures[i];
|
||||||
gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
|
gl.bindTextureToUnit(textures[i], videoTextureUnits[i], false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -718,7 +832,7 @@ void Shader::checkSetScreenParams()
|
|||||||
|
|
||||||
if (location >= 0)
|
if (location >= 0)
|
||||||
{
|
{
|
||||||
TemporaryAttacher attacher(this);
|
TemporaryAttacher attacher(this, true);
|
||||||
glUniform4fv(location, 1, params);
|
glUniform4fv(location, 1, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,7 +849,7 @@ void Shader::checkSetPointSize(float size)
|
|||||||
|
|
||||||
if (location >= 0)
|
if (location >= 0)
|
||||||
{
|
{
|
||||||
TemporaryAttacher attacher(this);
|
TemporaryAttacher attacher(this, true);
|
||||||
glUniform1f(location, size);
|
glUniform1f(location, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,7 +869,7 @@ void Shader::checkSetBuiltinUniforms()
|
|||||||
const Matrix4 &curxform = gl.matrices.transform.back();
|
const Matrix4 &curxform = gl.matrices.transform.back();
|
||||||
const Matrix4 &curproj = gl.matrices.projection;
|
const Matrix4 &curproj = gl.matrices.projection;
|
||||||
|
|
||||||
TemporaryAttacher attacher(this);
|
TemporaryAttacher attacher(this, true);
|
||||||
|
|
||||||
bool tpmatrixneedsupdate = false;
|
bool tpmatrixneedsupdate = false;
|
||||||
|
|
||||||
@@ -802,11 +916,6 @@ void Shader::checkSetBuiltinUniforms()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<std::string, Object *> &Shader::getBoundRetainables() const
|
|
||||||
{
|
|
||||||
return boundRetainables;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Shader::getGLSLVersion()
|
std::string Shader::getGLSLVersion()
|
||||||
{
|
{
|
||||||
const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
|
const char *tmp = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
|
||||||
|
|||||||
@@ -96,13 +96,24 @@ public:
|
|||||||
{
|
{
|
||||||
int location;
|
int location;
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int components;
|
int components;
|
||||||
MatrixSize matrix;
|
MatrixSize matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
UniformType baseType;
|
UniformType baseType;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
float *floats;
|
||||||
|
int *ints;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture **textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Pointer to currently active Shader.
|
// Pointer to currently active Shader.
|
||||||
@@ -147,11 +158,9 @@ public:
|
|||||||
std::string getWarnings() const;
|
std::string getWarnings() const;
|
||||||
|
|
||||||
const UniformInfo *getUniformInfo(const std::string &name) const;
|
const UniformInfo *getUniformInfo(const std::string &name) const;
|
||||||
|
void updateUniform(const UniformInfo *info, int count, bool internalUpdate = false);
|
||||||
|
|
||||||
void sendInts(const UniformInfo *info, const int *vec, int count);
|
void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate = false);
|
||||||
void sendFloats(const UniformInfo *info, const float *vec, int count);
|
|
||||||
void sendMatrices(const UniformInfo *info, const float *m, int count);
|
|
||||||
void sendTexture(const UniformInfo *info, Texture *texture);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether a uniform with the specified name exists and is actively
|
* Gets whether a uniform with the specified name exists and is actively
|
||||||
@@ -171,24 +180,11 @@ public:
|
|||||||
void checkSetPointSize(float size);
|
void checkSetPointSize(float size);
|
||||||
void checkSetBuiltinUniforms();
|
void checkSetBuiltinUniforms();
|
||||||
|
|
||||||
const std::map<std::string, Object *> &getBoundRetainables() const;
|
|
||||||
|
|
||||||
GLuint getProgram() const
|
GLuint getProgram() const
|
||||||
{
|
{
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T *getScratchBuffer(size_t count)
|
|
||||||
{
|
|
||||||
size_t bytes = sizeof(T) * count;
|
|
||||||
|
|
||||||
if (scratchBuffer.size() < bytes)
|
|
||||||
scratchBuffer.resize(bytes);
|
|
||||||
|
|
||||||
return (T *) scratchBuffer.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string getGLSLVersion();
|
static std::string getGLSLVersion();
|
||||||
static bool isSupported();
|
static bool isSupported();
|
||||||
|
|
||||||
@@ -200,6 +196,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
struct TextureUnit
|
||||||
|
{
|
||||||
|
GLuint texture = 0;
|
||||||
|
bool active = false;
|
||||||
|
};
|
||||||
|
|
||||||
// Map active uniform names to their locations.
|
// Map active uniform names to their locations.
|
||||||
void mapActiveUniforms();
|
void mapActiveUniforms();
|
||||||
|
|
||||||
@@ -209,9 +211,7 @@ private:
|
|||||||
|
|
||||||
GLuint compileCode(ShaderStage stage, const std::string &code);
|
GLuint compileCode(ShaderStage stage, const std::string &code);
|
||||||
|
|
||||||
int getTextureUnit(const std::string &name);
|
int getFreeTextureUnits(int count);
|
||||||
|
|
||||||
void retainObject(const std::string &name, Object *object);
|
|
||||||
|
|
||||||
// Get any warnings or errors generated only by the shader program object.
|
// Get any warnings or errors generated only by the shader program object.
|
||||||
std::string getProgramWarnings() const;
|
std::string getProgramWarnings() const;
|
||||||
@@ -237,11 +237,7 @@ private:
|
|||||||
std::map<std::string, UniformInfo> uniforms;
|
std::map<std::string, UniformInfo> uniforms;
|
||||||
|
|
||||||
// Texture unit pool for setting images
|
// Texture unit pool for setting images
|
||||||
std::map<std::string, GLint> texUnitPool; // texUnitPool[name] = textureunit
|
std::vector<TextureUnit> textureUnits;
|
||||||
std::vector<GLuint> activeTexUnits; // activeTexUnits[textureunit-1] = textureid
|
|
||||||
|
|
||||||
// Uniform name to retainable objects
|
|
||||||
std::map<std::string, Object*> boundRetainables;
|
|
||||||
|
|
||||||
bool canvasWasActive;
|
bool canvasWasActive;
|
||||||
OpenGL::Viewport lastViewport;
|
OpenGL::Viewport lastViewport;
|
||||||
@@ -253,11 +249,6 @@ private:
|
|||||||
|
|
||||||
GLuint videoTextureUnits[3];
|
GLuint videoTextureUnits[3];
|
||||||
|
|
||||||
std::vector<char> scratchBuffer;
|
|
||||||
|
|
||||||
// Counts total number of textures bound to each texture unit in all shaders
|
|
||||||
static std::vector<int> textureCounters;
|
|
||||||
|
|
||||||
static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
|
static StringMap<ShaderStage, STAGE_MAX_ENUM>::Entry stageNameEntries[];
|
||||||
static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
|
static StringMap<ShaderStage, STAGE_MAX_ENUM> stageNames;
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,8 @@ static int _getCount(lua_State *L, int startidx, const Shader::UniformInfo *info
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T *_getNumbers(lua_State *L, int startidx, Shader *shader, int components, int count)
|
static void _updateNumbers(lua_State *L, int startidx, T *values, int components, int count)
|
||||||
{
|
{
|
||||||
T *values = shader->getScratchBuffer<T>(components * count);
|
|
||||||
|
|
||||||
if (components == 1)
|
if (components == 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; ++i)
|
for (int i = 0; i < count; ++i)
|
||||||
@@ -76,16 +74,15 @@ static T *_getNumbers(lua_State *L, int startidx, Shader *shader, int components
|
|||||||
lua_pop(L, components);
|
lua_pop(L, components);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info, bool colors)
|
int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info, bool colors)
|
||||||
{
|
{
|
||||||
int count = _getCount(L, startidx, info);
|
int count = _getCount(L, startidx, info);
|
||||||
int components = info->components;
|
int components = info->components;
|
||||||
|
float *values = info->floats;
|
||||||
|
|
||||||
float *values = _getNumbers<float>(L, startidx, shader, components, count);
|
_updateNumbers(L, startidx, values, components, count);
|
||||||
|
|
||||||
if (colors && graphics::isGammaCorrect())
|
if (colors && graphics::isGammaCorrect())
|
||||||
{
|
{
|
||||||
@@ -99,15 +96,15 @@ int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
luax_catchexcept(L, [&]() { shader->sendFloats(info, values, count); });
|
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Shader_sendInts(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
int w_Shader_sendInts(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||||
{
|
{
|
||||||
int count = _getCount(L, startidx, info);
|
int count = _getCount(L, startidx, info);
|
||||||
int *values = _getNumbers<int>(L, startidx, shader, info->components, count);
|
_updateNumbers(L, startidx, info->ints, info->components, count);
|
||||||
luax_catchexcept(L, [&]() { shader->sendInts(info, values, count); });
|
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,15 +113,15 @@ int w_Shader_sendBooleans(lua_State *L, int startidx, Shader *shader, const Shad
|
|||||||
int count = _getCount(L, startidx, info);
|
int count = _getCount(L, startidx, info);
|
||||||
int components = info->components;
|
int components = info->components;
|
||||||
|
|
||||||
// We have to send booleans as ints or floats.
|
// We have to send booleans as ints.
|
||||||
float *values = shader->getScratchBuffer<float>(components * count);
|
int *values = info->ints;
|
||||||
|
|
||||||
if (components == 1)
|
if (components == 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
luaL_checktype(L, startidx + i, LUA_TBOOLEAN);
|
luaL_checktype(L, startidx + i, LUA_TBOOLEAN);
|
||||||
values[i] = (float) lua_toboolean(L, startidx + i);
|
values[i] = (int) lua_toboolean(L, startidx + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -137,14 +134,14 @@ int w_Shader_sendBooleans(lua_State *L, int startidx, Shader *shader, const Shad
|
|||||||
{
|
{
|
||||||
lua_rawgeti(L, startidx + i, k);
|
lua_rawgeti(L, startidx + i, k);
|
||||||
luaL_checktype(L, -1, LUA_TBOOLEAN);
|
luaL_checktype(L, -1, LUA_TBOOLEAN);
|
||||||
values[i * components + k - 1] = (float) lua_toboolean(L, -1);
|
values[i * components + k - 1] = (int) lua_toboolean(L, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
lua_pop(L, components);
|
lua_pop(L, components);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
luax_catchexcept(L, [&]() { shader->sendFloats(info, values, count); });
|
luax_catchexcept(L, [&]() { shader->updateUniform(info, count); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +160,7 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad
|
|||||||
int rows = info->matrix.rows;
|
int rows = info->matrix.rows;
|
||||||
int elements = columns * rows;
|
int elements = columns * rows;
|
||||||
|
|
||||||
float *values = shader->getScratchBuffer<float>(elements * count);
|
float *values = info->floats;
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
@@ -243,15 +240,21 @@ int w_Shader_sendMatrices(lua_State *L, int startidx, Shader *shader, const Shad
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shader->sendMatrices(info, values, count);
|
shader->updateUniform(info, count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Shader_sendTexture(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
int w_Shader_sendTextures(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||||
{
|
{
|
||||||
// We don't support arrays of textures (yet).
|
int count = _getCount(L, startidx, info);
|
||||||
Texture *texture = luax_checktexture(L, startidx);
|
|
||||||
luax_catchexcept(L, [&]() { shader->sendTexture(info, texture); });
|
std::vector<Texture *> textures;
|
||||||
|
textures.reserve(count);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
textures.push_back(luax_checktexture(L, startidx + i));
|
||||||
|
|
||||||
|
luax_catchexcept(L, [&]() { shader->sendTextures(info, textures.data(), count); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +280,7 @@ int w_Shader_send(lua_State *L)
|
|||||||
case Shader::UNIFORM_BOOL:
|
case Shader::UNIFORM_BOOL:
|
||||||
return w_Shader_sendBooleans(L, startidx, shader, info);
|
return w_Shader_sendBooleans(L, startidx, shader, info);
|
||||||
case Shader::UNIFORM_SAMPLER:
|
case Shader::UNIFORM_SAMPLER:
|
||||||
return w_Shader_sendTexture(L, startidx, shader, info);
|
return w_Shader_sendTextures(L, startidx, shader, info);
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "Unknown variable type for shader uniform '%s", name);
|
return luaL_error(L, "Unknown variable type for shader uniform '%s", name);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user