From 77878b723ae2d9d693bad009bbed7e6e4e681193 Mon Sep 17 00:00:00 2001 From: The Bearodactyl Date: Sun, 3 Nov 2024 16:52:19 -0600 Subject: [PATCH] RAAAAAHHHHHHH RAAAAAHHHHHHH --- .gitignore | 2 + CMakeLists.txt | 4 + mod.json | 48 ++-- resources/addIcon.png | Bin 0 -> 10402 bytes src/includes.hpp | 42 ++++ src/main.cpp | 107 +++------ src/settings/list_cell.cpp | 13 ++ src/settings/list_cell.hpp | 16 ++ src/settings/multi_string_setting.cpp | 259 ++++++++++++++++++++++ src/settings/multi_string_setting.hpp | 82 +++++++ src/trail_customization/rainbow_trail.cpp | 46 ++-- src/trail_customization/rainbow_trail.hpp | 2 +- src/types/serializable_vector.hpp | 55 +++++ src/utils/color_utils.cpp | 131 +++++++---- src/utils/color_utils.hpp | 7 + 15 files changed, 641 insertions(+), 173 deletions(-) create mode 100644 resources/addIcon.png create mode 100644 src/includes.hpp create mode 100644 src/settings/list_cell.cpp create mode 100644 src/settings/list_cell.hpp create mode 100644 src/settings/multi_string_setting.cpp create mode 100644 src/settings/multi_string_setting.hpp create mode 100644 src/types/serializable_vector.hpp diff --git a/.gitignore b/.gitignore index beb171c..6a71e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ build-*/ # Visual Studio .vs/ + +bindings/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 7eb5ecc..f820fc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64") set(CMAKE_CXX_VISIBILITY_PRESET hidden) +set(GEODE_BINDINGS_REPO_PATH "D:\\Projects\\gay-wave-trail\\bindings\\") project(gay-wave-trail VERSION 1.0.0) @@ -14,6 +15,9 @@ file( src/trail_customization/*.cpp src/settings/*.cpp src/ui/*.cpp + src/types/*.cpp + src/types/*.hpp + src/*.hpp ) add_library(${PROJECT_NAME} SHARED ${SOURCES}) diff --git a/mod.json b/mod.json index 5c50151..1484a53 100644 --- a/mod.json +++ b/mod.json @@ -1,5 +1,5 @@ { - "geode": "3.8.1", + "geode": "3.4.0", "gd": { "win": "2.206", "android": "2.206", @@ -67,12 +67,6 @@ "type": "bool", "default": false }, - "rainbow-icon": { - "name": "First it was just the trail...", - "description": "NOW THE ICON TOO???\noh my fuckin sex, i\nam so dissapointed.\n(changes the wave icon color)", - "type": "bool", - "default": false - }, "saturation": { "name": "HOW GAY ARE YOU???", "type": "float", @@ -109,9 +103,11 @@ "default": false }, "gaydient-section": { - "type": "title", "name": "Gaydient Settings", - "description": "make kayla gay" + "type": "custom", + "description": "make kayla gay", + "scale": 300, + "posX": 80 }, "use-gradient": { "name": "Enable the GAYDIENT", @@ -119,34 +115,18 @@ "type": "bool", "default": false }, - "color-one": { - "name": "Wave trail color #1", - "description": "The first color the wave trail will become", - "type": "color", - "default": "#FFFFFF" - }, - "color-two": { - "name": "Wave trail color #2", - "description": "The second color the wave trail will become", - "type": "color", - "default": "#FFFFFF" - }, - "color-three": { - "name": "Wave trail color #3", - "description": "The third color the wave trail will become", - "type": "color", - "default": "#FFFFFF" - }, - "color-four": { - "name": "Wave trail color #4", - "description": "The fourth color the wave trail will become", - "type": "color", - "default": "#FFFFFF" + "colors-list": { + "name": "Colors", + "type": "custom", + "description": "the colors to use for the wave trail", + "default": ["#FFFFFF", "#FFFFFF", "#FFFFFF", "#FFFFFF"] }, "chaos-section": { "name": "The chaos emeralds (CHECK SETTING DESCRIPTIONS)", - "type": "title", - "description": "make skylar gay" + "type": "custom", + "description": "make skylar gay", + "scale": 300, + "posX": 160 }, "chaos": { "name": "THE CHAOS EMERALDS", diff --git a/resources/addIcon.png b/resources/addIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..3fc1816cdb510297a6b13421c1a78554271b35ce GIT binary patch literal 10402 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 esm*iikZcAGC8L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace geode::prelude; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index d607767..468cdbe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,14 +6,15 @@ #include #include #include -#include #include #include "Geode/cocos/misc_nodes/CCMotionStreak.h" #include "Geode/loader/ModEvent.hpp" #include "Geode/modify/Modify.hpp" +#include "settings/multi_string_setting.hpp" #include "settings/section.hpp" #include "trail_customization/rainbow_trail.hpp" +#include "utils/color_utils.hpp" using namespace geode::prelude; using namespace cocos2d; @@ -27,19 +28,21 @@ struct MyPlayLayer : Modify { float speed = Mod::get()->getSettingValue("speed"); float saturation = Mod::get()->getSettingValue("saturation"); + std::vector color_strings = Mod::get()->getSettingValue("colors-list").m_strings; + + std::vector colors; + + for (const auto &color_string: color_strings) { + colors.push_back(ColorUtils::hex_to_rgb(color_string)); + } + bool mirror_players = Mod::get()->getSettingValue("mirror-players"); bool use_gradient = Mod::get()->getSettingValue("use-gradient"); bool enable = Mod::get()->getSettingValue("enable"); bool noRegularTrail = Mod::get()->getSettingValue("no-reg-trail"); - bool rainbow_icon = Mod::get()->getSettingValue("rainbow-icon"); bool disable_trail = Mod::get()->getSettingValue("disable-wave-trail"); bool infinite_trail = Mod::get()->getSettingValue("infinite-trail"); - auto color1 = Mod::get()->getSettingValue("color-one"); - auto color2 = Mod::get()->getSettingValue("color-two"); - auto color3 = Mod::get()->getSettingValue("color-three"); - auto color4 = Mod::get()->getSettingValue("color-four"); - if (ColorUtils::owo >= 360) { ColorUtils::owo = 0; } else { @@ -49,76 +52,30 @@ struct MyPlayLayer : Modify { phase = fmod(phase + speed, 360.f); bool p2 = true; - _ccColor3B rainbowColor = RainbowTrail::get_rainbow(0, saturation); - _ccColor3B rainbowColor2 = RainbowTrail::get_rainbow(180, saturation); - - _ccColor3B gradientColor = RainbowTrail::get_gradient(phase, 0.0f, false, color1, color2, color3, color4); - _ccColor3B gradientColor2 = RainbowTrail::get_gradient(phase, 0.0f, false, color4, color3, color2, color1); + RainbowTrail traill; - if (m_player1->m_isDart && noRegularTrail) { - m_player1->m_regularTrail - ->setVisible(false); - } + ccColor3B rainbowColor = RainbowTrail::get_rainbow(0, saturation); + ccColor3B rainbowColor2 = RainbowTrail::get_rainbow(180, saturation); + auto gradientColor = traill.get_gradient(phase, 0.0f, false, colors); + auto gradientColor2 = traill.get_gradient(phase + 180.0f, 0.0f, false, colors); - if (m_player2->m_isDart && noRegularTrail) { - m_player2->m_regularTrail - ->setVisible(false); - } - - if (enable) { - if (! use_gradient) { - if (m_player1->m_waveTrail) { - m_player1->m_waveTrail - ->setColor(rainbowColor); - - if (rainbow_icon && m_player1->m_isDart) { - m_player1->setColor(rainbowColor); - } - } - - if (m_player2->m_waveTrail) { - m_player2->m_waveTrail - ->setColor(! mirror_players - ? rainbowColor2 - : rainbowColor); - - if (rainbow_icon && m_player1->m_isDart) { - m_player2->setColor(rainbowColor2); - } - } - } else { + if (enable && m_player1->m_isDart) { + m_player1->m_regularTrail->setVisible(!noRegularTrail); if (m_player1->m_waveTrail) { - m_player1->m_waveTrail - ->setColor(gradientColor); - - if (rainbow_icon && m_player1->m_isDart) { - m_player1->setColor(gradientColor); - } else if (! rainbow_icon) { - reset_colors(); - } + m_player1->m_waveTrail->setColor(use_gradient ? gradientColor : rainbowColor); + m_player1->m_waveTrail->setVisible(!disable_trail); } + } + if (enable && m_player2->m_isDart) { + m_player2->m_regularTrail->setVisible(!noRegularTrail); if (m_player2->m_waveTrail) { - m_player2->m_waveTrail - ->setColor(! mirror_players - ? gradientColor - : gradientColor2); - - if (rainbow_icon && m_player2->m_isDart) { - m_player2->setColor(! mirror_players ? gradientColor : gradientColor2); - } else if (! rainbow_icon) { - reset_colors(); - } + ccColor3B p2Color = mirror_players + ? (use_gradient ? gradientColor : rainbowColor) + : (use_gradient ? gradientColor2 : rainbowColor2); + m_player2->m_waveTrail->setColor(p2Color); + m_player2->m_waveTrail->setVisible(!disable_trail); } - } - - if (disable_trail) { - this->m_player1->m_waveTrail->setVisible(false); - this->m_player2->m_waveTrail->setVisible(false); - } else { - this->m_player1->m_waveTrail->setVisible(true); - this->m_player2->m_waveTrail->setVisible(true); - } } } @@ -153,14 +110,14 @@ struct MyPlayLayer : Modify { /* persist wave trail */ struct MyMotionStreak : Modify { void fadeOutStreak2(float p0) { - if (!Mod::get()->getSettingValue("persist-wave-trail")) { + if (! Mod::get()->getSettingValue("persist-wave-trail")) { PlayerObject::fadeOutStreak2(p0); } } }; /* editor trail */ -class $modify(HardStreak) { +struct MyHardStreak : Modify { void updateStroke(float p0) { if (LevelEditorLayer::get() && Mod::get()->getSettingValue("editor-trail")) { m_drawStreak = true; @@ -170,7 +127,7 @@ class $modify(HardStreak) { } }; -class $modify(PlayerObject) { +struct MyPlayerObject : Modify { void placeStreakPoint() { if (LevelEditorLayer::get() && m_isDart && Mod::get()->getSettingValue("editor-trail")) { m_waveTrail->addPoint(this->getPosition()); @@ -191,4 +148,6 @@ class $modify(PlayerObject) { $on_mod(Loaded) { Mod::get()->addCustomSetting("gaydient-section", "none"); Mod::get()->addCustomSetting("chaos-section", "none"); -} + Mod::get()->addCustomSetting("colors-list", + Mod::get()->getSettingDefinition("colors-list")->get()->json->get>("default")); +} \ No newline at end of file diff --git a/src/settings/list_cell.cpp b/src/settings/list_cell.cpp new file mode 100644 index 0000000..2de5ae4 --- /dev/null +++ b/src/settings/list_cell.cpp @@ -0,0 +1,13 @@ +#include + +#include "list_cell.hpp" + +bool JBListCell::init(CCSize const &size) { + m_width = size.width; + m_height = size.height; + this->setContentSize(size); + this->setID("nong-list-cell"); + return true; +} + +void JBListCell::draw() { reinterpret_cast(this)->StatsCell::draw(); } \ No newline at end of file diff --git a/src/settings/list_cell.hpp b/src/settings/list_cell.hpp new file mode 100644 index 0000000..8f0178c --- /dev/null +++ b/src/settings/list_cell.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include + +using namespace geode::prelude; + +class JBListCell : public CCLayer, public FLAlertLayerProtocol { +protected: + float m_width; + float m_height; + + bool init(CCSize const &size); + void draw() override; +}; \ No newline at end of file diff --git a/src/settings/multi_string_setting.cpp b/src/settings/multi_string_setting.cpp new file mode 100644 index 0000000..5a2be6b --- /dev/null +++ b/src/settings/multi_string_setting.cpp @@ -0,0 +1,259 @@ +#include "multi_string_setting.hpp" +#include "../types/serializable_vector.hpp" +#include +#include + +using namespace geode::prelude; + +SettingNode *MultiStringSettingValue::createNode(float width) { + return MultiStringSettingNode::create(this, width); +} + +class MultiStringSettingPopup + : public geode::Popup, std::function)>> { +protected: + std::vector m_localValue; + std::function)> m_newStringsCallback; + CCMenu *m_listMenu; + ListView *m_list; + bool setup(std::vector localValue, + std::function)> newStringsCallback) override { + auto winSize = CCDirector::sharedDirector()->getWinSize(); + m_localValue = localValue; + m_newStringsCallback = newStringsCallback; + + m_listMenu = CCMenu::create(); + m_listMenu->setPosition(0, 0); + this->m_mainLayer->addChild(m_listMenu); + + createList(); + + handleTouchPriority(this); + return true; + } + + void onActionButton(CCObject *target) { + auto id = static_cast(target)->getID(); + auto index = std::stoi(id.substr(4)); + if (index == m_localValue.size() - 1) { + m_localValue.push_back(""); + } else { + m_localValue.erase(m_localValue.begin() + index); + } + m_newStringsCallback(m_localValue); + createList(); + } + + void createList() { + std::optional previousListPosition = {}; + if (m_list != nullptr) { + auto tableView = m_list->m_tableView; + float viewHeight = tableView->getContentHeight(); + float entireListHeight = tableView->m_contentLayer->getContentHeight(); + if (entireListHeight > viewHeight) { + float mostPossibleMovedHeightBottom = + entireListHeight - viewHeight; + float entireListYPosition = tableView->m_contentLayer->getPositionY(); + float mostPossibleMovedHeightTop = + -mostPossibleMovedHeightBottom - entireListYPosition; + previousListPosition = mostPossibleMovedHeightTop; + } + } + m_listMenu->removeAllChildren(); + m_list = nullptr; + + auto cells = CCArray::create(); + auto size = this->m_mainLayer->getContentSize(); + + for (int i = 0; i < m_localValue.size(); i++) { + auto last = i == m_localValue.size() - 1; + auto size2 = CCSize{size.width - 10.f, 40.f}; + + auto menu = CCMenu::create(); + menu->setPosition(0, 0); + + auto inputNode = TextInput::create(103.f, "Color Hex", "chatFont.fnt"); + inputNode->setScale(1.f); + inputNode->setPosition(size2.width / 2 - 15.f, size2.height / 2); + inputNode->setFilter("#0123456789abcdefABCDEF"); + inputNode->setMaxCharCount(300); + inputNode->setWidth(size2.width - 60.f); + inputNode->setString(m_localValue[i], false); + inputNode->setCallback([this, i](std::string const &str) { + m_localValue[i] = str; + m_newStringsCallback(m_localValue); + }); + menu->addChild(inputNode); + + auto spr = last ? CCSprite::create("addIcon.png"_spr) + : CCSprite::createWithSpriteFrameName("GJ_deleteIcon_001.png"); + spr->setScale(0.75f); + auto btn = CCMenuItemSpriteExtra::create( + spr, this, menu_selector(MultiStringSettingPopup::onActionButton)); + btn->setID(fmt::format("btn-{}", i)); + btn->setPosition(size2.width - 15.f, size2.height / 2); + menu->addChild(btn); + cells->addObject(menu); + } + + auto list = ListView::create(cells, 40.f, size.width - 8.f, size.height - 16.f); + list->setPosition(4.f, 10.f); + + std::optional newListPosition = {}; + if (previousListPosition.has_value()) { + auto tableView = list->m_tableView; + float viewHeight = tableView->getContentHeight(); + float entireListHeight = tableView->m_contentLayer->getContentHeight(); + // VV + float mostPossibleMovedHeightBottom = entireListHeight - viewHeight; + // VV + newListPosition = -previousListPosition.value() - mostPossibleMovedHeightBottom; + newListPosition = std::clamp(newListPosition.value(), -mostPossibleMovedHeightBottom, 0.f); + if (entireListHeight < viewHeight) { + newListPosition = viewHeight - entireListHeight; + } + } + if (newListPosition.has_value()) { + list->m_tableView->m_contentLayer->setPosition(CCPoint{0, newListPosition.value()}); + } + m_listMenu->addChild(list); + m_list = list; + } + +public: + static MultiStringSettingPopup * + create(std::vector localValue, + std::function)> newStringsCallback) { + auto ret = new MultiStringSettingPopup(); + if (ret && ret->initAnchored(420.f, 160.f, localValue, newStringsCallback)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; + } +}; + +bool MultiStringSettingNode::init(MultiStringSettingValue *value, float width) { + if (! SettingNode::init(value)) + return false; + this->m_value = value; + for (std::string &str: value->getStrings()) { + m_localValue.push_back(str); + } + + float height = 40.f; + this->setContentSize({width, height}); + + auto menu = CCMenu::create(); + menu->setPosition(0, 0); + menu->setID("inputs-menu"); + + // No way to get the JSON without hardcoding the setting ID... + auto settingJson = Mod::get()->getSettingDefinition("colors-list")->get()->json; + m_defaultValue = settingJson->get>("default"); + m_name = settingJson->get("name"); + m_description = settingJson->get("description"); + + m_label = CCLabelBMFont::create(m_name.c_str(), "bigFont.fnt"); + m_label->setAnchorPoint({0.f, 0.5f}); + m_label->setPosition(20.f, height / 2); + m_label->setScale(0.5f); + menu->addChild(m_label); + + auto infoSpr = CCSprite::createWithSpriteFrameName("GJ_infoIcon_001.png"); + infoSpr->setScale(.6f); + auto infoBtn = + CCMenuItemSpriteExtra::create(infoSpr, this, menu_selector(MultiStringSettingNode::onDesc)); + infoBtn->setPosition(m_label->getScaledContentSize().width + 40.f, height / 2); + menu->addChild(infoBtn); + + auto resetSpr = CCSprite::createWithSpriteFrameName("geode.loader/reset-gold.png"); + resetSpr->setScale(.5f); + m_resetBtn = + CCMenuItemSpriteExtra::create(resetSpr, this, menu_selector(MultiStringSettingNode::onReset)); + m_resetBtn->setPosition(m_label->getScaledContentSize().width + 40.f + 20.f, height / 2); + menu->addChild(m_resetBtn); + + auto viewSpr = ButtonSprite::create("View"); + viewSpr->setScale(0.72f); + auto viewBtn = + CCMenuItemSpriteExtra::create(viewSpr, this, menu_selector(MultiStringSettingNode::onView)); + viewBtn->setPosition(width - 40.f, height - 20.f); + menu->addChild(viewBtn); + + this->addChild(menu); + handleTouchPriority(this); + + updateVisuals(); + + return true; +} + +void MultiStringSettingNode::onView(CCObject *) { + auto popup = + MultiStringSettingPopup::create(m_localValue, [this](std::vector newStrings) { + m_localValue = newStrings; + updateVisuals(); + }); + popup->m_noElasticity = true; + popup->show(); +} + +void MultiStringSettingNode::onReset(CCObject *) { resetToDefault(); } + +void MultiStringSettingNode::onDesc(CCObject *) { + FLAlertLayer::create(m_name.c_str(), m_description.c_str(), "OK")->show(); +} + +void MultiStringSettingNode::updateVisuals() { + m_resetBtn->setVisible(hasNonDefaultValue()); + m_label->setColor(hasUncommittedChanges() ? ccColor3B{0x11, 0xdd, 0x00} + : ccColor3B{0xff, 0xff, 0xff}); + this->dispatchChanged(); +} + +void MultiStringSettingNode::commit() { + this->m_value->setStrings(m_localValue); + updateVisuals(); + this->dispatchCommitted(); +} + +bool MultiStringSettingNode::hasUncommittedChanges() { + if (m_localValue.size() != m_value->getStrings().size()) + return true; + for (int i = 0; i < m_localValue.size(); i++) { + if (m_localValue[i] != m_value->getStrings()[i]) + return true; + } + return false; +} + +bool MultiStringSettingNode::hasNonDefaultValue() { + if (m_localValue.size() != m_defaultValue.size()) + return true; + for (int i = 0; i < m_localValue.size(); i++) { + if (m_localValue[i] != m_defaultValue[i]) + return true; + } + return false; +} + +void MultiStringSettingNode::resetToDefault() { + m_localValue.clear(); + for (std::string &str: m_defaultValue) { + m_localValue.push_back(str); + } + updateVisuals(); +} + +MultiStringSettingNode *MultiStringSettingNode::create(MultiStringSettingValue *value, + float width) { + auto ret = new MultiStringSettingNode(); + if (ret && ret->init(value, width)) { + ret->autorelease(); + return ret; + } + CC_SAFE_DELETE(ret); + return nullptr; +} \ No newline at end of file diff --git a/src/settings/multi_string_setting.hpp b/src/settings/multi_string_setting.hpp new file mode 100644 index 0000000..3e46f12 --- /dev/null +++ b/src/settings/multi_string_setting.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "list_cell.hpp" +#include "../includes.hpp" + +using namespace geode::prelude; + +struct MultiStringSettingStruct { + std::vector m_strings; +}; + +class MultiStringSettingValue; + +class MultiStringSettingValue : public SettingValue { +protected: + std::vector m_strings; + +public: + MultiStringSettingValue(std::string const &key, std::string const &modID, + std::vector strings) + : SettingValue(key, modID), m_strings(strings) {} + + bool load(matjson::Value const &json) override { + m_strings.clear(); + auto array = json.as_array(); + for (auto const &elem : array) { + m_strings.push_back(elem.as_string()); + } + return true; + } + + bool save(matjson::Value &json) const override { + auto array = matjson::Array(); + for (auto const &string : m_strings) { + array.push_back(string); + } + json = array; + return true; + } + + SettingNode *createNode(float width) override; + + void setStrings(std::vector strings) { + this->m_strings = strings; + this->valueChanged(); + } + + std::vector getStrings() const { return this->m_strings; } +}; + +template <> struct SettingValueSetter { + static MultiStringSettingStruct get(SettingValue *setting) { + return MultiStringSettingStruct{static_cast(setting)->getStrings()}; + }; + static void set(MultiStringSettingValue *setting, MultiStringSettingStruct const &value) { + setting->setStrings(value.m_strings); + }; +}; + +class MultiStringSettingNode : public SettingNode { +protected: + MultiStringSettingValue *m_value; + CCMenuItemSpriteExtra *m_resetBtn; + CCLabelBMFont *m_label; + std::vector m_localValue; + std::string m_name; + std::string m_description; + std::vector m_defaultValue; + + bool init(MultiStringSettingValue *value, float width); + +public: + void updateVisuals(); + void onView(CCObject *); + void onReset(CCObject *); + void onDesc(CCObject *); + void commit() override; + bool hasUncommittedChanges() override; + bool hasNonDefaultValue() override; + void resetToDefault() override; + static MultiStringSettingNode *create(MultiStringSettingValue *value, float width); +}; \ No newline at end of file diff --git a/src/trail_customization/rainbow_trail.cpp b/src/trail_customization/rainbow_trail.cpp index 2d17389..925a0f2 100644 --- a/src/trail_customization/rainbow_trail.cpp +++ b/src/trail_customization/rainbow_trail.cpp @@ -1,7 +1,7 @@ #include "rainbow_trail.hpp" #include -#include #include +#include cocos2d::_ccColor3B RainbowTrail::get_rainbow(float offset, float saturation) { float R, G, B; @@ -18,30 +18,30 @@ cocos2d::_ccColor3B RainbowTrail::get_rainbow(float offset, float saturation) { return out; } -cocos2d::_ccColor3B RainbowTrail::get_gradient(float &phase, float offset, bool smooth, ccColor3B c1, ccColor3B c2, ccColor3B c3, ccColor3B c4) { - float t = fmodf(phase + offset, 360.0f); - float y = t / 90.0f; - int quadrant = static_cast(t / 90.0f); +cocos2d::_ccColor3B RainbowTrail::get_gradient(float phase, float offset, bool smooth, const std::vector &colors) { + float t = fmodf(phase + offset, 360.0f); + float y = t / 90.0f; + int quadrant = static_cast(t / 90.0f); - cocos2d::_ccColor3B out; + cocos2d::_ccColor3B out; - out.r = static_cast( - quadrant == 0 ? c1.r + (c2.r - c1.r) * y - : quadrant == 1 ? c2.r + (c3.r - c2.r) * (y - 1.0f) - : quadrant == 2 ? c3.r + (c4.r - c3.r) * (y - 2.0f) - : c4.r + (c1.r - c4.r) * (y - 3.0f)); + out.r = static_cast( + quadrant == 0 ? colors[0].r + (colors[1].r - colors[0].r) * y + : quadrant == 1 ? colors[1].r + (colors[2].r - colors[1].r) * (y - 1.0f) + : quadrant == 2 ? colors[2].r + (colors[3].r - colors[2].r) * (y - 2.0f) + : colors[3].r + (colors[0].r - colors[3].r) * (y - 3.0f)); - out.g = static_cast( - quadrant == 0 ? c1.g + (c2.g - c1.g) * y - : quadrant == 1 ? c2.g + (c3.g - c2.g) * (y - 1.0f) - : quadrant == 2 ? c3.g + (c4.g - c3.g) * (y - 2.0f) - : c4.g + (c1.g - c4.g) * (y - 3.0f)); + out.g = static_cast( + quadrant == 0 ? colors[0].g + (colors[1].g - colors[0].g) * y + : quadrant == 1 ? colors[1].g + (colors[2].g - colors[1].g) * (y - 1.0f) + : quadrant == 2 ? colors[2].g + (colors[3].g - colors[2].g) * (y - 2.0f) + : colors[3].g + (colors[0].g - colors[3].g) * (y - 3.0f)); - out.b = static_cast( - quadrant == 0 ? c1.b + (c2.b - c1.b) * y - : quadrant == 1 ? c2.b + (c3.b - c2.b) * (y - 1.0f) - : quadrant == 2 ? c3.b + (c4.b - c3.b) * (y - 2.0f) - : c4.b + (c1.b - c4.b) * (y - 3.0f)); + out.b = static_cast( + quadrant == 0 ? colors[0].b + (colors[1].b - colors[0].b) * y + : quadrant == 1 ? colors[1].b + (colors[2].b - colors[1].b) * (y - 1.0f) + : quadrant == 2 ? colors[2].b + (colors[3].b - colors[2].b) * (y - 2.0f) + : colors[3].b + (colors[0].b - colors[3].b) * (y - 3.0f)); - return out; -} + return out; +} \ No newline at end of file diff --git a/src/trail_customization/rainbow_trail.hpp b/src/trail_customization/rainbow_trail.hpp index a70e73d..b01d1fc 100644 --- a/src/trail_customization/rainbow_trail.hpp +++ b/src/trail_customization/rainbow_trail.hpp @@ -8,5 +8,5 @@ class RainbowTrail { public: static cocos2d::_ccColor3B get_rainbow(float offset, float saturation); cocos2d::_ccColor3B get_custom_rainbow(const std::vector &hex_colors, float offset, float saturation); - static cocos2d::_ccColor3B get_gradient(float &phase, float offset, bool smooth, ccColor3B c1, ccColor3B c2, ccColor3B c3, ccColor3B c4); + cocos2d::_ccColor3B get_gradient(float phase, float offset, bool smooth, const std::vector& colors); }; \ No newline at end of file diff --git a/src/types/serializable_vector.hpp b/src/types/serializable_vector.hpp new file mode 100644 index 0000000..736ad5b --- /dev/null +++ b/src/types/serializable_vector.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include + +template <> +struct matjson::Serialize> { + static bool is_json(matjson::Value const &value) { return value.is_array(); } + + static std::vector from_json(matjson::Value const &value) { + std::vector vec; + if (! is_json(value)) { + return vec; + } + auto array = value.as_array(); + for (auto const &elem: array) { + vec.push_back(elem.as_int()); + } + return vec; + } + + static matjson::Value to_json(std::vector const &vec) { + auto array = matjson::Array(); + for (auto const &elem: vec) { + array.push_back(matjson::Value(elem)); + } + return array; + } +}; + +template <> +struct matjson::Serialize> { + static bool is_json(matjson::Value const &value) { return value.is_array(); } + + static std::vector from_json(matjson::Value const &value) { + std::vector vec; + if (! is_json(value)) { + return vec; + } + auto array = value.as_array(); + for (auto const &elem: array) { + vec.push_back(elem.as_string()); + } + return vec; + } + + static matjson::Value to_json(std::vector const &vec) { + auto array = matjson::Array(); + for (auto const &elem: vec) { + array.push_back(matjson::Value(elem)); + } + return array; + } +}; \ No newline at end of file diff --git a/src/utils/color_utils.cpp b/src/utils/color_utils.cpp index 8a61189..98feb55 100644 --- a/src/utils/color_utils.cpp +++ b/src/utils/color_utils.cpp @@ -3,42 +3,42 @@ void ColorUtils::hsv_to_rgb(float &fR, float &fG, float &fB, float &fH, float &fS, float &fV) { float c = fV * fS; - float x = static_cast(static_cast(c) * ( 1 - std::abs(std::fmod(fH / 60.0f, 2) - 1))); + float x = static_cast(static_cast(c) * (1 - std::abs(std::fmod(fH / 60.0f, 2) - 1))); float m = fV - c; - fR = ( fH < 60.0f ) - ? c - : ( fH < 120.0f ) - ? x - : ( fH < 180.0f ) + fR = (fH < 60.0f) + ? c + : (fH < 120.0f) + ? x + : (fH < 180.0f) ? 0 - : ( fH < 240.0f ) - ? 0 - : ( fH < 300.0f ) - ? x - : c; - fG = ( fH < 60.0f ) - ? x - : ( fH < 120.0f ) - ? c - : ( fH < 180.0f ) + : (fH < 240.0f) + ? 0 + : (fH < 300.0f) + ? x + : c; + fG = (fH < 60.0f) + ? x + : (fH < 120.0f) + ? c + : (fH < 180.0f) ? c - : ( fH < 240.0f ) - ? x - : ( fH < 300.0f ) - ? 0 - : 0; - fB = ( fH < 60.0f ) - ? 0 - : ( fH < 120.0f ) - ? 0 - : ( fH < 180.0f ) + : (fH < 240.0f) ? x - : ( fH < 240.0f ) - ? c - : ( fH < 300.0f ) - ? c - : x; + : (fH < 300.0f) + ? 0 + : 0; + fB = (fH < 60.0f) + ? 0 + : (fH < 120.0f) + ? 0 + : (fH < 180.0f) + ? x + : (fH < 240.0f) + ? c + : (fH < 300.0f) + ? c + : x; fR += m; fG += m; @@ -48,16 +48,16 @@ void ColorUtils::hsv_to_rgb(float &fR, float &fG, float &fB, float &fH, float &f float ColorUtils::owo = 0; void ColorUtils::hex_to_hsv(uint32_t hex, float &h, float &s, float &v) { - float r = (( hex >> 16 ) & 0xFF ) / 255.0f; - float g = (( hex >> 8 ) & 0xFF ) / 255.0f; - float b = ( hex & 0xFF ) / 255.0f; + float r = ((hex >> 16) & 0xFF) / 255.0f; + float g = ((hex >> 8) & 0xFF) / 255.0f; + float b = (hex & 0xFF) / 255.0f; float max = std::max(std::max(r, g), b); float min = std::min(std::min(r, g), b); v = max; float delta = max - min; - if ( max != 0.0f ) { + if (max != 0.0f) { s = delta / max; } else { s = 0.0f; @@ -65,16 +65,65 @@ void ColorUtils::hex_to_hsv(uint32_t hex, float &h, float &s, float &v) { return; } - if ( r == max ) { - h = ( g - b ) / delta; - } else if ( g == max ) { - h = 2.0f + ( b - r ) / delta; + if (r == max) { + h = (g - b) / delta; + } else if (g == max) { + h = 2.0f + (b - r) / delta; } else { - h = 4.0f + ( r - g ) / delta; + h = 4.0f + (r - g) / delta; } h *= 60.0f; - if ( h < 0.0f ) { + if (h < 0.0f) { h += 360.0f; } } + +cocos2d::ccColor3B ColorUtils::hex_to_rgb(const std::string &hex) { + if (! is_valid_hex_code(hex)) { + return cocos2d::ccColor3B{0, 0, 0}; + } + + std::string clean_hex = hex; + if (clean_hex[0] == '#') { + clean_hex = clean_hex.substr(1); + } + + GLubyte r = hex_pair_to_dec(clean_hex.substr(0, 2)); + GLubyte g = hex_pair_to_dec(clean_hex.substr(2, 2)); + GLubyte b = hex_pair_to_dec(clean_hex.substr(4, 2)); + + return cocos2d::ccColor3B{r, g, b}; +} + +GLubyte ColorUtils::hex_pair_to_dec(const std::string &hex_pair) { + int val = 0; + + for (char c: hex_pair) { + val = val * 16; + + if (c >= '0' && c <= '9') { + val += c - '0'; + } else { + val += std::tolower(c) - 'a' + 10; + } + } + + return static_cast(val); +} + +bool ColorUtils::is_valid_hex_code(const std::string &hex_code) { + if (hex_code.empty()) + return false; + + size_t start_pos = (hex_code[0] == '#') ? 1 : 0; + + if (hex_code.length() != start_pos + 6) + return false; + + return std::all_of(hex_code.begin() + start_pos, hex_code.end(), + [](char c) { + c = std::tolower(c); + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f'); + }); +} \ No newline at end of file diff --git a/src/utils/color_utils.hpp b/src/utils/color_utils.hpp index b45041d..6da02ad 100644 --- a/src/utils/color_utils.hpp +++ b/src/utils/color_utils.hpp @@ -1,10 +1,17 @@ +#pragma once + #include using namespace cocos2d; class ColorUtils { public: + static cocos2d::ccColor3B hex_to_rgb(const std::string& hex); static void hsv_to_rgb(float &fR, float &fG, float &fB, float &fH, float &fS, float &fV); static void hex_to_hsv(uint32_t hex, float &h, float &s, float &v); static float owo; + +private: + static GLubyte hex_pair_to_dec(const std::string& hex_pair); + static bool is_valid_hex_code(const std::string& hex_code); }; \ No newline at end of file