Skip to content
...@@ -54,7 +54,16 @@ bool RenderDispatcher::dispatchNoRecurse(const std::unordered_set<GUIElement*>& ...@@ -54,7 +54,16 @@ bool RenderDispatcher::dispatchNoRecurse(const std::unordered_set<GUIElement*>&
instances.clear(); instances.clear();
instancesClear.clear(); instancesClear.clear();
for (auto& element : elements) {
if (!element->dirty || !element->updateOverlaps) continue;
Rect bounds = element->getBounds(false);
for (auto& elementClip : elements) {
if (elementClip->dirty) continue;
if (!elementClip->getBounds(false).overlaps(bounds)) continue;
elementClip->dirty = 1;
//SDL_Log("RenderDispatcher::dispatchNoRecurse collide %i %i", (int)&element, (int)&elementClip);
}
}
for (auto& element : elements) { for (auto& element : elements) {
if (!element->dirty) continue; if (!element->dirty) continue;
size_t appendSize = element->getInstanceCount(); size_t appendSize = element->getInstanceCount();
...@@ -66,9 +75,12 @@ bool RenderDispatcher::dispatchNoRecurse(const std::unordered_set<GUIElement*>& ...@@ -66,9 +75,12 @@ bool RenderDispatcher::dispatchNoRecurse(const std::unordered_set<GUIElement*>&
size_t appendSize = element->getInstanceCount(); size_t appendSize = element->getInstanceCount();
Span<Instance> newInstances = instances.appendGetEnd(appendSize); Span<Instance> newInstances = instances.appendGetEnd(appendSize);
element->populateInstances(newInstances); element->populateInstances(newInstances);
if (element->updateOverlaps)
for (size_t i = 0; i < appendSize; i++)
newInstances[i].depth += element->depth;
element->dirty -= 1; element->dirty -= 1;
instancesClear.append(InstanceDataFlat{ instancesClear.append(InstanceDataFlat{
element->getBounds(true), clearColor (RectU)element->getBounds(true), clearColor
}); });
} }
if (instances.size() == 0) return false; if (instances.size() == 0) return false;
...@@ -99,10 +111,10 @@ void RenderDispatcher::updateUniforms(SDL_Window* window, Vec2 offset) { ...@@ -99,10 +111,10 @@ void RenderDispatcher::updateUniforms(SDL_Window* window, Vec2 offset) {
0, 0, -1, 0, 0, 0, -1, 0,
-1 - offset.x * wI * 2.0f, 1 + offset.y * hI * 2.0f, 0, 1 -1 - offset.x * wI * 2.0f, 1 + offset.y * hI * 2.0f, 0, 1
}; };
commonUniforms.projection->set(ortho); projection.set(ortho);
timeMS = SDL_GetTicks(); timeMS = SDL_GetTicks();
commonUniforms.time->value = (uint32_t)timeMS; time.value = (uint32_t)timeMS;
} }
bool RenderDispatcher::handleMouse(const std::unordered_set<GUIElement*>& elements, MouseButton button, MouseInput input, Vec2 pos, uint32_t index) { bool RenderDispatcher::handleMouse(const std::unordered_set<GUIElement*>& elements, MouseButton button, MouseInput input, Vec2 pos, uint32_t index) {
pos = Vec2(offset.x + pos.x, offset.y + pos.y); pos = Vec2(offset.x + pos.x, offset.y + pos.y);
...@@ -156,23 +168,27 @@ bool RenderDispatcher::handleWheel(const std::unordered_set<GUIElement*>& elemen ...@@ -156,23 +168,27 @@ bool RenderDispatcher::handleWheel(const std::unordered_set<GUIElement*>& elemen
void orderObjects(Instance* arr, size_t n) { void orderObjects(Instance* arr, size_t n) {
for (size_t i = 0; i < n; i++) for (size_t i = 0; i < n; i++) if (arr->skip) arr->depth = -1;
if (arr->skip) arr->depth = -1; //Sort by depth
// Step 1: Sort by depth only (stable sort to keep original order in equal depths)
// We do stable sort so relative order inside equal depth remains for grouping later
std::stable_sort(arr, arr + n, [](const Instance& a, const Instance& b) { std::stable_sort(arr, arr + n, [](const Instance& a, const Instance& b) {
return a.depth < b.depth; return a.depth < b.depth;
}); });
// Step 2: Within equal depth groups, group by shader (stable sort again) //Sort by shaders
// we could optimise by switching the sort order each sort if the last sorts shader doesnt equal the first to ensure blocks of shaders remain connected for (size_t iDepthStart = 0, iDepthEnd = 1; iDepthEnd <= n; iDepthEnd++) {
size_t start = 0; if (iDepthEnd == n || arr[iDepthEnd].depth != arr[iDepthStart].depth) {
for (size_t i = 1; i <= n; i++) { std::stable_sort(arr + iDepthStart, arr + iDepthEnd, [](const Instance& a, const Instance& b) {
if (i == n || arr[i].depth != arr[start].depth) {
// Sort by shader inside [start, i)
std::stable_sort(arr + start, arr + i, [](const Instance& a, const Instance& b) {
return a.shader < b.shader; return a.shader < b.shader;
}); });
start = i; //Sort by uniforms
for (size_t iUniformStart = iDepthStart, iUniformEnd = iDepthStart + 1; iUniformEnd < iDepthEnd; iUniformEnd++) {
if (iUniformEnd == iDepthEnd || arr[iUniformEnd].uniforms.data != arr[iUniformStart].uniforms.data) {
std::stable_sort(arr + iUniformStart, arr + iUniformEnd, [](const Instance& a, const Instance& b) {
return a.uniforms.data < b.uniforms.data;
});
iUniformStart = iUniformEnd;
}
}
iDepthStart = iDepthEnd;
} }
} }
} }
...@@ -180,15 +196,21 @@ void RenderInstances(ObjectBuffer* obj, Span<Instance> data) { ...@@ -180,15 +196,21 @@ void RenderInstances(ObjectBuffer* obj, Span<Instance> data) {
orderObjects(data.data, data.size()); orderObjects(data.data, data.size());
size_t matchStart = 0; size_t matchStart = 0;
AShader* matchShader = data[0].shader; AShader* matchShader = data[0].shader;
Span<Uniform*> matchUniforms = data[0].uniforms;
size_t maxBatch = matchShader->getInstanceSize(); size_t maxBatch = matchShader->getInstanceSize();
for (size_t i = 1; i < data.size(); i++) { for (size_t i = 1; i < data.size(); i++) {
size_t batchSize = i - matchStart; size_t batchSize = i - matchStart;
if (data[i].depth == -1) return; Instance& inst = data[i];
if (data[i].shader == matchShader && batchSize != maxBatch) continue; if (inst.depth == -1) return;
if (batchSize != maxBatch && inst.shader == matchShader &&
inst.uniforms.data == matchUniforms.data) continue;
assert(matchShader); assert(matchShader);
if (matchUniforms.size() != 0)
matchShader->setUniforms(matchUniforms);
matchShader->renderInstances(obj, Span<Instance>(data.data + matchStart, i - matchStart)); matchShader->renderInstances(obj, Span<Instance>(data.data + matchStart, i - matchStart));
matchStart = i; matchStart = i;
matchShader = data[i].shader; matchShader = inst.shader;
matchUniforms = inst.uniforms;
maxBatch = matchShader->getInstanceSize(); maxBatch = matchShader->getInstanceSize();
} }
if (data.size() - matchStart == 0) return; if (data.size() - matchStart == 0) return;
......
...@@ -78,10 +78,10 @@ GLuint LoadShaderProgramFile(const char* vsFile, const char* fsFile) { ...@@ -78,10 +78,10 @@ GLuint LoadShaderProgramFile(const char* vsFile, const char* fsFile) {
return LoadShaderProgramMemory(vsSrc.get(), fsSrc.get()); return LoadShaderProgramMemory(vsSrc.get(), fsSrc.get());
} }
#include <cassert>
void CheckGLError(const char* function) { void CheckGLError(const char* function) {
GLenum err; GLenum err;
while ((err = glGetError()) != GL_NO_ERROR) { while ((err = glGetError()) != GL_NO_ERROR) {
std::cerr << "OpenGL Error in " << function << ": [" << err << "] " << (err) << std::endl;//glewGetErrorString std::cerr << "OpenGL Error in " << function << ": [" << err << "] " << (err) << std::endl;//glewGetErrorString
} }
} }
\ No newline at end of file
...@@ -6,14 +6,44 @@ void AShader::setProgram(GLuint program) { ...@@ -6,14 +6,44 @@ void AShader::setProgram(GLuint program) {
onSetProgram(); onSetProgram();
} }
ObjectBuffer::Shader ObjectBuffer::getShaderBuffers(AShader* shader) { void ObjectBuffer::Shader::resizeBuffer(AShader* shader, size_t newBufferSize) {
size_t instanceSize = shader->getInstanceSize();
if (newBufferSize == bufferSize) return;
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, instanceSize * newBufferSize, NULL, GL_STREAM_DRAW);
bufferSize = newBufferSize;
}
size_t nextPow2(size_t v) {
if (v == 0) return 1;
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
#if SIZE_MAX > 0xffffffff
v |= v >> 32;
#endif
v++;
return v;
}
void ObjectBuffer::Shader::upscaleBuffer(AShader* shader, size_t minBufferSize) {
size_t instanceSize = shader->getInstanceSize();
if (minBufferSize <= bufferSize) return;
size_t newBufferSize = nextPow2(instanceSize * minBufferSize);
glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
glBufferData(GL_ARRAY_BUFFER, newBufferSize, NULL, GL_STREAM_DRAW);
bufferSize = newBufferSize;
}
ObjectBuffer::Shader* ObjectBuffer::getShaderBuffers(AShader* shader) {
if (lastFound.first == shader->program) if (lastFound.first == shader->program)
return lastFound.second; return lastFound.second;
auto found = shaders.find(shader->program); auto found = shaders.find(shader->program);
if (found != shaders.end()) { if (found != shaders.end()) {
lastFound = std::pair<GLuint, Shader>(shader->program, found->second); lastFound = std::pair<GLuint, Shader*>(shader->program, &found->second);
return found->second; return &found->second;
} }
Shader newShader; Shader newShader;
...@@ -23,11 +53,10 @@ ObjectBuffer::Shader ObjectBuffer::getShaderBuffers(AShader* shader) { ...@@ -23,11 +53,10 @@ ObjectBuffer::Shader ObjectBuffer::getShaderBuffers(AShader* shader) {
constructVBOAttribs(VBO); constructVBOAttribs(VBO);
size_t instanceMaxCount = shader->getInstanceMaxCount();
size_t instanceSize = shader->getInstanceSize(); size_t instanceSize = shader->getInstanceSize();
glGenBuffers(1, &newShader.instanceVBO); glGenBuffers(1, &newShader.instanceVBO);
glBindBuffer(GL_ARRAY_BUFFER, newShader.instanceVBO); glBindBuffer(GL_ARRAY_BUFFER, newShader.instanceVBO);
glBufferData(GL_ARRAY_BUFFER, instanceSize * instanceMaxCount, NULL, GL_STREAM_DRAW); glBufferData(GL_ARRAY_BUFFER, 0, NULL, GL_STREAM_DRAW);
for (auto& field : shader->fields) { for (auto& field : shader->fields) {
if (field.varying) if (field.varying)
...@@ -40,9 +69,9 @@ ObjectBuffer::Shader ObjectBuffer::getShaderBuffers(AShader* shader) { ...@@ -40,9 +69,9 @@ ObjectBuffer::Shader ObjectBuffer::getShaderBuffers(AShader* shader) {
glBindVertexArray(0); glBindVertexArray(0);
lastFound = std::pair<GLuint, Shader>(shader->program, newShader); auto newInsert = shaders.insert(std::pair<GLuint, Shader>(shader->program, newShader));
shaders.insert(std::pair<GLuint, Shader>(shader->program, newShader)); lastFound = std::pair<GLuint, Shader*>(shader->program, &newInsert.first->second);
return newShader; return &newInsert.first->second;
} }
......
...@@ -17,9 +17,9 @@ void SliderElement::populateInstances(Span<Instance> buffer) { ...@@ -17,9 +17,9 @@ void SliderElement::populateInstances(Span<Instance> buffer) {
Distance limitInverse = (Distance)(position.w * (limitValue / maxValue)); Distance limitInverse = (Distance)(position.w * (limitValue / maxValue));
Distance stepPixel = (Distance)(position.w / maxValue); Distance stepPixel = (Distance)(position.w / maxValue);
background.rect = position; background.rect = (RectU)position;
background.color = theme.background[2]; background.color = theme.background[2];
backgroundLimit.rect = position; backgroundLimit.rect = (RectU)position;
backgroundLimit.color = theme.background[1]; backgroundLimit.color = theme.background[1];
backgroundLimit.rect.x += limitInverse; backgroundLimit.rect.x += limitInverse;
backgroundLimit.rect.w -= limitInverse; backgroundLimit.rect.w -= limitInverse;
...@@ -27,19 +27,19 @@ void SliderElement::populateInstances(Span<Instance> buffer) { ...@@ -27,19 +27,19 @@ void SliderElement::populateInstances(Span<Instance> buffer) {
if (fillValue) { if (fillValue) {
instances[instanceBackgrouncValue].skip = false; instances[instanceBackgrouncValue].skip = false;
backgroundValue.color = theme.statusArr[inputState]; backgroundValue.color = theme.statusArr[inputState];
backgroundValue.rect = position; backgroundValue.rect = (RectU)position;
backgroundValue.rect.w = (Distance)(position.w * (value / maxValue)); backgroundValue.rect.w = (Distance)(position.w * (value / maxValue));
} else } else
instances[instanceBackgrouncValue].skip = true; instances[instanceBackgrouncValue].skip = true;
lines.rect = position; lines.rect = (RectU)position;
lines.color = theme.background[0]; lines.color = theme.background[0];
lines.color.a = 128; lines.color.a = 128;
lines.distance = Vec2(stepPixel, 0); lines.distance = Vec2(stepPixel, 0);
lines.size = 1; lines.size = 1;
lines.offset = 0; lines.offset = 0;
handle.rect = calculateHandleBounds(); handle.rect = (RectU)calculateHandleBounds();
handle.color = theme.interactableArr[inputState]; handle.color = theme.interactableArr[inputState];
buffer.copyFrom(instances); buffer.copyFrom(instances);
......
...@@ -20,10 +20,10 @@ void SliderPrecisionElement::populateInstances(Span<Instance> buffer) { ...@@ -20,10 +20,10 @@ void SliderPrecisionElement::populateInstances(Span<Instance> buffer) {
Distance stepPixel = (Distance)(position.w / linkedSlider->maxValue * scale); Distance stepPixel = (Distance)(position.w / linkedSlider->maxValue * scale);
float valueFract = linkedSlider->value - std::floorf(linkedSlider->value); float valueFract = linkedSlider->value - std::floorf(linkedSlider->value);
background.rect = position; background.rect = (RectU)position;
background.color = theme.background[2]; background.color = theme.background[2];
backgroundLimit.rect = position; backgroundLimit.rect = (RectU)position;
backgroundLimit.color = theme.background[1]; backgroundLimit.color = theme.background[1];
float limitRelative = linkedSlider->limitValue - linkedSlider->value; float limitRelative = linkedSlider->limitValue - linkedSlider->value;
Position limitRelativePixel = (position.w / 2) - (Position)(limitRelative * position.w * scale / linkedSlider->maxValue); Position limitRelativePixel = (position.w / 2) - (Position)(limitRelative * position.w * scale / linkedSlider->maxValue);
...@@ -35,19 +35,19 @@ void SliderPrecisionElement::populateInstances(Span<Instance> buffer) { ...@@ -35,19 +35,19 @@ void SliderPrecisionElement::populateInstances(Span<Instance> buffer) {
if (linkedSlider->fillValue) { if (linkedSlider->fillValue) {
instances[instanceBackgrouncValue].skip = false; instances[instanceBackgrouncValue].skip = false;
backgroundValue.color = theme.statusArr[inputState]; backgroundValue.color = theme.statusArr[inputState];
backgroundValue.rect = position; backgroundValue.rect = (RectU)position;
backgroundValue.rect.w = background.rect.w / 2; backgroundValue.rect.w = background.rect.w / 2;
} else } else
instances[instanceBackgrouncValue].skip = true; instances[instanceBackgrouncValue].skip = true;
lines.rect = position; lines.rect = (RectU)position;
lines.color = theme.background[0]; lines.color = theme.background[0];
lines.color.a = 128; lines.color.a = 128;
lines.distance = Vec2(stepPixel, 0); lines.distance = Vec2(stepPixel, 0);
lines.size = 1; lines.size = 1;
lines.offset = (uint16_t)(valueFract * stepPixel); lines.offset = (uint16_t)(valueFract * stepPixel);
handle.rect = calculateHandleBounds(); handle.rect = (RectU)calculateHandleBounds();
handle.color = theme.interactableArr[inputState]; handle.color = theme.interactableArr[inputState];
buffer.copyFrom(instances); buffer.copyFrom(instances);
......
...@@ -23,30 +23,30 @@ void SliderRangeElement::populateInstances(Span<Instance> buffer) { ...@@ -23,30 +23,30 @@ void SliderRangeElement::populateInstances(Span<Instance> buffer) {
Distance limitInverse = (Distance)(position.w * (linkedSlider->limitValue / linkedSlider->maxValue)); Distance limitInverse = (Distance)(position.w * (linkedSlider->limitValue / linkedSlider->maxValue));
Distance stepPixel = (Distance)(position.w / linkedSlider->maxValue); Distance stepPixel = (Distance)(position.w / linkedSlider->maxValue);
background.rect = position; background.rect = (RectU)position;
background.color = theme.background[2]; background.color = theme.background[2];
backgroundLimit.rect = position; backgroundLimit.rect = (RectU)position;
backgroundLimit.color = theme.background[1]; backgroundLimit.color = theme.background[1];
backgroundLimit.rect.x += limitInverse; backgroundLimit.rect.x += limitInverse;
backgroundLimit.rect.w -= limitInverse; backgroundLimit.rect.w -= limitInverse;
backgroundValue.color = theme.statusArr[inputStateMin > inputStateMax ? inputStateMin : inputStateMax]; backgroundValue.color = theme.statusArr[inputStateMin > inputStateMax ? inputStateMin : inputStateMax];
backgroundValue.rect = position; backgroundValue.rect = (RectU)position;
Distance valueMinPix = (Distance)(position.w * (valueMin / linkedSlider->maxValue)); Distance valueMinPix = (Distance)(position.w * (valueMin / linkedSlider->maxValue));
Distance valueMaxPix = (Distance)(position.w * (valueMax / linkedSlider->maxValue)); Distance valueMaxPix = (Distance)(position.w * (valueMax / linkedSlider->maxValue));
backgroundValue.rect.x = position.x + valueMinPix; backgroundValue.rect.x = position.x + valueMinPix;
backgroundValue.rect.w = valueMaxPix - valueMinPix; backgroundValue.rect.w = valueMaxPix - valueMinPix;
lines.rect = position; lines.rect = (RectU)position;
lines.color = theme.background[0]; lines.color = theme.background[0];
lines.color.a = 128; lines.color.a = 128;
lines.distance = Vec2(stepPixel, 0); lines.distance = Vec2(stepPixel, 0);
lines.size = 1; lines.size = 1;
lines.offset = 0; lines.offset = 0;
handleMin.rect = calculateHandleBounds(false); handleMin.rect = (RectU)calculateHandleBounds(false);
handleMin.color = theme.interactableArr[inputStateMin]; handleMin.color = theme.interactableArr[inputStateMin];
handleMax.rect = calculateHandleBounds(true); handleMax.rect = (RectU)calculateHandleBounds(true);
handleMax.color = theme.interactableArr[inputStateMax]; handleMax.color = theme.interactableArr[inputStateMax];
buffer.copyFrom(instances); buffer.copyFrom(instances);
...@@ -130,7 +130,7 @@ bool SliderRangeElement::handleMouse(MouseButton button, MouseInput state, Vec2 ...@@ -130,7 +130,7 @@ bool SliderRangeElement::handleMouse(MouseButton button, MouseInput state, Vec2
//SDL_Log("Mouse x %i y %i. State %i, inputState %i", pos.x, pos.y, (int)state, (int)inputState); //SDL_Log("Mouse x %i y %i. State %i, inputState %i", pos.x, pos.y, (int)state, (int)inputState);
if (!linkedSlider) return false; if (!linkedSlider) return false;
dirty = DIRTY; dirty = DIRTY;
bool retMin = handleMouseMin(button, state, pos, index); bool retMin = inputStateMax == ACTIVE ? false : handleMouseMin(button, state, pos, index);
bool retMax = handleMouseMax(button, state, pos, index); bool retMax = handleMouseMax(button, state, pos, index);
return retMin || retMax; return retMin || retMax;
} }
......
...@@ -15,6 +15,7 @@ void TextElement::populateInstances(Span<Instance> buffer) { ...@@ -15,6 +15,7 @@ void TextElement::populateInstances(Span<Instance> buffer) {
assert(font); assert(font);
size_t textSize = text.size(); size_t textSize = text.size();
if (textChange || atlas->getLastUpdateID() != atlasUpdateID) { if (textChange || atlas->getLastUpdateID() != atlasUpdateID) {
dirty = DIRTY;
if (atlas == nullptr || atlas->getFontSize() != fontSize) if (atlas == nullptr || atlas->getFontSize() != fontSize)
atlas = font->getAtlas(fontSize); atlas = font->getAtlas(fontSize);
...@@ -22,15 +23,6 @@ void TextElement::populateInstances(Span<Instance> buffer) { ...@@ -22,15 +23,6 @@ void TextElement::populateInstances(Span<Instance> buffer) {
instances.resize(textSize); instances.resize(textSize);
atlas->generateInstances(position, text, Span<Instance>(instances)); atlas->generateInstances(position, text, Span<Instance>(instances));
SDL_Log("TextElement::populateInstances [%i]:", (int)textSize);
for (Instance& instance : instances) {
InstanceDataGlyph* data = instance.data.pointerAs<InstanceDataGlyph>();
std::cout << " rect ";
data->rect.debugPrint();
//std::cout << ", \tatlas ";
//data->atlas.debugPrint();
std::cout << std::endl;
}
atlasUpdateID = atlas->getLastUpdateID(); atlasUpdateID = atlas->getLastUpdateID();
} }
assert(instances.size() == textSize); assert(instances.size() == textSize);
......
...@@ -2,74 +2,8 @@ ...@@ -2,74 +2,8 @@
#include <cstring> #include <cstring>
#include <cstdint> #include <cstdint>
#include <cassert> #include <cassert>
#include <iostream>
Rect Rect::flipAxies() const {
return Rect{x, y, h, w};
}
bool Rect::inside(Vec2 point) const {
return x <= point.x && x+w >= point.x
&& y <= point.y && y+h >= point.y;
}
Rect Rect::clip(const Rect& that) const {
Rect newRect = *this;
int32_t diff;
diff = that.x - newRect.x;
if (diff > newRect.w) return Rect();
if (diff > 0) {
newRect.x += diff;
newRect.w -= diff;
}
diff = (newRect.x + newRect.w) - (that.x + that.w);
if (diff > newRect.w) return Rect();
if (diff > 0) {
newRect.w -= diff;
}
diff = that.y - newRect.y;
if (diff > newRect.h) return Rect();
if (diff > 0) {
newRect.y += diff;
newRect.h -= diff;
}
diff = (newRect.y + newRect.h) - (that.y + that.h);
if (diff > newRect.h) return Rect();
if (diff > 0) {
newRect.y -= diff;
}
return newRect;
}
Rect Rect::combine(const Rect& that) const {
Rect newRect = *this;
int32_t diff;
diff = that.x - newRect.x;
if (diff > 0) {
newRect.x -= diff;
newRect.w += diff;
}
diff = (newRect.x + newRect.w) - (that.x + that.w);
if (diff > 0) {
newRect.w += diff;
}
diff = that.y - newRect.y;
if (diff > 0) {
newRect.y -= diff;
newRect.h += diff;
}
diff = (newRect.y + newRect.h) - (that.y + that.h);
if (diff > 0) {
newRect.y += diff;
}
return newRect;
}
void Rect::debugPrint() const {
std::cout << "Rect(" << x << ", " << y << ", " << w << ", " << h << ")";
}
Vec2 Vec2::flipAxies() { Vec2 Vec2::flipAxies() {
return Vec2{y, x}; return Vec2{y, x};
......
...@@ -68,7 +68,7 @@ constexpr const GLenum textureLocs[] = { ...@@ -68,7 +68,7 @@ constexpr const GLenum textureLocs[] = {
GL_TEXTURE4, GL_TEXTURE5, GL_TEXTURE6, GL_TEXTURE7 GL_TEXTURE4, GL_TEXTURE5, GL_TEXTURE6, GL_TEXTURE7
}; };
void UniformTexture8::applyLoc(GLint loc) { void UniformTexture8::applyLoc(GLint loc) {
assert(tex != GL_NONE); if (tex == GL_NONE) return;
glActiveTexture(textureLocs[index]); glActiveTexture(textureLocs[index]);
glBindTexture(GL_TEXTURE_2D, tex); glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(loc, index); glUniform1i(loc, index);
...@@ -77,19 +77,21 @@ void UniformTexture8::set(const std::vector<uint8_t>& data, uint32_t width, uint ...@@ -77,19 +77,21 @@ void UniformTexture8::set(const std::vector<uint8_t>& data, uint32_t width, uint
assert(data.size() == (width * height)); assert(data.size() == (width * height));
if (tex == GL_NONE) { if (tex == GL_NONE) {
glGenTextures(1, &tex); glGenTextures(1, &tex);
CheckGLError("glBindTexture"); CheckGLError("glGenTextures");
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
} }
glBindTexture(GL_TEXTURE_2D, tex); glBindTexture(GL_TEXTURE_2D, tex);
CheckGLError("glBindTexture");
if (width == this->width && height == this->height) if (width == this->width && height == this->height) {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, data.data()); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, data.data());
else { CheckGLError("glTexSubImage2D");
this->width = width; } else {
this->height = height; glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data.data());
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, data.data()); CheckGLError("glTexImage2D");
} }
} }