From 5c552b0faf7968da75458a6124f269819e468d34 Mon Sep 17 00:00:00 2001 From: Richard Powell Date: Fri, 26 Jan 2024 06:10:13 +0900 Subject: [PATCH] Issue #456: move animation to use draw command --- src/AnimationView.cpp | 257 ++++++++++++++++++----------- src/AnimationView.h | 51 +++--- src/BackgroundImages.cpp | 19 +-- src/BackgroundImages.h | 6 +- src/CalChartDoc.cpp | 4 +- src/CalChartDoc.h | 4 +- src/CalChartDrawPrimativesHelper.h | 35 ++++ src/CalChartDrawing.cpp | 8 + src/CalChartDrawingGetMinSize.h | 6 + src/CalChartView.cpp | 18 +- src/core/CalChartDrawCommand.h | 27 +++ src/core/CalChartImage.cpp | 20 +-- src/core/CalChartImage.h | 14 +- src/core/CalChartSheet.cpp | 12 +- src/core/CalChartSheet.h | 8 +- src/core/CalChartShow.cpp | 4 +- src/core/CalChartShow.h | 4 +- 17 files changed, 311 insertions(+), 186 deletions(-) diff --git a/src/AnimationView.cpp b/src/AnimationView.cpp index d37413c9..b2d94bb2 100644 --- a/src/AnimationView.cpp +++ b/src/AnimationView.cpp @@ -28,6 +28,7 @@ #include "CalChartConfiguration.h" #include "CalChartDrawPrimativesHelper.h" #include "CalChartDrawing.h" +#include "CalChartRanges.h" #include "CalChartShapes.h" #include "CalChartSheet.h" #include "CalChartShowMode.h" @@ -35,17 +36,99 @@ #include "CalChartUtils.h" #include "CalChartView.h" #include "platconf.h" - +#include #include #include #include +namespace { + +// split the source image into a number of horizontal images +auto GenerateSpriteImages(wxImage const& image, int numberImages, int imageX, int imageY, double scale) +{ + return std::views::iota(0, numberImages) | std::views::transform([&image, imageX, imageY, scale](auto i) { + auto newImage = image.GetSubImage({ i * imageX + 0, 0, imageX, imageY }); + return newImage.Scale(newImage.GetWidth() * scale, newImage.GetHeight() * scale); + }); +} + +auto FacingBack(CalChart::Animation::animate_info_t const& info) +{ + auto direction = CalChart::AngleToDirection(info.mFacingDirection); + return direction == CalChart::Direction::SouthWest + || direction == CalChart::Direction::West + || direction == CalChart::Direction::NorthWest; +} + +auto FacingFront(CalChart::Animation::animate_info_t const& info) +{ + auto direction = CalChart::AngleToDirection(info.mFacingDirection); + return direction == CalChart::Direction::SouthEast + || direction == CalChart::Direction::East + || direction == CalChart::Direction::NorthEast; +} + +auto FacingSide(CalChart::Animation::animate_info_t const& info) +{ + return !FacingBack(info) && !FacingFront(info); +} + +auto CollisionWarning(CalChart::Animation::animate_info_t const& info) +{ + return info.mCollision == CalChart::Coord::CollisionType::warning; +} + +auto CollisionIntersect(CalChart::Animation::animate_info_t const& info) +{ + return info.mCollision == CalChart::Coord::CollisionType::intersect; +} + +template + requires(std::is_convertible_v, CalChart::Animation::animate_info_t>) +auto GeneratePointDrawCommand(Range&& infos) -> std::vector +{ + return CalChart::Ranges::ToVector(infos | std::views::transform([](auto&& info) { + auto size = CalChart::Coord{ CalChart::Int2CoordUnits(1), CalChart::Int2CoordUnits(1) }; + return CalChart::Draw::Rectangle{ + info.mPosition - size / 2, { CalChart::Int2CoordUnits(1), CalChart::Int2CoordUnits(1) } + }; + })); +} + +template + requires(std::is_convertible_v, CalChart::Animation::animate_info_t>) +auto GeneratePointDrawCommand(Range&& range, Function predicate, CalChart::BrushAndPen brushAndPen) -> CalChart::Draw::DrawCommand +{ + auto filteredRange = range | std::views::filter(predicate); + if (!filteredRange.empty()) { + return CalChart::Draw::withBrushAndPen(brushAndPen, GeneratePointDrawCommand(filteredRange)); + } + return CalChart::Draw::Ignore{}; +} + +} + AnimationView::AnimationView(CalChartView* view, CalChartConfiguration const& config, wxWindow* frame) : mView(view) , mConfig(config) + , mMeasure{ "AnimationViewDraw" } { SetFrame(frame); + RegenerateImages(); +} + +AnimationView::~AnimationView() +{ +} + +void AnimationView::RegenerateImages() const +{ + auto spriteScale = CalChartConfiguration::GetGlobalConfig().Get_SpriteBitmapScale(); + if (spriteScale == mScaleSize) { + return; + } + mScaleSize = spriteScale; #if defined(__APPLE__) && (__APPLE__) const static wxString kImageDir = "CalChart.app/Contents/Resources/default_sprite_strip.png"; #else @@ -60,118 +143,94 @@ AnimationView::AnimationView(CalChartView* view, CalChartConfiguration const& co return image; }(); // now slice up all the images - auto points = std::vector(mSpriteImages.size()); - std::iota(points.begin(), points.end(), 0); - std::transform(points.begin(), points.end(), mSpriteImages.begin(), [&image](auto i) { - constexpr auto image_X = 64; - constexpr auto image_Y = 128; - return image.GetSubImage({ i * image_X + 0, 0, image_X, image_Y }); + constexpr auto image_X = 64; + constexpr auto image_Y = 128; + auto images = GenerateSpriteImages(image, mSpriteCalChartImages.size(), image_X, image_Y, mScaleSize); + std::transform(images.begin(), images.end(), mSpriteCalChartImages.begin(), [](auto&& image) { + return std::make_shared(wxCalChart::ConvertToImageData(image)); }); } -AnimationView::~AnimationView() -{ -} - void AnimationView::OnDraw(wxDC* dc) { - OnDraw(*dc, mConfig); + // std::cout << mMeasure << "\n"; + // auto snapshot = mMeasure.doMeasurement(); + wxCalChart::Draw::DrawCommandList(*dc, GenerateDraw(mConfig)); } -void AnimationView::OnDraw(wxDC& dc, CalChartConfiguration const& config) +auto AnimationView::GenerateDraw(CalChartConfiguration const& config) const -> std::vector { if (!mAnimation) { // no animation, our job is done. - return; + return {}; } - wxCalChart::setPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::FIELD_DETAIL)); - auto tborder1 = mView->GetShowMode().Border1(); - wxCalChart::Draw::DrawCommandList(dc, CalChartDraw::GenerateModeDrawCommands(config, mView->GetShowMode(), ShowMode_kAnimation) + tborder1); + auto tborder1 = mView->GetShowMode().Border1(); + auto drawCmds = CalChartDraw::GenerateModeDrawCommands(config, mView->GetShowMode(), ShowMode_kAnimation) + tborder1; auto useSprites = config.Get_UseSprites(); if (useSprites) { - return OnDrawSprites(dc, config); + CalChart::append(drawCmds, GenerateDrawSprites(config)); + } else { + CalChart::append(drawCmds, GenerateDrawDots(config)); } - return OnDrawDots(dc, config); -} - -void AnimationView::OnDrawDots(wxDC& dc, CalChartConfiguration const& config) -{ - auto checkForCollision = mDrawCollisionWarning; - for (auto info : mAnimation->GetAllAnimateInfo()) { - if (checkForCollision && (info.mCollision != CalChart::Coord::CollisionType::none)) { - if (info.mCollision == CalChart::Coord::CollisionType::warning) { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_COLLISION_WARNING)); - } else if (info.mCollision == CalChart::Coord::CollisionType::intersect) { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_COLLISION)); - } - } else if (mView->IsSelected(info.index)) { - switch (CalChart::AngleToDirection(info.mFacingDirection)) { - case CalChart::Direction::SouthWest: - case CalChart::Direction::West: - case CalChart::Direction::NorthWest: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_BACK)); - } break; - case CalChart::Direction::SouthEast: - case CalChart::Direction::East: - case CalChart::Direction::NorthEast: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_FRONT)); - } break; - default: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_SIDE)); - } - } - } else { - switch (CalChart::AngleToDirection(info.mFacingDirection)) { - case CalChart::Direction::SouthWest: - case CalChart::Direction::West: - case CalChart::Direction::NorthWest: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_BACK)); - } break; - case CalChart::Direction::SouthEast: - case CalChart::Direction::East: - case CalChart::Direction::NorthEast: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_FRONT)); - } break; - default: { - wxCalChart::setBrushAndPen(dc, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_SIDE)); - } - } - } - auto position = info.mPosition; - auto x = position.x + mView->GetShowMode().Offset().x; - auto y = position.y + mView->GetShowMode().Offset().y; - auto drawPosition = fDIP(wxPoint(x, y)); - auto rectangleSize = fDIP(wxSize(CalChart::Int2CoordUnits(1), CalChart::Int2CoordUnits(1))); + return drawCmds; +} - dc.DrawRectangle(drawPosition - rectangleSize / 2, rectangleSize); +auto AnimationView::GenerateDrawDots(CalChartConfiguration const& config) const -> std::vector +{ + auto allInfo = mAnimation->GetAllAnimateInfo(); + auto allSelected = allInfo | std::views::filter([this](auto&& info) { return mView->IsSelected(info.index); }); + auto allNotSelected = allInfo | std::views::filter([this](auto&& info) { return !mView->IsSelected(info.index); }); + + auto drawCmds = std::vector{}; + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allNotSelected, [](auto&& info) { return FacingBack(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_BACK))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allNotSelected, [](auto&& info) { return FacingFront(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_FRONT))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allNotSelected, [](auto&& info) { return FacingSide(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_SIDE))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allSelected, [](auto&& info) { return FacingBack(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_BACK))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allSelected, [](auto&& info) { return FacingFront(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_FRONT))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allSelected, [](auto&& info) { return FacingSide(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_HILIT_SIDE))); + + if (mDrawCollisionWarning) { + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allInfo, [](auto&& info) { return CollisionWarning(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_COLLISION_WARNING))); + CalChart::append(drawCmds, + GeneratePointDrawCommand( + allInfo, [](auto&& info) { return CollisionIntersect(info); }, config.Get_CalChartBrushAndPen(CalChart::Colors::POINT_ANIM_COLLISION))); } + return drawCmds + mView->GetShowMode().Offset(); } -void AnimationView::OnDrawSprites(wxDC& dc, CalChartConfiguration const& config) +auto AnimationView::GenerateDrawSprites(CalChartConfiguration const& config) const -> std::vector { - auto scale = config.Get_SpriteBitmapScale(); + RegenerateImages(); constexpr auto comp_X = 0.5; auto comp_Y = config.Get_SpriteBitmapOffsetY(); - for (auto info : mAnimation->GetAllAnimateInfo()) { - auto image_offset = !GetAnimationFrame()->TimerOn() ? 0 : OnBeat() ? 1 - : 2; - auto image_index = CalChart::AngleToQuadrant(info.mFacingDirection) + image_offset * 8; - auto image = mSpriteImages[image_index]; - image = image.Scale(image.GetWidth() * scale, image.GetHeight() * scale); - if (mView->IsSelected(info.index)) { - image = image.ConvertToGreyscale(); - } - - auto position = info.mPosition; - auto x = position.x + mView->GetShowMode().Offset().x; - auto y = position.y + mView->GetShowMode().Offset().y; - auto drawPosition = fDIP(wxPoint(x, y)); - auto rectangleSize = fDIP(wxSize(image.GetWidth() * comp_X, image.GetHeight() * comp_Y)); - - dc.DrawBitmap(image, drawPosition - rectangleSize); - } + auto image_offset = !GetAnimationFrame()->TimerOn() ? 0 : OnBeat() ? 1 + : 2; + auto drawCmds = CalChart::Ranges::ToVector( + mAnimation->GetAllAnimateInfo() | std::views::transform([this, image_offset, comp_Y](auto&& info) { + auto image_index = CalChart::AngleToQuadrant(info.mFacingDirection) + image_offset * 8; + auto image = mSpriteCalChartImages[image_index]; + auto position = info.mPosition; + auto offset = CalChart::Coord(image->image_width * comp_X, image->image_height * comp_Y); + + return CalChart::Draw::Image{ position, image, mView->IsSelected(info.index) } - offset; + })); + return drawCmds + mView->GetShowMode().Offset(); } void AnimationView::OnUpdate(wxView* sender, wxObject* hint) @@ -234,7 +293,7 @@ void AnimationView::GotoTotalBeat(unsigned i) } } -bool AnimationView::AtEndOfShow() const +auto AnimationView::AtEndOfShow() const -> bool { if (mAnimation) { return (mAnimation->GetCurrentBeat() == mAnimation->GetTotalNumberBeats()); @@ -248,7 +307,7 @@ static auto towxPoint(CalChart::Coord const& c) } // Return a bounding box of the show -std::pair AnimationView::GetShowSizeAndOffset() const +auto AnimationView::GetShowSizeAndOffset() const -> std::pair { auto size = mView->GetShowFieldSize(); return { towxPoint(size), towxPoint({ 0, 0 }) }; @@ -256,7 +315,7 @@ std::pair AnimationView::GetShowSizeAndOffset() const // Return a bounding box of the show of where the marchers are. If they are // outside the show, we don't see them. -std::pair AnimationView::GetMarcherSizeAndOffset() const +auto AnimationView::GetMarcherSizeAndOffset() const -> std::pair { auto mode_size = towxPoint(mView->GetShowFieldSize()); auto bounding_box_upper_left = mode_size; @@ -297,24 +356,24 @@ void AnimationView::SelectMarchersInBox(wxPoint const& mouseStart, wxPoint const // lives in the Frame. So we have this weird path... void AnimationView::ToggleTimer() { GetAnimationFrame()->ToggleTimer(); } -bool AnimationView::OnBeat() const { return GetAnimationFrame()->OnBeat(); } +auto AnimationView::OnBeat() const -> bool { return GetAnimationFrame()->OnBeat(); } -AnimationPanel const* AnimationView::GetAnimationFrame() const +auto AnimationView::GetAnimationFrame() const -> AnimationPanel const* { return static_cast(GetFrame()); } -AnimationPanel* AnimationView::GetAnimationFrame() +auto AnimationView::GetAnimationFrame() -> AnimationPanel* { return static_cast(GetFrame()); } -CalChart::ShowMode const& AnimationView::GetShowMode() const +auto AnimationView::GetShowMode() const -> CalChart::ShowMode const& { return mView->GetShowMode(); } -AnimationView::MarcherInfo AnimationView::GetMarcherInfo(int which) const +auto AnimationView::GetMarcherInfo(int which) const -> AnimationView::MarcherInfo { MarcherInfo info{}; if (mAnimation) { @@ -330,7 +389,7 @@ AnimationView::MarcherInfo AnimationView::GetMarcherInfo(int which) const return info; } -std::multimap AnimationView::GetMarchersByDistance(float fromX, float fromY) const +auto AnimationView::GetMarchersByDistance(float fromX, float fromY) const -> std::multimap { auto anySelected = !mView->GetSelectionList().empty(); std::multimap result; diff --git a/src/AnimationView.h b/src/AnimationView.h index d30391dd..1fd400c6 100644 --- a/src/AnimationView.h +++ b/src/AnimationView.h @@ -22,7 +22,8 @@ */ #include "CalChartAngles.h" -#include "DCSaveRestore.h" +#include "CalChartDrawCommand.h" +#include "CalChartMeasure.h" #include #include #include @@ -45,28 +46,29 @@ class AnimationView : public wxView { public: AnimationView(CalChartView* view, CalChartConfiguration const& config, wxWindow* frame); ~AnimationView() override; + AnimationView(AnimationView const&) = delete; + auto operator=(AnimationView const&) = delete; + AnimationView(AnimationView&&) = delete; + auto operator=(AnimationView&&) = delete; void OnDraw(wxDC* dc) override; - void OnDraw(wxDC& dc, CalChartConfiguration const& config); - void OnDrawDots(wxDC& dc, CalChartConfiguration const& config); - void OnDrawSprites(wxDC& dc, CalChartConfiguration const& config); - void OnUpdate(wxView* sender, wxObject* hint = (wxObject*)nullptr) override; + void OnUpdate(wxView* sender, wxObject* hint = nullptr) override; void PrevBeat(); void NextBeat(); void GotoTotalBeat(unsigned i); - bool AtEndOfShow() const; + [[nodiscard]] auto AtEndOfShow() const -> bool; void RefreshAnimationSheet(); // info - int GetTotalNumberBeats() const; - int GetTotalCurrentBeat() const; + [[nodiscard]] auto GetTotalNumberBeats() const -> int; + [[nodiscard]] auto GetTotalCurrentBeat() const -> int; - std::pair GetShowSizeAndOffset() const; - std::pair GetMarcherSizeAndOffset() const; + [[nodiscard]] auto GetShowSizeAndOffset() const -> std::pair; + [[nodiscard]] auto GetMarcherSizeAndOffset() const -> std::pair; - CalChart::ShowMode const& GetShowMode() const; + [[nodiscard]] auto GetShowMode() const -> CalChart::ShowMode const&; struct MarcherInfo { CalChart::Radian direction{}; @@ -74,29 +76,33 @@ class AnimationView : public wxView { float y{}; }; - MarcherInfo GetMarcherInfo(int which) const; + [[nodiscard]] auto GetMarcherInfo(int which) const -> MarcherInfo; - std::multimap GetMarchersByDistance(float fromX, float fromY) const; + [[nodiscard]] auto GetMarchersByDistance(float fromX, float fromY) const -> std::multimap; -public: void UnselectAll(); void SelectMarchersInBox(wxPoint const& mouseStart, wxPoint const& mouseEnd, bool altDown); void ToggleTimer(); - bool OnBeat() const; + [[nodiscard]] auto OnBeat() const -> bool; void SetDrawCollisionWarning(bool b) { mDrawCollisionWarning = b; } - auto GetDrawCollisionWarning() const { return mDrawCollisionWarning; } + [[nodiscard]] auto GetDrawCollisionWarning() const { return mDrawCollisionWarning; } void SetPlayCollisionWarning(bool b) { mPlayCollisionWarning = b; } - auto GetPlayCollisionWarning() const { return mPlayCollisionWarning; } + [[nodiscard]] auto GetPlayCollisionWarning() const { return mPlayCollisionWarning; } private: void Generate(); void RefreshFrame(); - AnimationPanel const* GetAnimationFrame() const; - AnimationPanel* GetAnimationFrame(); + void RegenerateImages() const; + [[nodiscard]] auto GenerateDraw(CalChartConfiguration const& config) const -> std::vector; + [[nodiscard]] auto GenerateDrawDots(CalChartConfiguration const& config) const -> std::vector; + [[nodiscard]] auto GenerateDrawSprites(CalChartConfiguration const& config) const -> std::vector; + + [[nodiscard]] auto GetAnimationFrame() const -> AnimationPanel const*; + [[nodiscard]] auto GetAnimationFrame() -> AnimationPanel*; // Yes, this view has a view... CalChartView* mView{}; @@ -113,5 +119,10 @@ class AnimationView : public wxView { Size }; - std::array mSpriteImages; + static constexpr auto kAngles = 8; + // these need to be mutable because effectively they are a cache and may need to be regenerated. + mutable double mScaleSize = 0; + mutable std::array, kAngles * ImageBeat::Size> mSpriteCalChartImages; + + CalChart::MeasureDuration mMeasure; }; diff --git a/src/BackgroundImages.cpp b/src/BackgroundImages.cpp index 3247b595..158007b4 100644 --- a/src/BackgroundImages.cpp +++ b/src/BackgroundImages.cpp @@ -4,7 +4,7 @@ */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ */ #include "BackgroundImages.h" +#include "CalChartDrawPrimativesHelper.h" #include "CalChartImage.h" #include "CalChartTypes.h" #include @@ -314,24 +315,12 @@ wxRect BackgroundImage::CalculateScaleAndMove::operator()(wxCoord x, wxCoord y, BackgroundImages::BackgroundImages() = default; BackgroundImages::~BackgroundImages() = default; -void BackgroundImages::SetBackgroundImages(std::vector const& images) +void BackgroundImages::SetBackgroundImages(std::vector const& images) { mBackgroundImages.clear(); mWhichBackgroundIndex = -1; for (auto&& image : images) { - // ugh... not sure if there's a better way to pass data to image. - auto d = static_cast(malloc(sizeof(unsigned char) * image.image_width * image.image_height * 3)); - std::copy(image.data.begin(), image.data.end(), d); - auto a = static_cast(nullptr); - if (image.alpha.size()) { - a = static_cast(malloc(sizeof(unsigned char) * image.image_width * image.image_height)); - std::copy(image.alpha.begin(), image.alpha.end(), a); - wxImage img(image.image_width, image.image_height, d, a); - mBackgroundImages.emplace_back(img, image.left, image.top, image.scaled_width, image.scaled_height); - } else { - wxImage img(image.image_width, image.image_height, d); - mBackgroundImages.emplace_back(img, image.left, image.top, image.scaled_width, image.scaled_height); - } + mBackgroundImages.emplace_back(wxCalChart::ConvertTowxImage(image.data), image.left, image.top, image.scaled_width, image.scaled_height); } } diff --git a/src/BackgroundImages.h b/src/BackgroundImages.h index 3865bb6b..f13095c1 100644 --- a/src/BackgroundImages.h +++ b/src/BackgroundImages.h @@ -4,7 +4,7 @@ * Maintains the background image data */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -27,7 +27,7 @@ #include namespace CalChart { -struct ImageData; +struct ImageInfo; } class BackgroundImage; @@ -37,7 +37,7 @@ class BackgroundImages { BackgroundImages(); ~BackgroundImages(); - void SetBackgroundImages(std::vector const& images); + void SetBackgroundImages(std::vector const& images); auto GetAdjustBackgroundMode() const { return mAdjustBackgroundMode; } void SetAdjustBackgroundMode(bool adjustBackgroundMode) { mAdjustBackgroundMode = adjustBackgroundMode; } diff --git a/src/CalChartDoc.cpp b/src/CalChartDoc.cpp index f07e9836..27726108 100644 --- a/src/CalChartDoc.cpp +++ b/src/CalChartDoc.cpp @@ -615,10 +615,10 @@ std::unique_ptr CalChartDoc::Create_ToggleLabelVisibilityCommand() return std::make_unique(*this, wxT("Setting Label Visibility"), cmds); } -std::unique_ptr CalChartDoc::Create_AddNewBackgroundImageCommand(int left, int top, int image_width, int image_height, std::vector const& data, std::vector const& alpha) +std::unique_ptr CalChartDoc::Create_AddNewBackgroundImageCommand(ImageInfo const& image) { auto cmds = Create_SetSheetPair(); - cmds.emplace_back(Inject_CalChartDocArg(mShow->Create_AddNewBackgroundImageCommand(ImageData{ left, top, image_width, image_height, image_width, image_height, data, alpha }))); + cmds.emplace_back(Inject_CalChartDocArg(mShow->Create_AddNewBackgroundImageCommand(image))); return std::make_unique(*this, wxT("Adding Background Image"), cmds); } diff --git a/src/CalChartDoc.h b/src/CalChartDoc.h index 904e257b..86fbc4f4 100644 --- a/src/CalChartDoc.h +++ b/src/CalChartDoc.h @@ -4,7 +4,7 @@ */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -224,7 +224,7 @@ class CalChartDoc : public wxDocument { std::unique_ptr Create_ToggleLabelFlipCommand(); std::unique_ptr Create_SetLabelVisibleCommand(bool isVisible); std::unique_ptr Create_ToggleLabelVisibilityCommand(); - std::unique_ptr Create_AddNewBackgroundImageCommand(int left, int top, int image_width, int image_height, std::vector const& data, std::vector const& alpha); + std::unique_ptr Create_AddNewBackgroundImageCommand(CalChart::ImageInfo const& image); std::unique_ptr Create_RemoveBackgroundImageCommand(int which); std::unique_ptr Create_MoveBackgroundImageCommand(int which, int left, int top, int scaled_width, int scaled_height); std::unique_ptr Create_SetTransitionCommand(const std::vector& finalPositions, const std::map& continuities, const std::vector& marcherDotTypes); diff --git a/src/CalChartDrawPrimativesHelper.h b/src/CalChartDrawPrimativesHelper.h index b7cd4254..ce16991f 100644 --- a/src/CalChartDrawPrimativesHelper.h +++ b/src/CalChartDrawPrimativesHelper.h @@ -27,6 +27,7 @@ */ #include "CalChartDrawPrimatives.h" +#include "CalChartImage.h" #include "CalChartSizes.h" #include #include @@ -206,4 +207,38 @@ inline auto setFont(wxDC& dc, CalChart::Font font) dc.SetFont(wxFont(size, family, style, weight)); } +inline auto ConvertToImageData(wxImage const& image) -> CalChart::ImageData +{ + auto width = image.GetWidth(); + auto height = image.GetHeight(); + auto data = std::vector(width * height * 3); + auto* d = image.GetData(); + std::copy(d, d + width * height * 3, data.data()); + auto alpha = std::vector{}; + auto* a = image.GetAlpha(); + if (a) { + alpha.resize(width * height); + std::copy(a, a + width * height, alpha.data()); + } + + return { width, height, data, alpha }; +} + +inline auto ConvertToImageInfo(wxImage const& image, int x = 0, int y = 0) -> CalChart::ImageInfo +{ + auto width = image.GetWidth(); + auto height = image.GetHeight(); + return CalChart::ImageInfo{ x, y, width, height, ConvertToImageData(image) }; +} + +inline auto ConvertTowxImage(CalChart::ImageData const& image) -> wxImage +{ + auto data = image.data; + if (image.alpha.size()) { + auto alpha = image.alpha; + return { image.image_width, image.image_height, data.data(), alpha.data(), true }; + } + return { image.image_width, image.image_height, data.data(), true }; +} + } diff --git a/src/CalChartDrawing.cpp b/src/CalChartDrawing.cpp index 3b7d296e..7c360bc4 100644 --- a/src/CalChartDrawing.cpp +++ b/src/CalChartDrawing.cpp @@ -764,6 +764,14 @@ namespace details { auto where = wxCalChart::to_wxPoint(c.c1) + layoutPoint; DrawText(dc, c.text, fDIP(where), c.anchor, c.withBackground); }, + [&dc, layoutPoint = surface.origin](CalChart::Draw::Image const& c) { + auto where = wxCalChart::to_wxPoint(c.mStart) + layoutPoint; + auto image = wxCalChart::ConvertTowxImage(*c.mImage); + if (c.mGreyscale) { + image = image.ConvertToGreyscale(); + } + dc.DrawBitmap(image, fDIP(where)); + }, []([[maybe_unused]] CalChart::Draw::Ignore const& c) { }, []([[maybe_unused]] CalChart::Draw::Tab const& c) { diff --git a/src/CalChartDrawingGetMinSize.h b/src/CalChartDrawingGetMinSize.h index a3065157..14beaa6a 100644 --- a/src/CalChartDrawingGetMinSize.h +++ b/src/CalChartDrawingGetMinSize.h @@ -156,6 +156,12 @@ namespace details { return wxSize(width, metrics.height + text.linePad); } + inline auto GetMinSize([[maybe_unused]] Context context, CalChart::Draw::Image const& image) -> StackSize + { + // TODO: should this have scale in it? + return wxSize(image.mImage->image_width, image.mImage->image_width); + } + inline auto GetMinSize(Context context, CalChart::Draw::DrawManipulators const& cmd) -> StackSize; inline auto GetMinSize(Context context, CalChart::Draw::DrawStack const& cmd) -> StackSize; diff --git a/src/CalChartView.cpp b/src/CalChartView.cpp index 3952c6aa..f10d0445 100644 --- a/src/CalChartView.cpp +++ b/src/CalChartView.cpp @@ -30,6 +30,7 @@ #include "CalChartDoc.h" #include "CalChartDocCommand.h" #include "CalChartDrawCommand.h" +#include "CalChartDrawPrimativesHelper.h" #include "CalChartDrawing.h" #include "CalChartFrame.h" #include "CalChartShapes.h" @@ -608,22 +609,7 @@ bool CalChartView::AddBackgroundImage(const wxImage& image) if (!image.IsOk()) { return false; } - auto x = 100; - auto y = 100; - - auto width = image.GetWidth(); - auto height = image.GetHeight(); - std::vector data(width * height * 3); - auto d = image.GetData(); - std::copy(d, d + width * height * 3, data.data()); - std::vector alpha; - auto a = image.GetAlpha(); - if (a) { - alpha.resize(width * height); - std::copy(a, a + width * height, alpha.data()); - } - - auto cmd = mShow->Create_AddNewBackgroundImageCommand(x, y, width, height, data, alpha); + auto cmd = mShow->Create_AddNewBackgroundImageCommand(wxCalChart::ConvertToImageInfo(image, 100, 100)); GetDocument()->GetCommandProcessor()->Submit(cmd.release()); return true; } diff --git a/src/core/CalChartDrawCommand.h b/src/core/CalChartDrawCommand.h index 04f74525..f5ebfaa2 100644 --- a/src/core/CalChartDrawCommand.h +++ b/src/core/CalChartDrawCommand.h @@ -24,9 +24,11 @@ #include "CalChartConstants.h" #include "CalChartCoord.h" #include "CalChartDrawPrimatives.h" +#include "CalChartImage.h" #include #include #include +#include #include #include #include @@ -74,6 +76,7 @@ namespace Draw { struct Circle; struct Rectangle; struct Text; + struct Image; struct Tab; using DrawItems = std::variant< Ignore, @@ -83,6 +86,7 @@ namespace Draw { Circle, Rectangle, Text, + Image, Tab>; // meta manipulators @@ -327,6 +331,29 @@ namespace Draw { inline auto operator-(Text const& lhs, Coord rhs) { return Text{ lhs.c1 - rhs, lhs.text, lhs.anchor, lhs.withBackground, lhs.linePad }; } inline auto operator-(Coord lhs, Text const& rhs) { return Text{ lhs - rhs.c1, rhs.text, rhs.anchor, rhs.withBackground, rhs.linePad }; } + struct Image { + Coord mStart{}; + std::shared_ptr mImage{}; + bool mGreyscale{}; + + Image(Coord::units startx, Coord::units starty, std::shared_ptr image, bool greyscale = false) + : Image{ { startx, starty }, std::move(image), greyscale } + { + } + + Image(Coord start, std::shared_ptr image, bool greyscale = false) + : mStart{ start } + , mImage{ std::move(image) } + , mGreyscale{ greyscale } + { + } + friend auto operator==(Image const&, Image const&) -> bool = default; + }; + inline auto operator+(Image lhs, Coord rhs) { return Image{ lhs.mStart + rhs, lhs.mImage, lhs.mGreyscale }; } + inline auto operator+(Coord lhs, Image rhs) { return Image{ lhs + rhs.mStart, rhs.mImage, rhs.mGreyscale }; } + inline auto operator-(Image lhs, Coord rhs) { return Image{ lhs.mStart - rhs, lhs.mImage, lhs.mGreyscale }; } + inline auto operator-(Coord lhs, Image rhs) { return Image{ lhs - rhs.mStart, rhs.mImage, rhs.mGreyscale }; } + struct OverrideFont { Font font; std::vector commands{}; diff --git a/src/core/CalChartImage.cpp b/src/core/CalChartImage.cpp index 8ec92eda..df603b48 100644 --- a/src/core/CalChartImage.cpp +++ b/src/core/CalChartImage.cpp @@ -3,7 +3,7 @@ */ /* - Copyright (C) 2017 Richard Michael Powell + Copyright (C) 2017-2024 Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -24,7 +24,7 @@ namespace CalChart { -auto CreateImageData(Reader reader) -> std::pair +auto CreateImageInfo(Reader reader) -> std::pair { auto left = reader.Get(); auto top = reader.Get(); @@ -36,24 +36,24 @@ auto CreateImageData(Reader reader) -> std::pair auto alpha = reader.GetVector(); scaled_width = (scaled_width == 0) ? image_width : scaled_width; scaled_height = (scaled_height == 0) ? image_height : scaled_height; - return { ImageData{ left, top, scaled_width, scaled_height, image_width, image_height, data, alpha }, reader }; + return { ImageInfo{ left, top, scaled_width, scaled_height, ImageData{ image_width, image_height, data, alpha } }, reader }; } -auto Serialize(ImageData const& image) -> std::vector +auto Serialize(ImageInfo const& image) -> std::vector { std::vector result; Parser::Append(result, uint32_t(image.left)); Parser::Append(result, uint32_t(image.top)); Parser::Append(result, uint32_t(image.scaled_width)); Parser::Append(result, uint32_t(image.scaled_height)); - Parser::Append(result, uint32_t(image.image_width)); - Parser::Append(result, uint32_t(image.image_height)); + Parser::Append(result, uint32_t(image.data.image_width)); + Parser::Append(result, uint32_t(image.data.image_height)); // we know data size, but let's put it in anyways - Parser::Append(result, uint32_t(image.data.size())); - Parser::Append(result, image.data); + Parser::Append(result, uint32_t(image.data.data.size())); + Parser::Append(result, image.data.data); // alpha could be zero - Parser::Append(result, uint32_t(image.alpha.size())); - Parser::Append(result, image.alpha); + Parser::Append(result, uint32_t(image.data.alpha.size())); + Parser::Append(result, image.data.alpha); return result; } } diff --git a/src/core/CalChartImage.h b/src/core/CalChartImage.h index c90b97d0..c552dcc4 100644 --- a/src/core/CalChartImage.h +++ b/src/core/CalChartImage.h @@ -4,7 +4,7 @@ */ /* - Copyright (C) 2017 Richard Michael Powell + Copyright (C) 2017-2024 Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,14 +28,18 @@ namespace CalChart { class Reader; struct ImageData { - int left, top; - int scaled_width, scaled_height; int image_width, image_height; std::vector data; std::vector alpha; }; -auto CreateImageData(Reader) -> std::pair; -auto Serialize(ImageData const&) -> std::vector; +struct ImageInfo { + int left, top; + int scaled_width, scaled_height; + ImageData data; +}; + +auto CreateImageInfo(Reader) -> std::pair; +auto Serialize(ImageInfo const&) -> std::vector; } diff --git a/src/core/CalChartSheet.cpp b/src/core/CalChartSheet.cpp index 6825f941..4fff64ab 100644 --- a/src/core/CalChartSheet.cpp +++ b/src/core/CalChartSheet.cpp @@ -4,7 +4,7 @@ */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -383,7 +383,7 @@ Sheet::Sheet(size_t numPoints, Reader reader, ParseErrorHandlers const* correcti auto parse_INGL_BACK = [](Sheet* sheet, Reader reader) { auto num = reader.Get(); while (num--) { - auto [image, new_reader] = CreateImageData(reader); + auto [image, new_reader] = CreateImageInfo(reader); sheet->mBackgroundImages.push_back(image); reader = new_reader; } @@ -449,7 +449,7 @@ auto Sheet::SerializePrintContinuityData() const -> std::vector return result; } -auto Sheet::SerializeBackgroundImageData() const -> std::vector +auto Sheet::SerializeBackgroundImageInfo() const -> std::vector { std::vector result; Parser::Append(result, static_cast(mBackgroundImages.size())); @@ -486,7 +486,7 @@ auto Sheet::SerializeSheetData() const -> std::vector INGL_PCNT, SerializePrintContinuityData())); // Write Background - Parser::Append(result, Parser::Construct_block(INGL_BACK, SerializeBackgroundImageData())); + Parser::Append(result, Parser::Construct_block(INGL_BACK, SerializeBackgroundImageInfo())); return result; } @@ -780,12 +780,12 @@ void Sheet::sheet_round_trip_test() void Sheet_UnitTests() { Sheet::sheet_round_trip_test(); } -std::vector const& Sheet::GetBackgroundImages() const +std::vector const& Sheet::GetBackgroundImages() const { return mBackgroundImages; } -void Sheet::AddBackgroundImage(ImageData const& image, size_t where) +void Sheet::AddBackgroundImage(ImageInfo const& image, size_t where) { auto insert_point = mBackgroundImages.begin() + std::min(where, mBackgroundImages.size()); mBackgroundImages.insert(insert_point, image); diff --git a/src/core/CalChartSheet.h b/src/core/CalChartSheet.h index 57029ade..8253ab0f 100644 --- a/src/core/CalChartSheet.h +++ b/src/core/CalChartSheet.h @@ -61,7 +61,7 @@ class Sheet { auto SerializeAllPoints() const -> std::vector; auto SerializeContinuityData() const -> std::vector; auto SerializePrintContinuityData() const -> std::vector; - auto SerializeBackgroundImageData() const -> std::vector; + auto SerializeBackgroundImageInfo() const -> std::vector; auto SerializeSheetData() const -> std::vector; public: @@ -108,8 +108,8 @@ class Sheet { void SetNumber(std::string const& newnumber); // image - std::vector const& GetBackgroundImages() const; - void AddBackgroundImage(ImageData const& image, size_t where); + std::vector const& GetBackgroundImages() const; + void AddBackgroundImage(ImageInfo const& image, size_t where); void RemoveBackgroundImage(size_t which); void MoveBackgroundImage(size_t which, int left, int top, int scaled_width, int scaled_height); @@ -132,7 +132,7 @@ class Sheet { unsigned short mBeats; std::vector mPoints; std::string mName; - std::vector mBackgroundImages; + std::vector mBackgroundImages; // unit tests friend void Sheet_UnitTests(); diff --git a/src/core/CalChartShow.cpp b/src/core/CalChartShow.cpp index ecff6250..e9cc8df1 100644 --- a/src/core/CalChartShow.cpp +++ b/src/core/CalChartShow.cpp @@ -4,7 +4,7 @@ */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -968,7 +968,7 @@ Show_command_pair Show::Create_ToggleLabelVisibilityCommand() const return Create_SetLabelVisiblityCommand(visible); } -Show_command_pair Show::Create_AddNewBackgroundImageCommand(ImageData const& image) const +Show_command_pair Show::Create_AddNewBackgroundImageCommand(ImageInfo const& image) const { auto sheet = GetCurrentSheet(); auto action = [sheet_num = mSheetNum, image, where = sheet->GetBackgroundImages().size()](Show& show) { diff --git a/src/core/CalChartShow.h b/src/core/CalChartShow.h index 352f90f2..d78b898e 100644 --- a/src/core/CalChartShow.h +++ b/src/core/CalChartShow.h @@ -5,7 +5,7 @@ */ /* - Copyright (C) 1995-2011 Garrick Brian Meeker, Richard Michael Powell + Copyright (C) 1995-2024 Garrick Brian Meeker, Richard Michael Powell This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -112,7 +112,7 @@ class Show { Show_command_pair Create_SetLabelVisiblityCommand(std::map const& new_visibility) const; Show_command_pair Create_SetLabelVisibleCommand(bool isVisible) const; Show_command_pair Create_ToggleLabelVisibilityCommand() const; - Show_command_pair Create_AddNewBackgroundImageCommand(ImageData const& image) const; + Show_command_pair Create_AddNewBackgroundImageCommand(ImageInfo const& image) const; Show_command_pair Create_RemoveBackgroundImageCommand(int which) const; Show_command_pair Create_MoveBackgroundImageCommand(int which, int left, int top, int scaled_width, int scaled_height) const;