A little clean up
This commit is contained in:
parent
3b389bdc17
commit
1155067b26
8 changed files with 234 additions and 407 deletions
|
|
@ -112,123 +112,6 @@ void Graphics::Canvas::text(
|
||||||
popClamp();
|
popClamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::Canvas::drawColorwheel(const RectF& rec, const RGB& col) {
|
|
||||||
|
|
||||||
float const x = rec.x;
|
|
||||||
float const y = rec.y;
|
|
||||||
float const w = rec.z;
|
|
||||||
float const h = rec.w;
|
|
||||||
|
|
||||||
HSV hsv = tp::HSV(col);
|
|
||||||
float const hue = hsv.h / (NVG_PI * 2);
|
|
||||||
|
|
||||||
int i;
|
|
||||||
float r0, r1, ax, ay, bx, by, cx, cy, aeps, r;
|
|
||||||
NVGpaint paint;
|
|
||||||
|
|
||||||
nvgSave(mContext->vg);
|
|
||||||
|
|
||||||
cx = x + w * 0.5f;
|
|
||||||
cy = y + h * 0.5f;
|
|
||||||
r1 = (w < h ? w : h) * 0.5f - 5.0f;
|
|
||||||
r0 = r1 - 13.0f;
|
|
||||||
aeps = 0.5f / r1; // half a pixel arc length in radians (2pi cancels out).
|
|
||||||
|
|
||||||
for (i = 0; i < 6; i++) {
|
|
||||||
float a0 = (float) i / 6.0f * NVG_PI * 2.0f - aeps;
|
|
||||||
float a1 = (float) (i + 1.0f) / 6.0f * NVG_PI * 2.0f + aeps;
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgArc(mContext->vg, cx, cy, r0, a0, a1, NVG_CW);
|
|
||||||
nvgArc(mContext->vg, cx, cy, r1, a1, a0, NVG_CCW);
|
|
||||||
nvgClosePath(mContext->vg);
|
|
||||||
ax = cx + cosf(a0) * (r0 + r1) * 0.5f;
|
|
||||||
ay = cy + sinf(a0) * (r0 + r1) * 0.5f;
|
|
||||||
bx = cx + cosf(a1) * (r0 + r1) * 0.5f;
|
|
||||||
by = cy + sinf(a1) * (r0 + r1) * 0.5f;
|
|
||||||
paint = nvgLinearGradient(
|
|
||||||
mContext->vg,
|
|
||||||
ax,
|
|
||||||
ay,
|
|
||||||
bx,
|
|
||||||
by,
|
|
||||||
nvgHSLA(a0 / (NVG_PI * 2), 1.0f, 0.55f, 255),
|
|
||||||
nvgHSLA(a1 / (NVG_PI * 2), 1.0f, 0.55f, 255)
|
|
||||||
);
|
|
||||||
nvgFillPaint(mContext->vg, paint);
|
|
||||||
nvgFill(mContext->vg);
|
|
||||||
}
|
|
||||||
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgCircle(mContext->vg, cx, cy, r0 - 0.5f);
|
|
||||||
nvgCircle(mContext->vg, cx, cy, r1 + 0.5f);
|
|
||||||
nvgStrokeColor(mContext->vg, nvgRGBA(0, 0, 0, 64));
|
|
||||||
nvgStrokeWidth(mContext->vg, 1.0f);
|
|
||||||
nvgStroke(mContext->vg);
|
|
||||||
|
|
||||||
// Selector
|
|
||||||
nvgSave(mContext->vg);
|
|
||||||
nvgTranslate(mContext->vg, cx, cy);
|
|
||||||
nvgRotate(mContext->vg, hue * NVG_PI * 2);
|
|
||||||
|
|
||||||
// Marker on
|
|
||||||
nvgStrokeWidth(mContext->vg, 2.0f);
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgRect(mContext->vg, r0 - 1, -3, r1 - r0 + 2, 6);
|
|
||||||
nvgStrokeColor(mContext->vg, nvgRGBA(255, 255, 255, 192));
|
|
||||||
nvgStroke(mContext->vg);
|
|
||||||
|
|
||||||
paint = nvgBoxGradient(mContext->vg, r0 - 3, -5, r1 - r0 + 6, 10, 2, 4, nvgRGBA(0, 0, 0, 128), nvgRGBA(0, 0, 0, 0));
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgRect(mContext->vg, r0 - 2 - 10, -4 - 10, r1 - r0 + 4 + 20, 8 + 20);
|
|
||||||
nvgRect(mContext->vg, r0 - 2, -4, r1 - r0 + 4, 8);
|
|
||||||
nvgPathWinding(mContext->vg, NVG_HOLE);
|
|
||||||
nvgFillPaint(mContext->vg, paint);
|
|
||||||
nvgFill(mContext->vg);
|
|
||||||
|
|
||||||
// Center triangle
|
|
||||||
r = r0 - 6;
|
|
||||||
ax = cosf(120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
ay = sinf(120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
bx = cosf(-120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
by = sinf(-120.0f / 180.0f * NVG_PI) * r;
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgMoveTo(mContext->vg, r, 0);
|
|
||||||
nvgLineTo(mContext->vg, ax, ay);
|
|
||||||
nvgLineTo(mContext->vg, bx, by);
|
|
||||||
nvgClosePath(mContext->vg);
|
|
||||||
paint = nvgLinearGradient(mContext->vg, r, 0, ax, ay, nvgHSLA(hue, 1.0f, 0.5f, 255), nvgRGBA(255, 255, 255, 255));
|
|
||||||
nvgFillPaint(mContext->vg, paint);
|
|
||||||
nvgFill(mContext->vg);
|
|
||||||
paint = nvgLinearGradient(mContext->vg, (r + ax) * 0.5f, (0 + ay) * 0.5f, bx, by, nvgRGBA(0, 0, 0, 0), nvgRGBA(0, 0, 0, 255));
|
|
||||||
nvgFillPaint(mContext->vg, paint);
|
|
||||||
nvgFill(mContext->vg);
|
|
||||||
nvgStrokeColor(mContext->vg, nvgRGBA(0, 0, 0, 64));
|
|
||||||
nvgStroke(mContext->vg);
|
|
||||||
|
|
||||||
// Select circle on triangle
|
|
||||||
float yt = hsv.v * hsv.s;
|
|
||||||
float xt = hsv.v - 0.5 * yt;
|
|
||||||
ay = sinf(120.0f / 180.0f * NVG_PI) * r * (-1.0f + xt * 2.0f);
|
|
||||||
ax = cosf(120.0f / 180.0f * NVG_PI) * r * (1.0f - yt * 3.f);
|
|
||||||
nvgStrokeWidth(mContext->vg, 2.0f);
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgCircle(mContext->vg, ax, ay, 5);
|
|
||||||
nvgStrokeColor(mContext->vg, nvgRGBA(255, 255, 255, 192));
|
|
||||||
nvgStroke(mContext->vg);
|
|
||||||
|
|
||||||
paint = nvgRadialGradient(mContext->vg, ax, ay, 7, 9, nvgRGBA(0, 0, 0, 64), nvgRGBA(0, 0, 0, 0));
|
|
||||||
nvgBeginPath(mContext->vg);
|
|
||||||
nvgRect(mContext->vg, ax - 20, ay - 20, 40, 40);
|
|
||||||
nvgCircle(mContext->vg, ax, ay, 7);
|
|
||||||
nvgPathWinding(mContext->vg, NVG_HOLE);
|
|
||||||
nvgFillPaint(mContext->vg, paint);
|
|
||||||
nvgFill(mContext->vg);
|
|
||||||
|
|
||||||
nvgRestore(mContext->vg);
|
|
||||||
|
|
||||||
nvgRestore(mContext->vg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) {
|
void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) {
|
||||||
auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha);
|
auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha);
|
||||||
nvgBeginPath(mContext->vg);
|
nvgBeginPath(mContext->vg);
|
||||||
|
|
|
||||||
|
|
@ -91,12 +91,9 @@ namespace tp {
|
||||||
void rect(const RectF& rec, const RGBA& col, halnf round = 0);
|
void rect(const RectF& rec, const RGBA& col, halnf round = 0);
|
||||||
void text(const char*, const RectF&, halnf size, Align, halnf marging, const RGBA&);
|
void text(const char*, const RectF&, halnf size, Align, halnf marging, const RGBA&);
|
||||||
|
|
||||||
void drawColorwheel(const RectF& rec, const RGB& col);
|
|
||||||
|
|
||||||
ImageHandle createImageFromTextId(ualni id, Vec2F size);
|
ImageHandle createImageFromTextId(ualni id, Vec2F size);
|
||||||
void deleteImageHandle(ImageHandle image);
|
void deleteImageHandle(ImageHandle image);
|
||||||
void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding);
|
void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding);
|
||||||
// TODO : API
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
halnf mWidth = 600;
|
halnf mWidth = 600;
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,9 @@ void Camera::setFar(halnf in) { mFar = in; }
|
||||||
|
|
||||||
halnf Camera::getFOV() const { return mFOV; }
|
halnf Camera::getFOV() const { return mFOV; }
|
||||||
|
|
||||||
Mat4F Camera::calculateTransformationMatrix() { return calculateProjectionMatrix() * calculateViewMatrix(); }
|
Mat4F Camera::calculateTransformationMatrix() const { return calculateProjectionMatrix() * calculateViewMatrix(); }
|
||||||
|
|
||||||
Mat4F Camera::calculateViewMatrix() {
|
Mat4F Camera::calculateViewMatrix() const {
|
||||||
const Vec3F& F = (mPos - mTarget).unitV();
|
const Vec3F& F = (mPos - mTarget).unitV();
|
||||||
const Vec3F& S = mUp * F;
|
const Vec3F& S = mUp * F;
|
||||||
const Vec3F& U = F * S;
|
const Vec3F& U = F * S;
|
||||||
|
|
|
||||||
|
|
@ -36,9 +36,9 @@ namespace tp {
|
||||||
void offset_target(halnf val);
|
void offset_target(halnf val);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
[[nodiscard]] Mat4F calculateTransformationMatrix();
|
[[nodiscard]] Mat4F calculateTransformationMatrix() const;
|
||||||
[[nodiscard]] Mat<halnf, 4, 4> calculateProjectionMatrix() const;
|
[[nodiscard]] Mat<halnf, 4, 4> calculateProjectionMatrix() const;
|
||||||
[[nodiscard]] Mat<halnf, 4, 4> calculateViewMatrix();
|
[[nodiscard]] Mat<halnf, 4, 4> calculateViewMatrix() const;
|
||||||
[[nodiscard]] Vec3F project(Vec2F normalized);
|
[[nodiscard]] Vec3F project(Vec2F normalized);
|
||||||
[[nodiscard]] Vec2F project(const Vec3F& world);
|
[[nodiscard]] Vec2F project(const Vec3F& world);
|
||||||
[[nodiscard]] static Vec2F project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat);
|
[[nodiscard]] static Vec2F project(const tp::Vec3F& world, const tp::Mat4F& viewMat, const tp::Mat4F& projMat);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ void runApp() {
|
||||||
auto window = tp::Window::createWindow(800, 600, "Window 1");
|
auto window = tp::Window::createWindow(800, 600, "Window 1");
|
||||||
|
|
||||||
{
|
{
|
||||||
tp::Sketch3DWidget<tp::Window::Events, tp::Graphics::Canvas> gui(window->getCanvas(), {800, 1000});
|
tp::Sketch3DWidget<tp::Window::Events, tp::Graphics::Canvas> gui(window->getCanvas(), {1800, 1000});
|
||||||
|
|
||||||
if (window) {
|
if (window) {
|
||||||
while (!window->shouldClose()) {
|
while (!window->shouldClose()) {
|
||||||
|
|
@ -24,7 +24,7 @@ void runApp() {
|
||||||
gui.proc(window->getEvents(), { area.x, area.y, area.z, area.w }, { area.x, area.y, area.z, area.w });
|
gui.proc(window->getEvents(), { area.x, area.y, area.z, area.w }, { area.x, area.y, area.z, area.w });
|
||||||
gui.draw(window->getCanvas());
|
gui.draw(window->getCanvas());
|
||||||
|
|
||||||
tp::sleep(100);
|
tp::sleep(10);
|
||||||
|
|
||||||
window->draw();
|
window->draw();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,72 +3,74 @@
|
||||||
|
|
||||||
using namespace tp;
|
using namespace tp;
|
||||||
|
|
||||||
Stroke::GLHandles::GLHandles() {
|
StrokeGPUHandles::StrokeGPUHandles() {
|
||||||
glGenVertexArrays(1, &VertexArrayID);
|
glGenVertexArrays(1, &VertexArrayID);
|
||||||
glBindVertexArray(VertexArrayID);
|
glBindVertexArray(VertexArrayID);
|
||||||
|
|
||||||
glGenBuffers(1, &vertexbuffer);
|
glGenBuffers(1, &vertexbuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::GLHandles::sendDataToGPU(tp::Buffer<Point>* mPoints) {
|
void StrokeGPUHandles::sendDataToGPU(Buffer<StrokePoint>* mPoints) {
|
||||||
glBindVertexArray(VertexArrayID);
|
glBindVertexArray(VertexArrayID);
|
||||||
vbo_len = mPoints->size();
|
vbo_len = mPoints->size();
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
|
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(mPoints[0]) * vbo_len, mPoints->getBuff(), GL_STATIC_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(mPoints[0]) * vbo_len, mPoints->getBuff(), GL_STATIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stroke::GLHandles::~GLHandles() {
|
StrokeGPUHandles::~StrokeGPUHandles() {
|
||||||
glDeleteBuffers(1, &vertexbuffer);
|
glDeleteBuffers(1, &vertexbuffer);
|
||||||
glDeleteVertexArrays(1, &VertexArrayID);
|
glDeleteVertexArrays(1, &VertexArrayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stroke::Stroke() {}
|
Stroke::Stroke() = default;
|
||||||
|
|
||||||
tp::Buffer<Stroke::Point>& Stroke::buff() {
|
Buffer<StrokePoint>& Stroke::getPoints() { return mPoints; }
|
||||||
return mPoints;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stroke::updateGpuBuffers() {
|
const Buffer<StrokePoint>& Stroke::getPoints() const { return mPoints; }
|
||||||
mGl.sendDataToGPU(&mPoints);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stroke::denoisePos(tp::halni passes) {
|
void Stroke::setColor(const RGBA& col) { mColor = col; }
|
||||||
for (auto pass : tp::Range(passes)) {
|
|
||||||
for (auto pi : tp::Range(mPoints.size() - 2)) {
|
const RGBA& Stroke::getColor() const { return mColor; }
|
||||||
|
|
||||||
|
void Stroke::updateGpuBuffers() { mGPUHandles.sendDataToGPU(&mPoints); }
|
||||||
|
|
||||||
|
void Stroke::denoisePos(halni passes) {
|
||||||
|
for (auto pass : Range(passes)) {
|
||||||
|
for (auto pi : Range(mPoints.size() - 2)) {
|
||||||
mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f;
|
mPoints[pi + 1].pos = (mPoints[pi + 1].pos + mPoints[pi].pos + mPoints[pi + 2].pos) / 3.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::denoiseThickness(tp::halni passes) {
|
void Stroke::denoiseThickness(halni passes) {
|
||||||
for (auto pass : tp::Range(passes)) {
|
for (auto pass : Range(passes)) {
|
||||||
for (auto pi : tp::Range(mPoints.size() - 2)) {
|
for (auto pi : Range(mPoints.size() - 2)) {
|
||||||
mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f;
|
mPoints[pi + 1].thickness = (mPoints[pi].thickness + mPoints[pi + 2].thickness) / 2.f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::compress(tp::halnf factor) {
|
void Stroke::compress(halnf factor) {
|
||||||
if (mPoints.size() < 3) {
|
if (mPoints.size() < 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::List<Point> passed_poits;
|
List<StrokePoint> passed_poits;
|
||||||
|
|
||||||
for (auto idx : tp::Range(mPoints.size())) {
|
for (auto idx : Range(mPoints.size())) {
|
||||||
passed_poits.pushBack(mPoints[idx]);
|
passed_poits.pushBack(mPoints[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::List<Point>::Node* min_node = NULL;
|
List<StrokePoint>::Node* min_node = NULL;
|
||||||
do {
|
do {
|
||||||
min_node = NULL;
|
min_node = NULL;
|
||||||
tp::halnf min_factor = factor;
|
halnf min_factor = factor;
|
||||||
|
|
||||||
tp::List<Point>::Node* iter = passed_poits.first()->next;
|
List<StrokePoint>::Node* iter = passed_poits.first()->next;
|
||||||
for (; iter->next; iter = iter->next) {
|
for (; iter->next; iter = iter->next) {
|
||||||
tp::Vec3F dir1 = (iter->data.pos - iter->prev->data.pos).normalize();
|
Vec3F dir1 = (iter->data.pos - iter->prev->data.pos).normalize();
|
||||||
tp::Vec3F dir2 = (iter->next->data.pos - iter->data.pos).normalize();
|
Vec3F dir2 = (iter->next->data.pos - iter->data.pos).normalize();
|
||||||
tp::halnf factor = 1 - dir1.dot(dir2);
|
halnf factor = 1 - dir1.dot(dir2);
|
||||||
|
|
||||||
if (factor < min_factor) {
|
if (factor < min_factor) {
|
||||||
min_node = iter;
|
min_node = iter;
|
||||||
|
|
@ -83,29 +85,30 @@ void Stroke::compress(tp::halnf factor) {
|
||||||
|
|
||||||
|
|
||||||
mPoints.reserve(passed_poits.length());
|
mPoints.reserve(passed_poits.length());
|
||||||
tp::ualni idx = 0;
|
|
||||||
|
ualni idx = 0;
|
||||||
for (auto point : passed_poits) {
|
for (auto point : passed_poits) {
|
||||||
mPoints[idx] = point.data();
|
mPoints[idx] = point.data();
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) {
|
void Stroke::subdiv(halnf precision, const Camera* cam, halni passes) {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
if (mPoints.size() < 4) {
|
if (mPoints.size() < 4) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::List<Point> new_points;
|
List<StrokePoint> new_points;
|
||||||
for (auto idx : tp::Range(mPoints.size())) {
|
for (auto idx : Range(mPoints.size())) {
|
||||||
new_points.pushBack(mPoints[idx]);
|
new_points.pushBack(mPoints[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto viewmat = cam->calculateViewMatrix();
|
auto viewmat = cam->calculateViewMatrix();
|
||||||
auto projmat = cam->calculateProjectionMatrix();
|
auto projmat = cam->calculateProjectionMatrix();
|
||||||
|
|
||||||
for (auto i : tp::Range(passes)) {
|
for (auto i : Range(passes)) {
|
||||||
|
|
||||||
auto n_points = new_points.length();
|
auto n_points = new_points.length();
|
||||||
|
|
||||||
|
|
@ -129,9 +132,9 @@ void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) {
|
||||||
auto const ab = a.dot(b);
|
auto const ab = a.dot(b);
|
||||||
auto const la = l.dot(a);
|
auto const la = l.dot(a);
|
||||||
auto const lb = l.dot(b);
|
auto const lb = l.dot(b);
|
||||||
tp::Vec3F mid;
|
Vec3F mid;
|
||||||
|
|
||||||
if (1 - tp::abs(ab) < 0.001f) {
|
if (1 - abs(ab) < 0.001f) {
|
||||||
goto SKIP;
|
goto SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -189,7 +192,7 @@ void Stroke::subdiv(tp::halnf precision, tp::Camera* cam, tp::halni passes) {
|
||||||
|
|
||||||
if (new_points.length() != mPoints.size()) {
|
if (new_points.length() != mPoints.size()) {
|
||||||
mPoints.reserve(new_points.length());
|
mPoints.reserve(new_points.length());
|
||||||
tp::ualni idx = 0;
|
ualni idx = 0;
|
||||||
for (auto point : new_points) {
|
for (auto point : new_points) {
|
||||||
mPoints[idx] = point.data();
|
mPoints[idx] = point.data();
|
||||||
idx++;
|
idx++;
|
||||||
|
|
@ -201,11 +204,11 @@ PencilBrush::PencilBrush() {
|
||||||
mType = "pencil";
|
mType = "pencil";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PencilBrush::unsureReady(Stroke* stroke, tp::Camera* cam, bool debug) {
|
void PencilBrush::ensureReady(Stroke* stroke, const Camera* cam, bool debug) const {
|
||||||
if (stroke->buff().size() == 1) {
|
if (stroke->getPoints().size() == 1) {
|
||||||
auto new_point = stroke->buff()[0];
|
auto new_point = stroke->getPoints()[0];
|
||||||
new_point.pos += 0.00001f;
|
new_point.pos += 0.00001f;
|
||||||
stroke->buff().append(new_point);
|
stroke->getPoints().append(new_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mEnableCompression && !debug) {
|
if (mEnableCompression && !debug) {
|
||||||
|
|
@ -217,24 +220,24 @@ void PencilBrush::unsureReady(Stroke* stroke, tp::Camera* cam, bool debug) {
|
||||||
stroke->updateGpuBuffers();
|
stroke->updateGpuBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PencilBrush::sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) {
|
void PencilBrush::sample(Project* proj, Vec2F crs, halnf pressure) {
|
||||||
if (proj->mActiveLayer == -1) {
|
if (proj->mActiveLayer == -1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool max_level = mStroke && mStroke->mPoints.size() > mMaxPoints;
|
bool max_level = mStroke && mStroke->getPoints().size() > mMaxPoints;
|
||||||
if (!pressure || max_level) {
|
if (!pressure || max_level) {
|
||||||
if (mStroke) {
|
if (mStroke) {
|
||||||
unsureReady(mStroke, &proj->mCamera);
|
ensureReady(mStroke, &proj->mCamera);
|
||||||
proj->mLayers[proj->mActiveLayer]->strokes.pushBack(mStroke);
|
proj->mLayers[proj->mActiveLayer]->strokes.pushBack(mStroke);
|
||||||
mStroke = NULL;
|
mStroke = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_level) {
|
if (max_level) {
|
||||||
mStroke = new Stroke();
|
mStroke = new Stroke();
|
||||||
mStroke->mCol = mCol;
|
mStroke->setColor(mCol);
|
||||||
|
|
||||||
mStroke->mPoints.append(proj->mLayers[proj->mActiveLayer]->strokes.last()->data->mPoints.last());
|
mStroke->getPoints().append(proj->mLayers[proj->mActiveLayer]->strokes.last()->data->getPoints().last());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pressure) {
|
if (!pressure) {
|
||||||
|
|
@ -245,8 +248,8 @@ void PencilBrush::sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) {
|
||||||
auto thickness = pressure * (proj->mCamera.project({ 0.f, 0.f }) - proj->mCamera.project({ mSize, 0.f })).length();
|
auto thickness = pressure * (proj->mCamera.project({ 0.f, 0.f }) - proj->mCamera.project({ mSize, 0.f })).length();
|
||||||
bool point_passed = true;
|
bool point_passed = true;
|
||||||
|
|
||||||
if (mStroke && mStroke->buff().size()) {
|
if (mStroke && mStroke->getPoints().size()) {
|
||||||
auto last_point_2d = proj->mCamera.project(mStroke->buff().last().pos);
|
auto last_point_2d = proj->mCamera.project(mStroke->getPoints().last().pos);
|
||||||
point_passed = (crs - last_point_2d).length() > mPrecision;
|
point_passed = (crs - last_point_2d).length() > mPrecision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,21 +259,24 @@ void PencilBrush::sample(Project* proj, tp::Vec2F crs, tp::halnf pressure) {
|
||||||
|
|
||||||
if (!mStroke) {
|
if (!mStroke) {
|
||||||
mStroke = new Stroke();
|
mStroke = new Stroke();
|
||||||
mStroke->mCol = mCol;
|
mStroke->setColor(mCol);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto point_coords = proj->mCamera.project(crs);
|
auto point_coords = proj->mCamera.project(crs);
|
||||||
mStroke->buff().append({ point_coords, (tp::halnf) thickness });
|
mStroke->getPoints().append({ point_coords, (halnf) thickness });
|
||||||
mStroke->updateGpuBuffers();
|
|
||||||
|
// mStroke->updateGpuBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PencilBrush::draw(Renderer* render, tp::Camera* camera) {
|
void PencilBrush::draw(Renderer* render, const Camera* camera) const {
|
||||||
if (mStroke) {
|
if (mStroke) {
|
||||||
if (mEnableCompression) {
|
if (mEnableCompression) {
|
||||||
mShowStroke.buff() = mStroke->buff();
|
Stroke tempDisplayStroke;
|
||||||
mShowStroke.mCol = mStroke->mCol;
|
tempDisplayStroke.getPoints() = mStroke->getPoints();
|
||||||
unsureReady(&mShowStroke, camera, 0);
|
tempDisplayStroke.setColor(mStroke->getColor());
|
||||||
render->drawStroke(&mShowStroke, camera);
|
ensureReady(&tempDisplayStroke, camera, 0);
|
||||||
|
|
||||||
|
render->drawStroke(&tempDisplayStroke, camera);
|
||||||
} else {
|
} else {
|
||||||
render->drawStroke(mStroke, camera);
|
render->drawStroke(mStroke, camera);
|
||||||
}
|
}
|
||||||
|
|
@ -281,7 +287,7 @@ PencilBrush::~PencilBrush() {
|
||||||
if (mStroke) delete mStroke;
|
if (mStroke) delete mStroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
Project::Layer::~Layer() {
|
Layer::~Layer() {
|
||||||
for (auto str : strokes) {
|
for (auto str : strokes) {
|
||||||
delete str.data();
|
delete str.data();
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +307,7 @@ Project::Project() {
|
||||||
mActiveBrush = "pencil";
|
mActiveBrush = "pencil";
|
||||||
|
|
||||||
Stroke* debug = new Stroke();
|
Stroke* debug = new Stroke();
|
||||||
debug->mPoints = { { { 0, 0, 0 }, 1 }, { { 1, 1, 1 } , 1} };
|
debug->getPoints() = { { { 0, 0, 0 }, 1 }, { { 1, 1, 1 }, 1 } };
|
||||||
debug->updateGpuBuffers();
|
debug->updateGpuBuffers();
|
||||||
|
|
||||||
mLayers.last()->strokes.pushBack(debug);
|
mLayers.last()->strokes.pushBack(debug);
|
||||||
|
|
@ -311,17 +317,34 @@ Project::Project() {
|
||||||
vec = mCamera.project({1, 0, 0});
|
vec = mCamera.project({1, 0, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Project::sample(halnf pressure, halnf cameraRatio, Vec2F relativeCameraPos) {
|
||||||
|
mCamera.setRatio(cameraRatio);
|
||||||
|
|
||||||
|
auto idx = mBrushes.presents(mActiveBrush);
|
||||||
|
if (idx) {
|
||||||
|
auto brush = mBrushes.getSlotVal(idx);
|
||||||
|
|
||||||
|
if (brush->mType == "pencil") {
|
||||||
|
((tp::PencilBrush*) brush)->mCol = RGBA(1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
brush->sample(this, relativeCameraPos, pressure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Project::~Project() {
|
Project::~Project() {
|
||||||
for (auto brush : mBrushes) {
|
for (auto brush : mBrushes) {
|
||||||
delete brush->val;
|
delete brush->val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::Renderer(tp::Vec2F size) :
|
Renderer::Renderer(Vec2F size) :
|
||||||
mBuffer(size, 4),
|
mBuffer(size, 4),
|
||||||
mBufferDowncast(size),
|
mBufferDowncast(size),
|
||||||
mShader(".\\rsc\\shaders\\stroke.vert", ".\\rsc\\shaders\\stroke.geom", ".\\rsc\\shaders\\stroke.frag")
|
mShader(".\\rsc\\shaders\\stroke.vert", ".\\rsc\\shaders\\stroke.geom", ".\\rsc\\shaders\\stroke.frag")
|
||||||
{
|
{
|
||||||
|
mMaxSize = size;
|
||||||
|
|
||||||
mMatrixUniform = mShader.getu("MVP");
|
mMatrixUniform = mShader.getu("MVP");
|
||||||
mColorUniform = mShader.getu("Color");
|
mColorUniform = mShader.getu("Color");
|
||||||
mRatioUniform = mShader.getu("Ratio");
|
mRatioUniform = mShader.getu("Ratio");
|
||||||
|
|
@ -329,16 +352,40 @@ Renderer::Renderer(tp::Vec2F size) :
|
||||||
mBGColUniform = mShader.getu("BGCol");
|
mBGColUniform = mShader.getu("BGCol");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::renderToTexture(const Project* project, Vec2F size) {
|
||||||
|
size.clamp({ 1, 1 }, mMaxSize);
|
||||||
|
|
||||||
|
setViewport({ 0, 0, size.x, size.y });
|
||||||
|
setClearCol(project->mBackgroundColor);
|
||||||
|
renderBegin();
|
||||||
|
|
||||||
|
for (auto lay : project->mLayers) {
|
||||||
|
if (lay.data()->enabled) {
|
||||||
|
for (auto str : lay.data()->strokes) {
|
||||||
|
drawStroke(str.data(), &project->mCamera);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto idx = project->mBrushes.presents(project->mActiveBrush);
|
||||||
|
if (idx) {
|
||||||
|
auto brush = project->mBrushes.getSlotVal(idx);
|
||||||
|
brush->draw(this, &project->mCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderEnd();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::renderBegin() {
|
void Renderer::renderBegin() {
|
||||||
mBuffer.beginDraw();
|
mBuffer.beginDraw();
|
||||||
mBuffer.clear();
|
mBuffer.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setViewport(tp::RectF viewport) {
|
void Renderer::setViewport(RectF viewport) {
|
||||||
mBuffer.setViewport(viewport);
|
mBuffer.setViewport(viewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::drawStroke(Stroke* str, tp::Camera* camera) {
|
void Renderer::drawStroke(const Stroke* str, const Camera* camera) {
|
||||||
//return;
|
//return;
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
@ -347,30 +394,30 @@ void Renderer::drawStroke(Stroke* str, tp::Camera* camera) {
|
||||||
GLint val;
|
GLint val;
|
||||||
glGetIntegerv(GL_SAMPLES, &val);
|
glGetIntegerv(GL_SAMPLES, &val);
|
||||||
|
|
||||||
glBindVertexArray(str->mGl.VertexArrayID);
|
glBindVertexArray(str->mGPUHandles.VertexArrayID);
|
||||||
mShader.bind();
|
mShader.bind();
|
||||||
|
|
||||||
auto cam_mat = camera->calculateTransformationMatrix().transpose();
|
auto cam_mat = camera->calculateTransformationMatrix().transpose();
|
||||||
glUniformMatrix4fv(mMatrixUniform, 1, GL_FALSE, &cam_mat[0][0]);
|
glUniformMatrix4fv(mMatrixUniform, 1, GL_FALSE, &cam_mat[0][0]);
|
||||||
|
|
||||||
glUniform4fv(mColorUniform, 1, &str->mCol.r);
|
glUniform4fv(mColorUniform, 1, &str->mColor.r);
|
||||||
|
|
||||||
glUniform4fv(mBGColUniform, 1, &mBuffer.mClearCol.r);
|
glUniform4fv(mBGColUniform, 1, &mBuffer.mClearCol.r);
|
||||||
|
|
||||||
auto ratio = camera->getRatio();
|
auto ratio = camera->getRatio();
|
||||||
glUniform1fv(mRatioUniform, 1, &ratio);
|
glUniform1fv(mRatioUniform, 1, &ratio);
|
||||||
|
|
||||||
auto target = tp::halnf(((camera->getTarget() - camera->getPos()).length() - camera->getNear())
|
auto target = halnf(((camera->getTarget() - camera->getPos()).length() - camera->getNear())
|
||||||
/ (camera->getFar() - camera->getNear()));
|
/ (camera->getFar() - camera->getNear()));
|
||||||
|
|
||||||
glUniform1fv(mTargetUniform, 1, &target);
|
glUniform1fv(mTargetUniform, 1, &target);
|
||||||
|
|
||||||
// 1st attribute buffer : vertices
|
// 1st attribute buffer : vertices
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, str->mGl.vertexbuffer);
|
glBindBuffer(GL_ARRAY_BUFFER, str->mGPUHandles.vertexbuffer);
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (void*)0);
|
||||||
|
|
||||||
glDrawArrays(GL_LINE_STRIP, 0, str->mGl.vbo_len);
|
glDrawArrays(GL_LINE_STRIP, 0, str->mGPUHandles.vbo_len);
|
||||||
|
|
||||||
glDisableVertexAttribArray(0);
|
glDisableVertexAttribArray(0);
|
||||||
|
|
||||||
|
|
@ -393,15 +440,15 @@ void Renderer::renderEnd() {
|
||||||
mBufferDowncast.endDraw();
|
mBufferDowncast.endDraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::uhalni Renderer::getTextudeId() {
|
uhalni Renderer::getTextudeId() {
|
||||||
return mBufferDowncast.texId();
|
return mBufferDowncast.texId();
|
||||||
}
|
}
|
||||||
|
|
||||||
tp::RenderBuffer* Renderer::getBuff() {
|
RenderBuffer* Renderer::getBuff() {
|
||||||
return &mBufferDowncast;
|
return &mBufferDowncast;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::setClearCol(tp::RGBA col) {
|
void Renderer::setClearCol(RGBA col) {
|
||||||
mBuffer.mClearCol = col;
|
mBuffer.mClearCol = col;
|
||||||
mBufferDowncast.mClearCol = col;
|
mBufferDowncast.mClearCol = col;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,113 +15,40 @@ namespace tp {
|
||||||
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
class Project;
|
class Project;
|
||||||
|
class Stroke;
|
||||||
|
class Brush;
|
||||||
|
|
||||||
class Stroke {
|
struct StrokePoint {
|
||||||
|
Vec3F pos = { 0, 0, 0 };
|
||||||
friend Renderer;
|
halnf thickness = NULL;
|
||||||
|
|
||||||
public:
|
|
||||||
struct Point {
|
|
||||||
Vec3F pos = { 0, 0, 0 };
|
|
||||||
halnf thickness = NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
Buffer<Point> mPoints;
|
|
||||||
RGBA mCol;
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct GLHandles {
|
|
||||||
GLuint VertexArrayID = 0;
|
|
||||||
GLuint vertexbuffer = 0;
|
|
||||||
GLuint vbo_len = 0;
|
|
||||||
GLHandles();
|
|
||||||
void sendDataToGPU(Buffer<Point>* mPoints);
|
|
||||||
~GLHandles();
|
|
||||||
} mGl;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Stroke();
|
|
||||||
|
|
||||||
void denoisePos(halni passes);
|
|
||||||
void denoiseThickness(halni passes);
|
|
||||||
void compress(halnf factor);
|
|
||||||
void subdiv(halnf precition, Camera* cam, halni passes = 1);
|
|
||||||
|
|
||||||
void updateGpuBuffers();
|
|
||||||
|
|
||||||
Buffer<Point>& buff();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Brush {
|
struct StrokeGPUHandles {
|
||||||
public:
|
GLuint VertexArrayID = 0;
|
||||||
String mType = "equal";
|
GLuint vertexbuffer = 0;
|
||||||
Brush() {}
|
GLuint vbo_len = 0;
|
||||||
virtual void sample(Project* proj, Vec2F crs, halnf pressure) {}
|
StrokeGPUHandles();
|
||||||
virtual void draw(Renderer* render, Camera* camera) {}
|
void sendDataToGPU(Buffer<StrokePoint>* mPoints);
|
||||||
virtual ~Brush() {}
|
~StrokeGPUHandles();
|
||||||
};
|
|
||||||
|
|
||||||
class PencilBrush : public Brush {
|
|
||||||
|
|
||||||
halnf mPrecision = 0.001f;
|
|
||||||
|
|
||||||
halni mDenoisePassesPos = 1;
|
|
||||||
halni mDenoisePassesThick = 3;
|
|
||||||
halnf mCompressionFactor = 0.0001f;
|
|
||||||
halni mSubdivPasses = 3;
|
|
||||||
bool mEnableCompression = true;
|
|
||||||
|
|
||||||
halni mMaxPoints = 100;
|
|
||||||
|
|
||||||
Stroke* mStroke = NULL;
|
|
||||||
Stroke mShowStroke;
|
|
||||||
|
|
||||||
void unsureReady(Stroke* stroke, Camera* cam, bool debug = false);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
RGBA mCol = RGBA(1.0f);
|
|
||||||
halnf mSize = 0.01f;
|
|
||||||
|
|
||||||
PencilBrush();
|
|
||||||
virtual void sample(Project* proj, Vec2F crs, halnf pressure) override;
|
|
||||||
virtual void draw(Renderer* render, Camera* camera) override;
|
|
||||||
virtual ~PencilBrush();
|
|
||||||
};
|
|
||||||
|
|
||||||
struct EraserBrush : public Brush {
|
|
||||||
EraserBrush() { mType = "eraser"; }
|
|
||||||
virtual void sample(Project* proj, Vec2F crs, halnf pressure) override {}
|
|
||||||
virtual void draw(Renderer* render, Camera* camera) override {}
|
|
||||||
virtual ~EraserBrush() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Project {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct Layer {
|
|
||||||
String name = "new layer";
|
|
||||||
List<Stroke*> strokes;
|
|
||||||
bool enabled = true;
|
|
||||||
~Layer();
|
|
||||||
};
|
|
||||||
|
|
||||||
Buffer<Layer*> mLayers;
|
|
||||||
halni mActiveLayer = -1;
|
|
||||||
|
|
||||||
Camera mCamera;
|
|
||||||
RGBA mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f };
|
|
||||||
|
|
||||||
Map<String, Brush*> mBrushes;
|
|
||||||
String mActiveBrush;
|
|
||||||
|
|
||||||
Project();
|
|
||||||
~Project();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Renderer {
|
class Renderer {
|
||||||
|
public:
|
||||||
|
Renderer(Vec2F size); // max render size
|
||||||
|
~Renderer();
|
||||||
|
|
||||||
|
void renderToTexture(const Project* project, Vec2F size); // needed size
|
||||||
|
|
||||||
|
void renderBegin();
|
||||||
|
void setViewport(RectF viewport);
|
||||||
|
void drawStroke(const Stroke* str, const Camera* camera);
|
||||||
|
void renderEnd();
|
||||||
|
|
||||||
|
void setClearCol(RGBA col);
|
||||||
|
uhalni getTextudeId();
|
||||||
|
RenderBuffer* getBuff();
|
||||||
|
|
||||||
|
private:
|
||||||
RenderBuffer mBufferDowncast;
|
RenderBuffer mBufferDowncast;
|
||||||
RenderBuffer mBuffer;
|
RenderBuffer mBuffer;
|
||||||
RenderShader mShader;
|
RenderShader mShader;
|
||||||
|
|
@ -133,96 +60,100 @@ namespace tp {
|
||||||
GLuint mTargetUniform = 0;
|
GLuint mTargetUniform = 0;
|
||||||
GLuint mBGColUniform = 0;
|
GLuint mBGColUniform = 0;
|
||||||
|
|
||||||
public:
|
Vec2F mMaxSize;
|
||||||
Renderer(Vec2F size);
|
|
||||||
|
|
||||||
void renderBegin();
|
|
||||||
void setViewport(RectF viewport);
|
|
||||||
void drawStroke(Stroke* str, Camera* camera);
|
|
||||||
void renderEnd();
|
|
||||||
|
|
||||||
void setClearCol(RGBA col);
|
|
||||||
uhalni getTextudeId();
|
|
||||||
RenderBuffer* getBuff();
|
|
||||||
|
|
||||||
~Renderer();
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
class Stroke {
|
||||||
void Project::save(File& file) {
|
public:
|
||||||
file.write<Camera>(&mCamera);
|
Stroke();
|
||||||
file.write<rgba>(&mBackgroundColor);
|
void denoisePos(halni passes);
|
||||||
file.write<halni>(&mActiveLayer);
|
void denoiseThickness(halni passes);
|
||||||
|
void compress(halnf factor);
|
||||||
|
void subdiv(halnf precition, const Camera* cam, halni passes = 1);
|
||||||
|
void updateGpuBuffers();
|
||||||
|
Buffer<StrokePoint>& getPoints();
|
||||||
|
const Buffer<StrokePoint>& getPoints() const;
|
||||||
|
void setColor(const RGBA& col);
|
||||||
|
const RGBA& getColor() const;
|
||||||
|
|
||||||
alni lay_len = mLayers.length();
|
private:
|
||||||
file.write<alni>(&lay_len);
|
Buffer<StrokePoint> mPoints;
|
||||||
for (auto layer : mLayers) {
|
RGBA mColor;
|
||||||
layer.data()->name.save(&file);
|
|
||||||
|
|
||||||
file.write<bool>(&layer.data()->enabled);
|
friend Renderer;
|
||||||
|
StrokeGPUHandles mGPUHandles;
|
||||||
|
};
|
||||||
|
|
||||||
alni len = layer.data()->strokes.length();
|
struct Layer {
|
||||||
file.write<alni>(&len);
|
Layer() = default;
|
||||||
for (auto stiter : layer.data()->strokes) {
|
~Layer();
|
||||||
stiter->save(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Project::load(File& file) {
|
String name = "new layer";
|
||||||
file.read<Camera>(&mCamera);
|
List<Stroke*> strokes; // TODO use vector
|
||||||
file.read<rgba>(&mBackgroundColor);
|
bool enabled = true;
|
||||||
file.read<halni>(&mActiveLayer);
|
};
|
||||||
|
|
||||||
alni layers_len;
|
class Project {
|
||||||
file.read<alni>(&layers_len);
|
public:
|
||||||
mLayers.reserve(layers_len);
|
Project();
|
||||||
|
~Project();
|
||||||
|
|
||||||
for (alni idx = 0; idx < layers_len; idx++) {
|
// pos from -1 to 1 (left ot right bottom to top)
|
||||||
|
void sample(halnf pressure, halnf cameraRatio, Vec2F relativeCameraPos);
|
||||||
|
|
||||||
string key; key.load(&file);
|
public:
|
||||||
auto layer = new Layer();
|
Buffer<Layer*> mLayers;
|
||||||
layer->name = key;
|
halni mActiveLayer = -1;
|
||||||
mLayers[idx] = layer;
|
|
||||||
|
|
||||||
file.read<bool>(&layer->enabled);
|
Camera mCamera;
|
||||||
|
RGBA mBackgroundColor = { 0.22f, 0.22f, 0.25f, 1.f };
|
||||||
|
|
||||||
alni len;
|
Map<String, Brush*> mBrushes;
|
||||||
file.read<alni>(&len);
|
String mActiveBrush;
|
||||||
|
};
|
||||||
|
|
||||||
for (alni str_idx = 0; str_idx < len; str_idx++) {
|
class Brush {
|
||||||
auto str = new Stroke();
|
public:
|
||||||
layer->strokes.pushBack(str);
|
String mType = "equal";
|
||||||
layer->strokes.last()->data->load(file);
|
Brush() {}
|
||||||
}
|
virtual void sample(Project* proj, Vec2F crs, halnf pressure) {}
|
||||||
}
|
virtual void draw(Renderer* render, const Camera* camera) const {}
|
||||||
}
|
virtual ~Brush() {}
|
||||||
*/
|
};
|
||||||
|
|
||||||
/*
|
class PencilBrush : public Brush {
|
||||||
void Stroke::save(File& file) {
|
public:
|
||||||
file.write<rgba>(&mCol);
|
PencilBrush();
|
||||||
|
virtual ~PencilBrush();
|
||||||
|
|
||||||
alni length = mPoints.length();
|
virtual void sample(Project* proj, Vec2F crs, halnf pressure) override;
|
||||||
file.write<alni>(&length);
|
virtual void draw(Renderer* render, const Camera* camera) const override;
|
||||||
for (auto piter : mPoints) {
|
|
||||||
file.write<Point>(&piter.data());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Stroke::load(File& file) {
|
private:
|
||||||
rgba color;
|
void ensureReady(Stroke* stroke, const Camera* cam, bool debug = false) const;
|
||||||
file.read<rgba>(&color);
|
|
||||||
|
|
||||||
alni p_len;
|
public:
|
||||||
file.read<alni>(&p_len);
|
RGBA mCol = RGBA(1.0f);
|
||||||
|
halnf mSize = 0.01f;
|
||||||
|
|
||||||
mPoints.reserve(p_len);
|
private:
|
||||||
for (auto piter : mPoints) {
|
halnf mPrecision = 0.001f;
|
||||||
file.read<Point>(&piter.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
updateGpuBuffers();
|
halni mDenoisePassesPos = 1;
|
||||||
}
|
halni mDenoisePassesThick = 3;
|
||||||
*/
|
halnf mCompressionFactor = 0.0001f;
|
||||||
|
halni mSubdivPasses = 3;
|
||||||
|
bool mEnableCompression = true;
|
||||||
|
|
||||||
|
halni mMaxPoints = 100;
|
||||||
|
|
||||||
|
Stroke* mStroke = NULL;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EraserBrush : public Brush {
|
||||||
|
EraserBrush() { mType = "eraser"; }
|
||||||
|
virtual void sample(Project* proj, Vec2F crs, halnf pressure) override {}
|
||||||
|
virtual void draw(Renderer* render, const Camera* camera) const override {}
|
||||||
|
virtual ~EraserBrush() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -8,9 +8,6 @@ namespace tp {
|
||||||
template <typename Events, typename Canvas>
|
template <typename Events, typename Canvas>
|
||||||
class Sketch3DWidget : public Widget<Events, Canvas> {
|
class Sketch3DWidget : public Widget<Events, Canvas> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Canvas* mCanvas = nullptr;
|
|
||||||
|
|
||||||
Sketch3DWidget(Canvas& canvas, Vec2F renderResolution) :
|
Sketch3DWidget(Canvas& canvas, Vec2F renderResolution) :
|
||||||
mRenderer(renderResolution) {
|
mRenderer(renderResolution) {
|
||||||
mImage = canvas.createImageFromTextId(mRenderer.getBuff()->texId(), mRenderer.getBuff()->getSize());
|
mImage = canvas.createImageFromTextId(mRenderer.getBuff()->texId(), mRenderer.getBuff()->getSize());
|
||||||
|
|
@ -27,54 +24,25 @@ namespace tp {
|
||||||
this->mVisible = area.isOverlap(areaParent);
|
this->mVisible = area.isOverlap(areaParent);
|
||||||
if (!this->mVisible) return;
|
if (!this->mVisible) return;
|
||||||
|
|
||||||
mProject.mCamera.setRatio(this->mArea.w / this->mArea.z);
|
|
||||||
|
|
||||||
// mProject.mBackgroundColor = col_obj_bg->mCol;
|
|
||||||
|
|
||||||
if (!this->mArea.isInside(events.getPos())) {
|
if (!this->mArea.isInside(events.getPos())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
halnf pressure = 0.f;
|
halnf pressure = 0.f;
|
||||||
|
|
||||||
auto idx = mProject.mBrushes.presents(mProject.mActiveBrush);
|
auto crs = (events.getPos() - this->mArea.pos);
|
||||||
if (idx) {
|
crs.x /= this->mArea.z;
|
||||||
auto brush = mProject.mBrushes.getSlotVal(idx);
|
crs.y /= this->mArea.w;
|
||||||
auto crs = (events.getPos() - this->mArea.pos);
|
crs = (crs - 0.5) * 2;
|
||||||
crs.x /= this->mArea.z;
|
|
||||||
crs.y /= this->mArea.w;
|
|
||||||
crs = (crs - 0.5) * 2;
|
|
||||||
|
|
||||||
if (brush->mType == "pencil") {
|
mProject.sample(pressure, this->mArea.w / this->mArea.z, crs);
|
||||||
((tp::PencilBrush*) brush)->mCol = RGBA(1.f);
|
|
||||||
}
|
|
||||||
|
|
||||||
brush->sample(&mProject, crs, pressure);
|
// mProject.setBackGroundColor();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw(Canvas& canvas) override {
|
void draw(Canvas& canvas) override {
|
||||||
|
if (!this->mVisible) return;
|
||||||
mRenderer.setViewport({ 0, 0, this->mArea.z, this->mArea.w });
|
mRenderer.renderToTexture(&mProject, this->mArea.size);
|
||||||
mRenderer.setClearCol(mProject.mBackgroundColor);
|
|
||||||
mRenderer.renderBegin();
|
|
||||||
|
|
||||||
for (auto lay : mProject.mLayers) {
|
|
||||||
if (lay.data()->enabled) {
|
|
||||||
for (auto str : lay.data()->strokes) {
|
|
||||||
mRenderer.drawStroke(str.data(), &mProject.mCamera);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto idx = mProject.mBrushes.presents(mProject.mActiveBrush);
|
|
||||||
if (idx) {
|
|
||||||
auto brush = mProject.mBrushes.getSlotVal(idx);
|
|
||||||
brush->draw(&mRenderer, &mProject.mCamera);
|
|
||||||
}
|
|
||||||
|
|
||||||
mRenderer.renderEnd();
|
|
||||||
|
|
||||||
canvas.drawImage(this->mArea, &mImage, 0, 1, 12);
|
canvas.drawImage(this->mArea, &mImage, 0, 1, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,5 +50,6 @@ namespace tp {
|
||||||
Project mProject;
|
Project mProject;
|
||||||
Renderer mRenderer;
|
Renderer mRenderer;
|
||||||
Canvas::ImageHandle mImage;
|
Canvas::ImageHandle mImage;
|
||||||
|
Canvas* mCanvas = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue