Add fixed rotate buttons to perspective effect

pull/170/head
James Ball 2023-07-22 15:07:11 +01:00
rodzic 90ce1a73a2
commit 3a50b4f53e
11 zmienionych plików z 132 dodań i 45 usunięć

Wyświetl plik

@ -25,9 +25,9 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
audioProcessor.rotateY->setValue(rotateY.slider.getValue());
audioProcessor.rotateZ->setValue(rotateZ.slider.getValue());
audioProcessor.fixedRotateX = fixedRotateX->getToggleState();
audioProcessor.fixedRotateY = fixedRotateY->getToggleState();
audioProcessor.fixedRotateZ = fixedRotateZ->getToggleState();
audioProcessor.fixedRotateX->setBoolValueNotifyingHost(fixedRotateX->getToggleState());
audioProcessor.fixedRotateY->setBoolValueNotifyingHost(fixedRotateY->getToggleState());
audioProcessor.fixedRotateZ->setBoolValueNotifyingHost(fixedRotateZ->getToggleState());
};
rotateX.slider.onValueChange = onRotationChange;
@ -73,10 +73,6 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
rotateX.setComponent(fixedRotateX);
rotateY.setComponent(fixedRotateY);
rotateZ.setComponent(fixedRotateZ);
fixedRotateX->setToggleState(audioProcessor.fixedRotateX, juce::NotificationType::dontSendNotification);
fixedRotateY->setToggleState(audioProcessor.fixedRotateY, juce::NotificationType::dontSendNotification);
fixedRotateZ->setToggleState(audioProcessor.fixedRotateZ, juce::NotificationType::dontSendNotification);
}
ObjComponent::~ObjComponent() {

Wyświetl plik

@ -27,9 +27,9 @@ private:
juce::TextButton resetRotation{"Reset Rotation"};
juce::ToggleButton mouseRotate{"Rotate with Mouse (Esc to disable)"};
std::shared_ptr<SvgButton> fixedRotateX = std::make_shared<SvgButton>("fixedRotateX", juce::String(BinaryData::fixed_rotate_svg), "white", "red");
std::shared_ptr<SvgButton> fixedRotateY = std::make_shared<SvgButton>("fixedRotateY", juce::String(BinaryData::fixed_rotate_svg), "white", "red");
std::shared_ptr<SvgButton> fixedRotateZ = std::make_shared<SvgButton>("fixedRotateZ", juce::String(BinaryData::fixed_rotate_svg), "white", "red");
std::shared_ptr<SvgButton> fixedRotateX = std::make_shared<SvgButton>("fixedRotateX", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateX);
std::shared_ptr<SvgButton> fixedRotateY = std::make_shared<SvgButton>("fixedRotateY", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateY);
std::shared_ptr<SvgButton> fixedRotateZ = std::make_shared<SvgButton>("fixedRotateZ", juce::String(BinaryData::fixed_rotate_svg), "white", "red", audioProcessor.fixedRotateZ);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ObjComponent)
};

Wyświetl plik

@ -124,6 +124,13 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
}
}
}
addParameter(fixedRotateX);
addParameter(fixedRotateY);
addParameter(fixedRotateZ);
addParameter(perspectiveEffect->fixedRotateX);
addParameter(perspectiveEffect->fixedRotateY);
addParameter(perspectiveEffect->fixedRotateZ);
}
OscirenderAudioProcessor::~OscirenderAudioProcessor() {}

Wyświetl plik

@ -107,16 +107,16 @@ public:
}, new EffectParameter("Focal length", "focalLength", 1.0, 0.0, 2.0)
);
std::atomic<bool> fixedRotateX = false;
std::atomic<bool> fixedRotateY = false;
std::atomic<bool> fixedRotateZ = false;
BooleanParameter* fixedRotateX = new BooleanParameter("Object Fixed Rotate X", "objFixedRotateX", false);
BooleanParameter* fixedRotateY = new BooleanParameter("Object Fixed Rotate Y", "objFixedRotateY", false);
BooleanParameter* fixedRotateZ = new BooleanParameter("Object Fixed Rotate Z", "objFixedRotateZ", false);
std::shared_ptr<Effect> rotateX = std::make_shared<Effect>(
[this](int index, Vector2 input, const std::vector<double>& values, double sampleRate) {
if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input;
auto rotation = values[0] * std::numbers::pi;
if (fixedRotateX) {
if (fixedRotateX->getBoolValue()) {
obj->setCurrentRotationX(rotation);
} else {
obj->setBaseRotationX(rotation);
@ -131,7 +131,7 @@ public:
auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input;
auto rotation = values[0] * std::numbers::pi;
if (fixedRotateY) {
if (fixedRotateY->getBoolValue()) {
obj->setCurrentRotationY(rotation);
} else {
obj->setBaseRotationY(rotation);
@ -146,7 +146,7 @@ public:
auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input;
auto rotation = values[0] * std::numbers::pi;
if (fixedRotateZ) {
if (fixedRotateZ->getBoolValue()) {
obj->setCurrentRotationZ(rotation);
} else {
obj->setBaseRotationZ(rotation);

Wyświetl plik

@ -29,10 +29,22 @@ public:
return value.load();
}
bool getBoolValue() const {
return value.load();
}
void setValue(float newValue) override {
value.store(newValue >= 0.5f);
}
void setBoolValue(bool newValue) {
value.store(newValue);
}
void setBoolValueNotifyingHost(bool newValue) {
setValueNotifyingHost(newValue ? 1.0f : 0.0f);
}
float getDefaultValue() const override {
return false;
}

Wyświetl plik

@ -7,37 +7,55 @@ Vector2 PerspectiveEffect::apply(int index, Vector2 input, const std::vector<dou
auto effectScale = values[0];
auto depth = 1.0 + (values[1] - 0.1) * 3;
auto rotateSpeed = linearSpeedToActualSpeed(values[2]);
auto baseRotateX = values[3] * std::numbers::pi;
auto baseRotateY = values[4] * std::numbers::pi;
auto baseRotateZ = values[5] * std::numbers::pi;
double baseRotateX, baseRotateY, baseRotateZ;
if (fixedRotateX->getBoolValue()) {
baseRotateX = 0;
currentRotateX = values[3] * std::numbers::pi;
} else {
baseRotateX = values[3] * std::numbers::pi;
}
if (fixedRotateY->getBoolValue()) {
baseRotateY = 0;
currentRotateY = values[4] * std::numbers::pi;
} else {
baseRotateY = values[4] * std::numbers::pi;
}
if (fixedRotateZ->getBoolValue()) {
baseRotateZ = 0;
currentRotateZ = values[5] * std::numbers::pi;
} else {
baseRotateZ = values[5] * std::numbers::pi;
}
currentRotateX += baseRotateX * rotateSpeed;
currentRotateY += baseRotateY * rotateSpeed;
currentRotateZ += baseRotateZ * rotateSpeed;
if (currentRotateX > std::numbers::pi * 50) {
currentRotateX -= std::numbers::pi * 50;
if (currentRotateX > std::numbers::pi * 8) {
currentRotateX -= std::numbers::pi * 8;
}
if (currentRotateY > std::numbers::pi * 50) {
currentRotateY -= std::numbers::pi * 50;
if (currentRotateY > std::numbers::pi * 8) {
currentRotateY -= std::numbers::pi * 8;
}
if (currentRotateZ > std::numbers::pi * 50) {
currentRotateZ -= std::numbers::pi * 50;
if (currentRotateZ > std::numbers::pi * 8) {
currentRotateZ -= std::numbers::pi * 8;
}
auto x = input.x;
auto y = input.y;
auto z = 0.0;
parser.setVariable("x", x);
parser.setVariable("y", y);
parser.setVariable("z", z);
if (!defaultScript) {
parser.setVariable("x", x);
parser.setVariable("y", y);
parser.setVariable("z", z);
auto result = parser.run();
if (result.size() >= 3) {
x = result[0];
y = result[1];
z = result[2];
auto result = parser.run();
if (result.size() >= 3) {
x = result[0];
y = result[1];
z = result[2];
}
}
auto rotateX = baseRotateX + currentRotateX;

Wyświetl plik

@ -9,10 +9,15 @@ public:
PerspectiveEffect();
Vector2 apply(int index, Vector2 input, const std::vector<double>& values, double sampleRate) override;
BooleanParameter* fixedRotateX = new BooleanParameter("Perspective Fixed Rotate X", "perspectiveFixedRotateX", false);
BooleanParameter* fixedRotateY = new BooleanParameter("Perspective Fixed Rotate Y", "perspectiveFixedRotateY", false);
BooleanParameter* fixedRotateZ = new BooleanParameter("Perspective Fixed Rotate Z", "perspectiveFixedRotateZ", false);
private:
const juce::String DEFAULT_SCRIPT = "return { x, y, z }";
juce::MemoryBlock code{DEFAULT_SCRIPT.toRawUTF8(), DEFAULT_SCRIPT.getNumBytesAsUTF8() + 1};
LuaParser parser{DEFAULT_SCRIPT};
bool defaultScript = true;
float currentRotateX = 0;
float currentRotateY = 0;

Wyświetl plik

@ -1,15 +1,16 @@
#include "EffectsListComponent.h"
#include "SvgButton.h"
EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, std::shared_ptr<Effect> effect) : DraggableListBoxItem(lb, data, rn), effect(effect) {
auto parameters = effect->parameters;
EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, Effect& effect) : DraggableListBoxItem(lb, data, rn), effect(effect), audioProcessor(data.audioProcessor) {
auto parameters = effect.parameters;
for (int i = 0; i < parameters.size(); i++) {
std::shared_ptr<EffectComponent> effectComponent = std::make_shared<EffectComponent>(data.audioProcessor, *effect, i, i == 0);
std::shared_ptr<EffectComponent> effectComponent = std::make_shared<EffectComponent>(audioProcessor, effect, i, i == 0);
// using weak_ptr to avoid circular reference and memory leak
std::weak_ptr<EffectComponent> weakEffectComponent = effectComponent;
effectComponent->slider.setValue(parameters[i]->getValueUnnormalised(), juce::dontSendNotification);
effectComponent->slider.onValueChange = [this, i, weakEffectComponent] {
if (auto effectComponent = weakEffectComponent.lock()) {
this->effect->setValue(i, effectComponent->slider.getValue());
this->effect.setValue(i, effectComponent->slider.getValue());
}
};
@ -17,12 +18,17 @@ EffectsListComponent::EffectsListComponent(DraggableListBox& lb, AudioEffectList
effectComponent->selected.onClick = [this, weakEffectComponent] {
if (auto effectComponent = weakEffectComponent.lock()) {
auto data = (AudioEffectListBoxItemData&)modelData;
juce::SpinLock::ScopedLockType lock(data.audioProcessor.effectsLock);
juce::SpinLock::ScopedLockType lock(audioProcessor.effectsLock);
data.setSelected(rowNum, effectComponent->selected.getToggleState());
}
};
}
auto component = createComponent(parameters[i]);
if (component != nullptr) {
effectComponent->setComponent(component);
}
listModel.addComponent(effectComponent);
}
@ -66,6 +72,25 @@ void EffectsListComponent::resized() {
list.setBounds(area);
}
std::shared_ptr<juce::Component> EffectsListComponent::createComponent(EffectParameter* parameter) {
if (parameter->paramID == "rotateX" || parameter->paramID == "rotateY" || parameter->paramID == "rotateZ") {
BooleanParameter* toggle;
if (parameter->paramID == "rotateX") {
toggle = audioProcessor.perspectiveEffect->fixedRotateX;
} else if (parameter->paramID == "rotateY") {
toggle = audioProcessor.perspectiveEffect->fixedRotateY;
} else if (parameter->paramID == "rotateZ") {
toggle = audioProcessor.perspectiveEffect->fixedRotateZ;
}
std::shared_ptr<SvgButton> button = std::make_shared<SvgButton>(parameter->name, BinaryData::fixed_rotate_svg, "white", "red", toggle);
button->onClick = [this, toggle] {
toggle->setBoolValueNotifyingHost(!toggle->getBoolValue());
};
return button;
}
return nullptr;
}
int EffectsListBoxModel::getRowHeight(int row) {
auto data = (AudioEffectListBoxItemData&)modelData;
return data.getEffect(row)->parameters.size() * 30;
@ -79,7 +104,7 @@ juce::Component* EffectsListBoxModel::refreshComponentForRow(int rowNumber, bool
std::unique_ptr<EffectsListComponent> item(dynamic_cast<EffectsListComponent*>(existingComponentToUpdate));
if (juce::isPositiveAndBelow(rowNumber, modelData.getNumItems())) {
auto data = (AudioEffectListBoxItemData&)modelData;
item = std::make_unique<EffectsListComponent>(listBox, (AudioEffectListBoxItemData&)modelData, rowNumber, data.getEffect(rowNumber));
item = std::make_unique<EffectsListComponent>(listBox, (AudioEffectListBoxItemData&)modelData, rowNumber, *data.getEffect(rowNumber));
}
return item.release();
}

Wyświetl plik

@ -89,7 +89,7 @@ struct AudioEffectListBoxItemData : public DraggableListBoxItemData
class EffectsListComponent : public DraggableListBoxItem
{
public:
EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, std::shared_ptr<Effect> effect);
EffectsListComponent(DraggableListBox& lb, AudioEffectListBoxItemData& data, int rn, Effect& effect);
~EffectsListComponent();
void paint(juce::Graphics& g) override;
@ -97,10 +97,14 @@ public:
void resized() override;
protected:
std::shared_ptr<Effect> effect;
Effect& effect;
ComponentListModel listModel;
juce::ListBox list;
private:
OscirenderAudioProcessor& audioProcessor;
std::shared_ptr<juce::Component> createComponent(EffectParameter* parameter);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectsListComponent)
};

Wyświetl plik

@ -1,9 +1,9 @@
#pragma once
#include <JuceHeader.h>
class SvgButton : public juce::DrawableButton {
class SvgButton : public juce::DrawableButton, public juce::AudioProcessorParameter::Listener, public juce::AsyncUpdater {
public:
SvgButton(juce::String name, juce::String svg, juce::String colour, juce::String colourOn) : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted) {
SvgButton(juce::String name, juce::String svg, juce::String colour, juce::String colourOn, BooleanParameter* toggle = nullptr) : juce::DrawableButton(name, juce::DrawableButton::ButtonStyle::ImageFitted), toggle(toggle) {
auto doc = juce::XmlDocument::parse(svg);
changeSvgColour(doc.get(), colour);
normalImage = juce::Drawable::createFromSVG(*doc);
@ -16,14 +16,34 @@ class SvgButton : public juce::DrawableButton {
setClickingTogglesState(true);
}
setImages(normalImage.get(), nullptr, nullptr, nullptr, normalImageOn.get());
if (toggle != nullptr) {
toggle->addListener(this);
setToggleState(toggle->getBoolValue(), juce::NotificationType::dontSendNotification);
}
}
SvgButton(juce::String name, juce::String svg, juce::String colour) : SvgButton(name, svg, colour, colour) {}
~SvgButton() override {}
~SvgButton() override {
if (toggle != nullptr) {
toggle->removeListener(this);
}
}
void parameterValueChanged(int parameterIndex, float newValue) override {
triggerAsyncUpdate();
}
void parameterGestureChanged(int parameterIndex, bool gestureIsStarting) override {}
void handleAsyncUpdate() override {
setToggleState(toggle->getBoolValue(), juce::NotificationType::dontSendNotification);
}
private:
std::unique_ptr<juce::Drawable> normalImage;
std::unique_ptr<juce::Drawable> normalImageOn;
BooleanParameter* toggle;
void changeSvgColour(juce::XmlElement* xml, juce::String colour) {
forEachXmlChildElement(*xml, xmlnode) {

Wyświetl plik

@ -86,6 +86,6 @@ void VisualiserComponent::paintXY(juce::Graphics& g, juce::Rectangle<float> area
double strength = 10;
lengthScale = std::log(strength * lengthScale + 1) / std::log(strength + 1);
g.setColour(waveformColour.withAlpha(lengthScale));
g.drawLine(line, 2.0f);
g.drawLine(line, area.getWidth() / 150.0f);
}
}