72 lines
2.4 KiB
C++
72 lines
2.4 KiB
C++
#ifndef TEXTURE_PAINTER_CLASS
|
|
#define TEXTURE_PAINTER_CLASS
|
|
|
|
#include <cmath>
|
|
|
|
#include <glm/glm.hpp>
|
|
|
|
#include "texture.h"
|
|
|
|
// The brush behind the texture drawer. Edits a Texture's pixels and uploads them.
|
|
class TexturePainter {
|
|
public:
|
|
glm::vec3 color = glm::vec3(0.0f);
|
|
int brushSize = 8; // radius in pixels of a 256 wide texture, so it looks the same on any size
|
|
|
|
// uv runs 0-1 from the top left of the image. Joins up with the last call until EndStroke.
|
|
void Stroke(Texture& texture, const glm::vec2& uv) {
|
|
const glm::vec2 point(uv.x * texture.width, (1.0f - uv.y) * texture.height);
|
|
const float radius = glm::max(1.0f, brushSize * texture.width / 256.0f);
|
|
|
|
if (!stroking) {
|
|
Stamp(texture, point, radius);
|
|
}
|
|
else {
|
|
// Fill the gap, the mouse can cross a lot of pixels in one frame
|
|
const int steps = (int)std::ceil(glm::length(point - lastPoint) / (radius * 0.5f));
|
|
for (int i = 1; i <= steps; i++)
|
|
Stamp(texture, glm::mix(lastPoint, point, (float)i / (float)steps), radius);
|
|
}
|
|
|
|
stroking = true;
|
|
lastPoint = point;
|
|
texture.Upload();
|
|
}
|
|
|
|
void EndStroke() {
|
|
stroking = false;
|
|
}
|
|
|
|
void Clear(Texture& texture) {
|
|
texture.pixels.assign(texture.pixels.size(), 255);
|
|
texture.Upload();
|
|
}
|
|
|
|
private:
|
|
bool stroking = false;
|
|
glm::vec2 lastPoint = glm::vec2(0.0f);
|
|
|
|
void Stamp(Texture& texture, const glm::vec2& center, float radius) {
|
|
const int minX = glm::max((int)(center.x - radius), 0);
|
|
const int maxX = glm::min((int)(center.x + radius), texture.width - 1);
|
|
const int minY = glm::max((int)(center.y - radius), 0);
|
|
const int maxY = glm::min((int)(center.y + radius), texture.height - 1);
|
|
|
|
for (int y = minY; y <= maxY; y++) {
|
|
for (int x = minX; x <= maxX; x++) {
|
|
const glm::vec2 offset = glm::vec2(x + 0.5f, y + 0.5f) - center;
|
|
if (glm::dot(offset, offset) > radius * radius)
|
|
continue;
|
|
|
|
unsigned char* pixel = &texture.pixels[((size_t)y * texture.width + x) * 4];
|
|
pixel[0] = (unsigned char)(color.r * 255.0f);
|
|
pixel[1] = (unsigned char)(color.g * 255.0f);
|
|
pixel[2] = (unsigned char)(color.b * 255.0f);
|
|
pixel[3] = 255;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif
|