kopia lustrzana https://github.com/jameshball/osci-render
Add fixed rotate buttons to perspective effect
rodzic
90ce1a73a2
commit
3a50b4f53e
|
@ -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() {
|
||||
|
|
|
@ -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)
|
||||
};
|
|
@ -124,6 +124,13 @@ OscirenderAudioProcessor::OscirenderAudioProcessor()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
addParameter(fixedRotateX);
|
||||
addParameter(fixedRotateY);
|
||||
addParameter(fixedRotateZ);
|
||||
addParameter(perspectiveEffect->fixedRotateX);
|
||||
addParameter(perspectiveEffect->fixedRotateY);
|
||||
addParameter(perspectiveEffect->fixedRotateZ);
|
||||
}
|
||||
|
||||
OscirenderAudioProcessor::~OscirenderAudioProcessor() {}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue