diff --git a/src/DrawingProgram/BrushTool.cpp b/src/DrawingProgram/BrushTool.cpp index e185697..4a63fd6 100644 --- a/src/DrawingProgram/BrushTool.cpp +++ b/src/DrawingProgram/BrushTool.cpp @@ -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; diff --git a/src/DrawingProgram/EraserTool.cpp b/src/DrawingProgram/EraserTool.cpp index 0f5421e..cbfcbad 100644 --- a/src/DrawingProgram/EraserTool.cpp +++ b/src/DrawingProgram/EraserTool.cpp @@ -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; diff --git a/src/GridManager.cpp b/src/GridManager.cpp index 53b88bb..eefc11a 100644 --- a/src/GridManager.cpp +++ b/src/GridManager.cpp @@ -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 GridManager::get_shader(const sk_sp& runtimeEffect, const SkColor4f& pointColor) { + SkRuntimeShaderBuilder builder(runtimeEffect); + builder.uniform("pointColor") = pointColor; + sk_sp 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)); diff --git a/src/GridManager.hpp b/src/GridManager.hpp index f0e6e87..f12b3e1 100644 --- a/src/GridManager.hpp +++ b/src/GridManager.hpp @@ -24,12 +24,12 @@ class GridManager { GridType gridType = GRIDTYPE_CIRCLEDOT; private: + sk_sp get_shader(const sk_sp& runtimeEffect, const SkColor4f& pointColor); Vector2f oldWindowSize{0.0f, 0.0f}; WorldScalar size{50000000}; SkPath gridPath; - sk_sp circleDotShader; - sk_sp squareDotShader; - sk_sp lineShader; + sk_sp circleDotEffect; + sk_sp squareDotEffect; MainProgram& main; }; diff --git a/src/MainProgram.cpp b/src/MainProgram.cpp index 5282138..9ee8007 100755 --- a/src/MainProgram.cpp +++ b/src/MainProgram.cpp @@ -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); diff --git a/src/MainProgram.hpp b/src/MainProgram.hpp index da35831..b711fe1 100644 --- a/src/MainProgram.hpp +++ b/src/MainProgram.hpp @@ -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(); diff --git a/src/ResourceDisplay/FileResourceDisplay.cpp b/src/ResourceDisplay/FileResourceDisplay.cpp index 6a5c8c9..6a1e689 100644 --- a/src/ResourceDisplay/FileResourceDisplay.cpp +++ b/src/ResourceDisplay/FileResourceDisplay.cpp @@ -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()); diff --git a/src/Server/CommandList.hpp b/src/Server/CommandList.hpp index c6ce284..6beb9b9 100644 --- a/src/Server/CommandList.hpp +++ b/src/Server/CommandList.hpp @@ -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 diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 7dee24a..6c9a004 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -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(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(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(newColorToSet)); + if(gui.text_button_wide("done", "Done")) + optionsMenuOpen = false; + gui.pop_id(); + } + break; + } case SET_DOWNLOAD_NAME: { CLAY({ .layout = { diff --git a/src/Toolbar.hpp b/src/Toolbar.hpp index c1ab9ba..b887f2a 100644 --- a/src/Toolbar.hpp +++ b/src/Toolbar.hpp @@ -147,6 +147,7 @@ class Toolbar { CONNECT_MENU, GENERAL_SETTINGS_MENU, LOBBY_INFO_MENU, + CANVAS_SETTINGS_MENU, SET_DOWNLOAD_NAME, ABOUT_MENU } optionsMenuType; diff --git a/src/World.cpp b/src/World.cpp index 2a986f9..3451826 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -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(canvasTheme.backColor)) { + canvasTheme.backColor = SkColor4f{newBackColor.x(), newBackColor.y(), newBackColor.z(), 1.0f}; + Vector3f newHSV = rgb_to_hsv(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; diff --git a/src/World.hpp b/src/World.hpp index 66f361f..283a7ca 100644 --- a/src/World.hpp +++ b/src/World.hpp @@ -86,6 +86,14 @@ class World { Vector3f userColor = {0.0f, 0.0f, 0.0f}; std::string name; std::unordered_map 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);