#include "BrushTool.h" #include "../Commands/Brushstroke.h" #include "../LayerNodes/PaintLayerNode.h" #include "../ManagementContext/StyleManagmentContext.h" #include "../UserData.h" #include void BrushTool::OnDeactivate() { } void BrushTool::OnActivate() { if (Brushes.empty()) { // only load if not already loaded LoadBrushes(); } RequestBrushlistRefresh = true; if (!activeBrush) return; // no brushes available activeBrush->LoadStampTexture(); SetActiveBrush(activeBrush); // reinit tool values } void BrushTool::OnRender() { if (!target || !activeBrush || inputQueue.empty()) { return; } auto paintLayer = dynamic_cast(LayerManagementContext::SelectedLayer); if (!paintLayer) return; if (!strokeContext) { strokeContext = new StrokeRenderingContext(activeBrush, LayerManagementContext::FinalWidth, LayerManagementContext::FinalHeight, Color, Size); } auto requeue = std::queue>(); bool cancelled = false; while (inputQueue.size() > 0) { std::shared_ptr stream = inputQueue.front(); inputQueue.pop(); if (stream->IsCancelled()) { cancelled = true; break; } strokeContext->SubmitInputs(stream->PullFilteredInputs(8000000ULL, 0.5)); // 125hz if (!stream->GetComplete()) { requeue.push(stream); } } inputQueue = requeue; preview = strokeContext->RenderQueued(¤tBoundingBox); if (strokeContext->IsComplete()) { // handoff to command auto command = std::make_unique(strokeContext, paintLayer, isEraser, activeBrush); strokeContext = nullptr; history->Execute(std::move(command)); preview = nullptr; } if (cancelled) { delete strokeContext; strokeContext = nullptr; delete preview; preview = nullptr; } } void BrushTool::LoadBrushes() { for (auto* b : Brushes) delete b; // delete objects first Brushes.clear(); std::string brushesDir = UserData::GetBrushesDir(); std::list paths; for (const auto& entry : std::filesystem::directory_iterator(brushesDir)) { if (entry.path().extension() == ".json") { paths.push_back(entry.path().string()); } } paths.sort(); for (const std::string& path : paths) { Brushes.push_back(new Brush(path)); } activeBrush = Brushes.front(); } bool BrushTool::IsEraser() { return isEraser; } void BrushTool::SetActiveBrush(Brush* brush) { activeBrush = brush; activeBrush->LoadStampTexture(); Tool::Size = &activeBrush->Size; Tool::Flow = &activeBrush->Flow; Tool::Opacity = &activeBrush->Opacity; Tool::SetColor(Tool::Color[0], Tool::Color[1], Tool::Color[2]); } void BrushTool::OnGuiRender() { char stringBuffers[3][20]; std::sprintf(stringBuffers[0], "Size: %.1f px", (float)(*Size)); std::sprintf(stringBuffers[1], "Flow: %.1f%%%%", (float)(*Flow * 100.0)); // double %% because used as format std::sprintf(stringBuffers[2], "Opacity: %.1f%%%%", (float)(*Opacity * 100.0)); // double %% because used as format const ImGuiViewport* viewport = ImGui::GetMainViewport(); ImVec2 work_pos = viewport->WorkPos; // Use work area to avoid menu-bar/task-bar, if any! ImVec2 work_size = viewport->WorkSize; ImVec2 window_pos; window_pos.x = work_pos.x + (work_size.x / 2); window_pos.y = work_pos.y + work_size.y - 64; ImGui::SetNextWindowPos((window_pos), 0, ImVec2(0.5f, 1.0f)); StyleManagmentContext::Push(TOOLBAR); ImGui::Begin("Quick Sliders", (bool*)NULL, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove);// | ImGuiWindowFlags_NoBackground); ImGui::PushItemWidth(0.0f); ImGui::SliderFloat("##SizeSlider", Size, 0.3f, 1000.0f, stringBuffers[0], ImGuiSliderFlags_Logarithmic); ImGui::SameLine(); ImGui::SliderFloat("##FlowSlider", Flow, 0.0f, 1.0f, stringBuffers[1]); ImGui::SameLine(); ImGui::SliderFloat("##OpacitySlider", Opacity, 0.0f, 1.0f, stringBuffers[2]); ImGui::PopItemWidth(); ImGui::End(); StyleManagmentContext::Pop(); }