Can change canvas background color

This commit is contained in:
Yousef Khadadeh 2025-08-01 10:58:45 +03:00
parent 0b1cc8d4c2
commit 6cec654d4c
12 changed files with 93 additions and 25 deletions

View file

@ -185,7 +185,7 @@ void BrushTool::commit_stroke() {
void BrushTool::draw(SkCanvas* canvas, const DrawData& drawData) {
if(!drawData.main->toolbar.io->hoverObstructed) {
SkPaint linePaint;
linePaint.setColor4f(drawP.world.main.canvasTheme.toolFrontColor);
linePaint.setColor4f(drawP.world.canvasTheme.toolFrontColor);
linePaint.setStroke(true);
linePaint.setStrokeWidth(0.0f);
float width;

View file

@ -66,7 +66,7 @@ bool EraserTool::prevent_undo_or_redo() {
void EraserTool::draw(SkCanvas* canvas, const DrawData& drawData) {
if(!drawData.main->toolbar.io->hoverObstructed) {
SkColor4f c = drawP.world.main.canvasTheme.toolFrontColor;
SkColor4f c = drawP.world.canvasTheme.toolFrontColor;
c.fA = 0.5f;
SkPaint linePaint;

View file

@ -8,20 +8,33 @@
#define GRID_CACHE_SIZE_INT 10
#define GRID_DOT_SIZE 0.5f
// NOTE: Skia shaders return premultiplied alpha colors
const char* squareDotGridSkSl =
R"V(half4 main(float2 fragCoord) {
R"V(
uniform vec4 pointColor;
vec4 main(float2 fragCoord) {
float m1 = step(mod(fragCoord.x + 0.25, 10.0), 0.5);
float m2 = step(mod(fragCoord.y + 0.25, 10.0), 0.5);
float fin = m1 * m2;
return half4(fin);
vec4 pointColorUnmultiplied = vec4(pointColor.rgb, 1.0);
return pointColorUnmultiplied * pointColor.a * fin;
})V";
const char* circleDotGridSkSl =
R"V(half4 main(float2 fragCoord) {
R"V(
uniform vec4 pointColor;
vec4 main(float2 fragCoord) {
float2 modCoord = mod(fragCoord + float2(5.0), float2(10.0));
float fin = step(distance(float2(5.0), modCoord), 0.25);
return half4(fin);
vec4 pointColorUnmultiplied = vec4(pointColor.rgb, 1.0);
return pointColorUnmultiplied * pointColor.a * fin;
})V";
GridManager::GridManager(MainProgram& initMain):
@ -32,16 +45,21 @@ GridManager::GridManager(MainProgram& initMain):
std::cout << "[GridManager::GridManager] Circle dot shader construction error\n";
std::cout << err.c_str() << std::endl;
}
else
circleDotShader = effect->makeShader(nullptr, {nullptr, 0});
circleDotEffect = effect;
auto [effect2, err2] = SkRuntimeEffect::MakeForShader(SkString(squareDotGridSkSl));
if(!err2.isEmpty()) {
std::cout << "[GridManager::GridManager] Square dot shader construction error\n";
std::cout << err2.c_str() << std::endl;
}
else
squareDotShader = effect2->makeShader(nullptr, {nullptr, 0});
squareDotEffect = effect2;
}
sk_sp<SkShader> GridManager::get_shader(const sk_sp<SkRuntimeEffect>& runtimeEffect, const SkColor4f& pointColor) {
SkRuntimeShaderBuilder builder(runtimeEffect);
builder.uniform("pointColor") = pointColor;
sk_sp<SkShader> s = builder.makeShader();
return s;
}
void GridManager::draw(SkCanvas* canvas, const DrawData& drawData) {
@ -73,11 +91,12 @@ void GridManager::draw(SkCanvas* canvas, const DrawData& drawData) {
SkPaint linePaint;
if(gridType == GRIDTYPE_CIRCLEDOT || gridType == GRIDTYPE_SQUAREDOT) {
linePaint.setShader(gridType == 1 ? circleDotShader : squareDotShader);
linePaint.setAlphaf(std::clamp(alteredZoom / 20.0f, 0.0f, 0.4f));
SkColor4f pointColor = main.world->canvasTheme.toolFrontColor;
pointColor.fA = std::clamp(alteredZoom / 20.0f, 0.0f, 0.4f);
linePaint.setShader(get_shader(gridType == 1 ? circleDotEffect : squareDotEffect, pointColor));
}
else if(gridType == GRIDTYPE_LINE) {
linePaint.setColor4f({1.0f, 1.0f, 1.0f, 1.0f});
linePaint.setColor4f(main.world->canvasTheme.toolFrontColor);
linePaint.setStyle(SkPaint::kStroke_Style);
linePaint.setStrokeWidth(0.0f);
linePaint.setAlphaf(std::clamp(alteredZoom / 35.0f, 0.0f, 0.3f));

View file

@ -24,12 +24,12 @@ class GridManager {
GridType gridType = GRIDTYPE_CIRCLEDOT;
private:
sk_sp<SkShader> get_shader(const sk_sp<SkRuntimeEffect>& runtimeEffect, const SkColor4f& pointColor);
Vector2f oldWindowSize{0.0f, 0.0f};
WorldScalar size{50000000};
SkPath gridPath;
sk_sp<SkShader> circleDotShader;
sk_sp<SkShader> squareDotShader;
sk_sp<SkShader> lineShader;
sk_sp<SkRuntimeEffect> circleDotEffect;
sk_sp<SkRuntimeEffect> squareDotEffect;
MainProgram& main;
};

View file

@ -252,7 +252,7 @@ void MainProgram::load_config() {
}
void MainProgram::draw(SkCanvas* canvas) {
canvas->clear(transparentBackground ? SkColor4f{0.0f, 0.0f, 0.0f, 0.0f} : canvasTheme.backColor);
canvas->clear(transparentBackground ? SkColor4f{0.0f, 0.0f, 0.0f, 0.0f} : world->canvasTheme.backColor);
grid.draw(canvas, world->drawData);
world->draw(canvas);
toolbar.draw(canvas);

View file

@ -92,11 +92,6 @@ class MainProgram {
void early_destroy();
struct CanvasTheme {
SkColor4f backColor = {0.12f, 0.12f, 0.12f, 1.0f};
SkColor4f toolFrontColor = {1.0f, 1.0f, 1.0f, 1.0f};
} canvasTheme;
void new_tab(const World::OpenWorldInfo& tabInfo, bool createSameThread = false);
void set_tab_to_close(size_t tabToClose);
bool network_being_used();

View file

@ -38,7 +38,7 @@ void FileResourceDisplay::draw(SkCanvas* canvas, const DrawData& drawData, const
svgDom = findSVGData->second;
SkPaint blendingPaint;
blendingPaint.setColorFilter(SkColorFilters::Blend(drawData.main->canvasTheme.toolFrontColor, SkColorSpace::MakeSRGB(), SkBlendMode::kSrcIn));
blendingPaint.setColorFilter(SkColorFilters::Blend(drawData.main->world->canvasTheme.toolFrontColor, SkColorSpace::MakeSRGB(), SkBlendMode::kSrcIn));
canvas->saveLayer(imRect, &blendingPaint);
canvas->translate(imRect.x(), imRect.y());
canvas->scale(imRect.width() / svgDom->containerSize().width(), imRect.height() / svgDom->containerSize().height());

View file

@ -17,7 +17,8 @@ enum ServerCommands : MessageCommandType {
SERVER_RESOURCE_DATA,
SERVER_CHAT_MESSAGE,
SERVER_NEW_BOOKMARK,
SERVER_REMOVE_BOOKMARK
SERVER_REMOVE_BOOKMARK,
SERVER_CANVAS_COLOR
};
enum ClientCommands : MessageCommandType {
@ -36,7 +37,8 @@ enum ClientCommands : MessageCommandType {
CLIENT_NEW_RESOURCE,
CLIENT_CHAT_MESSAGE,
CLIENT_NEW_BOOKMARK,
CLIENT_REMOVE_BOOKMARK
CLIENT_REMOVE_BOOKMARK,
CLIENT_CANVAS_COLOR
};
// NOTE: Do not change savefile header length

View file

@ -476,6 +476,10 @@ void Toolbar::top_toolbar() {
optionsMenuOpen = true;
optionsMenuType = HOST_MENU;
}
if(gui.text_button_wide("canvas specific settings", "Canvas Settings")) {
optionsMenuOpen = true;
optionsMenuType = CANVAS_SETTINGS_MENU;
}
if(gui.text_button_wide("start connecting", "Connect")) {
serverToConnectTo.clear();
optionsMenuOpen = true;
@ -1364,6 +1368,31 @@ void Toolbar::options_menu() {
}
break;
}
case CANVAS_SETTINGS_MENU: {
CLAY({
.layout = {
.sizing = {.width = CLAY_SIZING_FIT(500), .height = CLAY_SIZING_FIT(0) },
.padding = CLAY_PADDING_ALL(io->theme->padding1),
.childGap = io->theme->childGap1,
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP},
.layoutDirection = CLAY_TOP_TO_BOTTOM
},
.backgroundColor = convert_vec4<Clay_Color>(io->theme->backColor1),
.cornerRadius = CLAY_CORNER_RADIUS(io->theme->windowCorners1),
.floating = {.attachPoints = {.element = CLAY_ATTACH_POINT_CENTER_CENTER, .parent = CLAY_ATTACH_POINT_CENTER_CENTER}, .attachTo = CLAY_ATTACH_TO_PARENT},
.border = {.color = convert_vec4<Clay_Color>(io->theme->backColor2), .width = CLAY_BORDER_OUTSIDE(io->theme->windowBorders1)}
}) {
gui.push_id("canvas settings menu");
gui.obstructing_window();
SkColor4f newColorToSet = main.world->canvasTheme.backColor;
gui.color_picker_button_field("canvasColor", "Canvas Color", &newColorToSet, false);
main.world->set_canvas_background_color(convert_vec3<Vector3f>(newColorToSet));
if(gui.text_button_wide("done", "Done"))
optionsMenuOpen = false;
gui.pop_id();
}
break;
}
case SET_DOWNLOAD_NAME: {
CLAY({
.layout = {

View file

@ -147,6 +147,7 @@ class Toolbar {
CONNECT_MENU,
GENERAL_SETTINGS_MENU,
LOBBY_INFO_MENU,
CANVAS_SETTINGS_MENU,
SET_DOWNLOAD_NAME,
ABOUT_MENU
} optionsMenuType;

View file

@ -1,5 +1,6 @@
#include "World.hpp"
#include "DrawComponents/DrawComponent.hpp"
#include "Helpers/HsvRgb.hpp"
#include "Helpers/MathExtras.hpp"
#include "Helpers/Networking/ByteStream.hpp"
#include "Server/CommandList.hpp"
@ -165,6 +166,19 @@ void World::unfocus_update() {
con.update();
}
void World::set_canvas_background_color(const Vector3f& newBackColor) {
if(newBackColor != convert_vec3<Vector3f>(canvasTheme.backColor)) {
canvasTheme.backColor = SkColor4f{newBackColor.x(), newBackColor.y(), newBackColor.z(), 1.0f};
Vector3f newHSV = rgb_to_hsv<Vector3f>(newBackColor);
if(newHSV.z() >= 0.6f) {
canvasTheme.toolFrontColor = SkColor4f{0.0f, 0.0f, 0.0f, 1.0f};
}
else {
canvasTheme.toolFrontColor = SkColor4f{1.0f, 1.0f, 1.0f, 1.0f};
}
}
}
void World::send_chat_message(const std::string& message) {
if(!clientStillConnecting) {
std::string newMessage = "[" + displayName + "] " + message;

View file

@ -86,6 +86,14 @@ class World {
Vector3f userColor = {0.0f, 0.0f, 0.0f};
std::string name;
std::unordered_map<ServerPortionID, ClientData> clients;
void set_canvas_background_color(const Vector3f& newBackColor);
struct CanvasTheme {
SkColor4f backColor = {0.12f, 0.12f, 0.12f, 1.0f};
SkColor4f toolFrontColor = {1.0f, 1.0f, 1.0f, 1.0f};
} canvasTheme;
private:
void init_client_callbacks();
void set_name(const std::string& n);