Focal length, rotation, and rotation speed sliders all functional, and add Effect initialisable with a lambda

pull/170/head
James Ball 2023-07-05 12:02:28 +01:00
rodzic a487306784
commit e2f9a6c4a4
13 zmienionych plików z 160 dodań i 29 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ EffectsComponent::EffectsComponent(OscirenderAudioProcessor& p) : audioProcessor
setText("Audio Effects");
addAndMakeVisible(frequency);
frequency.setHideCheckbox(true);
frequency.setCheckboxVisible(false);
frequency.slider.setSkewFactorFromMidPoint(500.0);
frequency.slider.setTextValueSuffix("Hz");

Wyświetl plik

@ -1,5 +1,6 @@
#include "ObjComponent.h"
#include "PluginEditor.h"
#include <numbers>
ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessorEditor& editor) : audioProcessor(p), pluginEditor(editor) {
setText("3D .obj File Settings");
@ -9,6 +10,31 @@ ObjComponent::ObjComponent(OscirenderAudioProcessor& p, OscirenderAudioProcessor
addAndMakeVisible(rotateY);
addAndMakeVisible(rotateZ);
addAndMakeVisible(rotateSpeed);
focalLength.slider.onValueChange = [this] {
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
audioProcessor.focalLength.setValue(focalLength.slider.getValue());
audioProcessor.focalLength.apply();
};
auto onRotationChange = [this]() {
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
audioProcessor.rotateX.setValue(rotateX.slider.getValue());
audioProcessor.rotateY.setValue(rotateY.slider.getValue());
audioProcessor.rotateZ.setValue(rotateZ.slider.getValue());
// all the rotate apply functions are the same
audioProcessor.rotateX.apply();
};
rotateX.slider.onValueChange = onRotationChange;
rotateY.slider.onValueChange = onRotationChange;
rotateZ.slider.onValueChange = onRotationChange;
rotateSpeed.slider.onValueChange = [this] {
juce::SpinLock::ScopedLockType lock(audioProcessor.parsersLock);
audioProcessor.rotateSpeed.setValue(rotateSpeed.slider.getValue());
audioProcessor.rotateSpeed.apply();
};
}
void ObjComponent::resized() {

Wyświetl plik

@ -166,12 +166,18 @@ void OscirenderAudioProcessor::addLuaSlider() {
}
void OscirenderAudioProcessor::updateLuaValues() {
Vector2 vector;
for (auto& effect : luaEffects) {
effect->apply(0, vector);
effect->apply();
}
}
// parsersLock should be held when calling this
void OscirenderAudioProcessor::updateObjValues() {
focalLength.apply();
rotateX.apply();
rotateSpeed.apply();
}
void OscirenderAudioProcessor::updateAngleDelta() {
auto cyclesPerSample = frequency / currentSampleRate;
thetaDelta = cyclesPerSample * 2.0 * juce::MathConstants<double>::pi;
@ -269,6 +275,7 @@ void OscirenderAudioProcessor::openFile(int index) {
currentFile = index;
invalidateFrameBuffer = true;
updateLuaValues();
updateObjValues();
}
void OscirenderAudioProcessor::changeCurrentFile(int index) {
@ -417,6 +424,10 @@ void OscirenderAudioProcessor::processBlock (juce::AudioBuffer<float>& buffer, j
x = channels.x;
y = channels.y;
// clip to -1.0 to 1.0
x = std::max(-1.0, std::min(1.0, x));
y = std::max(-1.0, std::min(1.0, y));
if (totalNumOutputChannels >= 2) {

Wyświetl plik

@ -14,6 +14,7 @@
#include "parser/FrameProducer.h"
#include "parser/FrameConsumer.h"
#include "audio/Effect.h"
#include <numbers>
//==============================================================================
/**
@ -71,12 +72,50 @@ public:
std::shared_ptr<std::vector<std::shared_ptr<Effect>>> enabledEffects = std::make_shared<std::vector<std::shared_ptr<Effect>>>();
std::vector<std::shared_ptr<Effect>> luaEffects;
// TODO see if there is a way to move this code to .cpp
std::function<Vector2(int, Vector2, double, double, int)> onRotationChange = [this](int index, Vector2 input, double value, double frequency, double sampleRate) {
if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input;
obj->setBaseRotation(
rotateX.getValue() * std::numbers::pi,
rotateY.getValue() * std::numbers::pi,
rotateZ.getValue() * std::numbers::pi
);
}
return input;
};
Effect focalLength{"Focal length", "focalLength", 1};
Effect rotateX{"Rotate x", "rotateX", 0};
Effect rotateY{"Rotate y", "rotateY", 0};
Effect rotateZ{"Rotate z", "rotateZ", 0};
Effect rotateSpeed{"Rotate speed", "rotateSpeed", 0};
Effect focalLength{
[this](int index, Vector2 input, double value, double frequency, double sampleRate) {
if (getCurrentFileIndex() != -1) {
auto camera = getCurrentFileParser()->getCamera();
if (camera == nullptr) return input;
camera->setFocalLength(value);
}
return input;
},
"Focal length",
"focalLength",
1
};
Effect rotateX{onRotationChange, "Rotate x", "rotateX", 1};
Effect rotateY{onRotationChange, "Rotate y", "rotateY", 1};
Effect rotateZ{onRotationChange, "Rotate z", "rotateZ", 0};
Effect rotateSpeed{
[this](int index, Vector2 input, double value, double frequency, double sampleRate) {
if (getCurrentFileIndex() != -1) {
auto obj = getCurrentFileParser()->getObject();
if (obj == nullptr) return input;
obj->setRotationSpeed(value);
}
return input;
},
"Rotate speed",
"rotateSpeed",
0
};
juce::SpinLock parsersLock;
std::vector<std::shared_ptr<FileParser>> parsers;
@ -87,7 +126,6 @@ public:
std::unique_ptr<FrameProducer> producer;
void addLuaSlider();
void updateLuaValues();
void updateAngleDelta();
void addFrame(std::vector<std::unique_ptr<Shape>> frame, int fileIndex) override;
void enableEffect(std::shared_ptr<Effect> effect);
@ -123,6 +161,8 @@ private:
void updateFrame();
void updateLengthIncrement();
void openFile(int index);
void updateLuaValues();
void updateObjValues();
const double MIN_LENGTH_INCREMENT = 0.000001;

Wyświetl plik

@ -8,11 +8,21 @@ Effect::Effect(juce::String name, juce::String id) : name(name), id(id) {}
Effect::Effect(juce::String name, juce::String id, double value) : name(name), id(id), value(value) {}
Effect::Effect(std::function<Vector2(int, Vector2, double, double, int)> application, juce::String name, juce::String id, double value) : Effect(name, id, value) {
this->application = application;
};
Vector2 Effect::apply(int index, Vector2 input) {
if (effectApplication == nullptr) {
return input;
if (application) {
return application(index, input, value, frequency, sampleRate);
} else if (effectApplication != nullptr) {
return effectApplication->apply(index, input, value, frequency, sampleRate);
}
return effectApplication->apply(index, input, value, frequency, sampleRate);
return input;
}
void Effect::apply() {
apply(0, Vector2());
}
double Effect::getValue() {

Wyświetl plik

@ -8,8 +8,10 @@ public:
Effect(std::unique_ptr<EffectApplication> effectApplication, juce::String name, juce::String id);
Effect(juce::String name, juce::String id);
Effect(juce::String name, juce::String id, double value);
Effect(std::function<Vector2(int, Vector2, double, double, int)> application, juce::String name, juce::String id, double value);
Vector2 apply(int index, Vector2 input);
void apply();
double getValue();
void setValue(double value);
void setFrequency(double frequency);
@ -24,6 +26,7 @@ private:
int sampleRate = 192000;
juce::String name;
juce::String id;
std::function<Vector2(int, Vector2, double, double, int)> application;
std::unique_ptr<EffectApplication> effectApplication;
};

Wyświetl plik

@ -12,8 +12,8 @@ EffectComponent::EffectComponent(double min, double max, double step, Effect& ef
slider.setValue(effect.getValue(), juce::dontSendNotification);
}
EffectComponent::EffectComponent(double min, double max, double step, Effect& effect, bool hideCheckbox) : EffectComponent(min, max, step, effect) {
setHideCheckbox(hideCheckbox);
EffectComponent::EffectComponent(double min, double max, double step, Effect& effect, bool checkboxVisible) : EffectComponent(min, max, step, effect) {
setCheckboxVisible(checkboxVisible);
}
void EffectComponent::componentSetup() {
@ -34,11 +34,11 @@ void EffectComponent::resized() {
auto bounds = getLocalBounds();
bounds.removeFromRight(10);
slider.setBounds(bounds.removeFromRight(sliderRight));
if (hideCheckbox) {
bounds.removeFromLeft(5);
} else {
if (checkboxVisible) {
bounds.removeFromLeft(2);
selected.setBounds(bounds.removeFromLeft(25));
} else {
bounds.removeFromLeft(5);
}
textBounds = bounds;
}
@ -51,6 +51,6 @@ void EffectComponent::paint(juce::Graphics& g) {
g.drawText(name, textBounds, juce::Justification::left);
}
void EffectComponent::setHideCheckbox(bool hide) {
hideCheckbox = hide;
void EffectComponent::setCheckboxVisible(bool visible) {
checkboxVisible = visible;
}

Wyświetl plik

@ -8,13 +8,13 @@ class EffectComponent : public juce::Component {
public:
EffectComponent(double min, double max, double step, double value, juce::String name, juce::String id);
EffectComponent(double min, double max, double step, Effect& effect);
EffectComponent(double min, double max, double step, Effect& effect, bool hideCheckbox);
EffectComponent(double min, double max, double step, Effect& effect, bool checkboxVisible);
~EffectComponent();
void resized() override;
void paint(juce::Graphics& g) override;
void setHideCheckbox(bool hide);
void setCheckboxVisible(bool visible);
juce::Slider slider;
juce::String id;
@ -23,7 +23,7 @@ public:
private:
void componentSetup();
bool hideCheckbox = false;
bool checkboxVisible = false;
juce::Rectangle<int> textBounds;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EffectComponent)

Wyświetl plik

@ -2,7 +2,7 @@
LuaListComponent::LuaListComponent(OscirenderAudioProcessor& p, Effect& effect) {
effectComponent = std::make_shared<EffectComponent>(0.0, 1.0, 0.01, effect);
effectComponent->setHideCheckbox(true);
effectComponent->setCheckboxVisible(false);
effectComponent->slider.onValueChange = [this, &effect, &p] {
effect.setValue(effectComponent->slider.getValue());

Wyświetl plik

@ -6,6 +6,7 @@ Camera::Camera(double focalLength, double x, double y, double z) : focalLength(f
std::vector<std::unique_ptr<Shape>> Camera::draw(WorldObject& object) {
std::vector<std::unique_ptr<Shape>> shapes;
object.nextFrame();
for (auto& edge : object.edges) {
Vector2 start = project(object.rotateX, object.rotateY, object.rotateZ, edge.x1, edge.y1, edge.z1);
Vector2 end = project(object.rotateX, object.rotateY, object.rotateZ, edge.x2, edge.y2, edge.z2);
@ -30,14 +31,14 @@ void Camera::findZPos(WorldObject& object) {
}
}
void Camera::setFocalLength(double focalLength) {
this->focalLength = focalLength;
}
std::vector<Vector2> Camera::sampleVerticesInRender(WorldObject& object) {
double rotation = 2.0 * std::numbers::pi / SAMPLE_RENDER_SAMPLES;
std::vector<Vector2> vertices;
double oldRotateX = object.rotateX;
double oldRotateY = object.rotateY;
double oldRotateZ = object.rotateZ;
for (int i = 0; i < SAMPLE_RENDER_SAMPLES - 1; i++) {
for (size_t j = 0; j < std::min(VERTEX_SAMPLES, object.numVertices); j++) {

Wyświetl plik

@ -11,6 +11,7 @@ public:
std::vector<std::unique_ptr<Shape>> draw(WorldObject& object);
void findZPos(WorldObject& object);
void setFocalLength(double focalLength);
private:
const double VERTEX_VALUE_THRESHOLD = 1.0;
const double CAMERA_MOVE_INCREMENT = -0.1;
@ -18,7 +19,7 @@ private:
const int VERTEX_SAMPLES = 1000;
const int MAX_NUM_STEPS = 1000;
double focalLength;
std::atomic<double> focalLength;
double x, y, z;
std::vector<Vector2> sampleVerticesInRender(WorldObject& object);

Wyświetl plik

@ -206,3 +206,33 @@ WorldObject::WorldObject(std::string obj_string) {
}
}
}
void WorldObject::setBaseRotation(double x, double y, double z) {
baseRotateX = x;
baseRotateY = y;
baseRotateZ = z;
}
void WorldObject::setRotationSpeed(double rotateSpeed) {
this->rotateSpeed = linearSpeedToActualSpeed(rotateSpeed);
}
// called whenever a new frame is drawn, so that the object can update its
// rotation
void WorldObject::nextFrame() {
currentRotateX += baseRotateX * rotateSpeed;
currentRotateY += baseRotateY * rotateSpeed;
currentRotateZ += baseRotateZ * rotateSpeed;
rotateX = baseRotateX + currentRotateX;
rotateY = baseRotateY + currentRotateY;
rotateZ = baseRotateZ + currentRotateZ;
}
// this just makes the range of the speed more useful
double WorldObject::linearSpeedToActualSpeed(double rotateSpeed) {
double actualSpeed = (std::exp(3 * std::min(10.0, std::abs(rotateSpeed))) - 1) / 50000;
if (rotateSpeed < 0) {
actualSpeed *= -1;
}
return actualSpeed;
}

Wyświetl plik

@ -6,10 +6,19 @@ class WorldObject {
public:
WorldObject(std::string);
double rotateX = 0.0, rotateY = 0.0, rotateZ = 0.0;
void setBaseRotation(double x, double y, double z);
void setRotationSpeed(double rotateSpeed);
void nextFrame();
std::atomic<double> rotateX = 0.0, rotateY = 0.0, rotateZ = 0.0;
std::vector<Line3D> edges;
std::vector<float> vs;
int numVertices;
private:
double linearSpeedToActualSpeed(double rotateSpeed);
std::atomic<double> baseRotateX = 0.0, baseRotateY = 0.0, baseRotateZ = 0.0;
std::atomic<double> currentRotateX = 0.0, currentRotateY = 0.0, currentRotateZ = 0.0;
std::atomic<double> rotateSpeed;
};