diff --git a/Resources/oscilloscope/real_reflection.jpg b/Resources/oscilloscope/real_reflection.jpg new file mode 100644 index 0000000..b0199ef Binary files /dev/null and b/Resources/oscilloscope/real_reflection.jpg differ diff --git a/Resources/oscilloscope/vector_display_reflection.jpg b/Resources/oscilloscope/vector_display_reflection.jpg index c873d98..66028f4 100644 Binary files a/Resources/oscilloscope/vector_display_reflection.jpg and b/Resources/oscilloscope/vector_display_reflection.jpg differ diff --git a/Source/CommonPluginEditor.cpp b/Source/CommonPluginEditor.cpp index c9781e3..6eaa5d8 100644 --- a/Source/CommonPluginEditor.cpp +++ b/Source/CommonPluginEditor.cpp @@ -76,7 +76,9 @@ CommonPluginEditor::CommonPluginEditor(CommonAudioProcessor& p, juce::String app tooltipDropShadow.setOwner(&tooltipWindow); +#if SOSCI_FEATURES SharedTextureManager::getInstance()->initGL(); +#endif } void CommonPluginEditor::initialiseMenuBar(juce::MenuBarModel& menuBarModel) { diff --git a/Source/visualiser/LineFragmentShader.glsl b/Source/visualiser/LineFragmentShader.glsl index e87a414..f9a1264 100644 --- a/Source/visualiser/LineFragmentShader.glsl +++ b/Source/visualiser/LineFragmentShader.glsl @@ -28,8 +28,7 @@ float erf(float x) { x *= x; return s - s / (x * x); } - - + void main() { // fish eye distortion vec2 uv = vTexCoord - vec2(0.5); diff --git a/Source/visualiser/VisualiserComponent.cpp b/Source/visualiser/VisualiserComponent.cpp index 52da420..54297f4 100644 --- a/Source/visualiser/VisualiserComponent.cpp +++ b/Source/visualiser/VisualiserComponent.cpp @@ -50,21 +50,22 @@ VisualiserComponent::VisualiserComponent(juce::File& lastOpenedDirectory, juce:: } addAndMakeVisible(settingsButton); settingsButton.setTooltip("Opens the visualiser settings window."); - //if (visualiserOnly) { - addAndMakeVisible(sharedTextureButton); - sharedTextureButton.setTooltip("Toggles sending the oscilloscope's visuals to a Syphon/Spout receiver."); - sharedTextureButton.onClick = [this] { - if (sharedTextureSender != nullptr) { - openGLContext.executeOnGLThread([this](juce::OpenGLContext& context) { - closeSharedTexture(); - }, false); - } else { - openGLContext.executeOnGLThread([this](juce::OpenGLContext& context) { - initialiseSharedTexture(); - }, false); - } - }; - //} + +#if SOSCI_FEATURES + addAndMakeVisible(sharedTextureButton); + sharedTextureButton.setTooltip("Toggles sending the oscilloscope's visuals to a Syphon/Spout receiver."); + sharedTextureButton.onClick = [this] { + if (sharedTextureSender != nullptr) { + openGLContext.executeOnGLThread([this](juce::OpenGLContext& context) { + closeSharedTexture(); + }, false); + } else { + openGLContext.executeOnGLThread([this](juce::OpenGLContext& context) { + initialiseSharedTexture(); + }, false); + } + }; +#endif fullScreenButton.onClick = [this]() { enableFullScreen(); @@ -299,9 +300,9 @@ void VisualiserComponent::resized() { popOutButton.setBounds(buttons.removeFromRight(30)); } settingsButton.setBounds(buttons.removeFromRight(30)); - //if (visualiserOnly) { - sharedTextureButton.setBounds(buttons.removeFromRight(30)); - //} +#if SOSCI_FEATURES + sharedTextureButton.setBounds(buttons.removeFromRight(30)); +#endif record.setBounds(buttons.removeFromRight(25)); if (record.getToggleState()) { stopwatch.setVisible(true); @@ -318,9 +319,11 @@ void VisualiserComponent::resized() { } void VisualiserComponent::popoutWindow() { +#if SOSCI_FEATURES if (sharedTextureButton.getToggleState()) { sharedTextureButton.triggerClick(); } +#endif setRecording(false); auto visualiser = new VisualiserComponent(lastOpenedDirectory, ffmpegFile, haltRecording, threadManager, settings, recordingParameters, this); visualiser->settings.setLookAndFeel(&getLookAndFeel()); @@ -355,6 +358,7 @@ void VisualiserComponent::childUpdated() { } } +#if SOSCI_FEATURES void VisualiserComponent::initialiseSharedTexture() { sharedTextureSender = SharedTextureManager::getInstance()->addSender("osci-render - " + juce::String(juce::Time::getCurrentTime().toMilliseconds()), renderTexture.width, renderTexture.height); sharedTextureSender->initGL(); @@ -374,6 +378,7 @@ void VisualiserComponent::closeSharedTexture() { } } +#endif void VisualiserComponent::newOpenGLContextCreated() { using namespace juce::gl; @@ -418,10 +423,12 @@ void VisualiserComponent::newOpenGLContextCreated() { wideBlurShader->addFragmentShader(wideBlurFragmentShader); wideBlurShader->link(); +#if SOSCI_FEATURES glowShader = std::make_unique(openGLContext); glowShader->addVertexShader(juce::OpenGLHelpers::translateVertexShaderToV3(glowVertexShader)); glowShader->addFragmentShader(glowFragmentShader); glowShader->link(); +#endif glGenBuffers(1, &vertexBuffer); glGenBuffers(1, &quadIndexBuffer); @@ -433,7 +440,9 @@ void VisualiserComponent::newOpenGLContextCreated() { void VisualiserComponent::openGLContextClosing() { using namespace juce::gl; +#if SOSCI_FEATURES closeSharedTexture(); +#endif glDeleteBuffers(1, &quadIndexBuffer); glDeleteBuffers(1, &vertexIndexBuffer); @@ -444,16 +453,19 @@ void VisualiserComponent::openGLContextClosing() { glDeleteTextures(1, &blur2Texture.id); glDeleteTextures(1, &blur3Texture.id); glDeleteTextures(1, &blur4Texture.id); - glDeleteTextures(1, &glowTexture.id); glDeleteTextures(1, &renderTexture.id); screenOpenGLTexture.release(); + +#if SOSCI_FEATURES + glDeleteTextures(1, &glowTexture.id); reflectionOpenGLTexture.release(); + glowShader.reset(); +#endif simpleShader.reset(); texturedShader.reset(); blurShader.reset(); wideBlurShader.reset(); - glowShader.reset(); lineShader.reset(); outputShader.reset(); } @@ -479,11 +491,11 @@ void VisualiserComponent::renderOpenGL() { renderScope(xSamples, ySamples, zSamples); } - //if (parent == nullptr) { - if (sharedTextureSender != nullptr) { - sharedTextureSender->renderGL(); - } - //} +#if SOSCI_FEATURES + if (sharedTextureSender != nullptr) { + sharedTextureSender->renderGL(); + } +#endif if (record.getToggleState()) { if (recordingVideo) { @@ -579,11 +591,14 @@ void VisualiserComponent::setupTextures() { blur2Texture = makeTexture(512, 512); blur3Texture = makeTexture(128, 128); blur4Texture = makeTexture(128, 128); - glowTexture = makeTexture(512, 512); renderTexture = makeTexture(1024, 1024); - reflectionTexture = createReflectionTexture(); screenTexture = createScreenTexture(); + +#if SOSCI_FEATURES + glowTexture = makeTexture(512, 512); + reflectionTexture = createReflectionTexture(); +#endif glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind } @@ -781,11 +796,12 @@ void VisualiserComponent::drawLine(const std::vector& xPoints, const std: lineShader->setUniform("uFadeAmount", fadeAmount); lineShader->setUniform("uNEdges", (GLfloat) nEdges); - - lineShader->setUniform("uScreenType", (GLfloat) screenType); - lineShader->setUniform("uFishEye", screenType == ScreenType::VectorDisplay ? VECTOR_DISPLAY_FISH_EYE : 0.0f); setOffsetAndScale(lineShader.get()); +#if SOSCI_FEATURES + lineShader->setUniform("uScreenType", (GLfloat) screenType); + lineShader->setUniform("uFishEye", screenType == ScreenType::VectorDisplay ? VECTOR_DISPLAY_FISH_EYE : 0.0f); +#endif glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vertexIndexBuffer); int nEdgesThisTime = xPoints.size() - 1; @@ -851,23 +867,27 @@ void VisualiserComponent::drawCRT() { wideBlurShader->setUniform("uOffset", 0.0f, 1.0f / 128.0f); drawTexture({blur4Texture}); - // create glow texture - activateTargetTexture(glowTexture); - setShader(glowShader.get()); - setOffsetAndScale(glowShader.get()); - drawTexture({blur3Texture}); - - // blur the glow texture to blend it nicely. blur3Texture and blur1Texture are reserved, so we can't use them - // horizontal 512x512 - activateTargetTexture(blur2Texture); - setShader(wideBlurShader.get()); - wideBlurShader->setUniform("uOffset", 1.0f / 512.0f, 0.0f); - drawTexture({glowTexture}); - - // vertical 512x512 - activateTargetTexture(glowTexture); - wideBlurShader->setUniform("uOffset", 0.0f, 1.0f / 512.0f); - drawTexture({blur2Texture}); +#if SOSCI_FEATURES + if (settings.parameters.screenType->isRealisticDisplay()) { + // create glow texture + activateTargetTexture(glowTexture); + setShader(glowShader.get()); + setOffsetAndScale(glowShader.get()); + drawTexture({blur3Texture}); + + // blur the glow texture to blend it nicely. blur3Texture and blur1Texture are reserved, so we can't use them + // horizontal 512x512 + activateTargetTexture(blur2Texture); + setShader(wideBlurShader.get()); + wideBlurShader->setUniform("uOffset", 1.0f / 512.0f, 0.0f); + drawTexture({glowTexture}); + + // vertical 512x512 + activateTargetTexture(glowTexture); + wideBlurShader->setUniform("uOffset", 0.0f, 1.0f / 512.0f); + drawTexture({blur2Texture}); + } +#endif activateTargetTexture(renderTexture); setShader(outputShader.get()); @@ -877,36 +897,50 @@ void VisualiserComponent::drawCRT() { outputShader->setUniform("uTime", time); outputShader->setUniform("uGlow", (float) settings.getGlow()); outputShader->setUniform("uAmbient", (float) settings.getAmbient()); - outputShader->setUniform("uFishEye", screenType == ScreenType::VectorDisplay ? VECTOR_DISPLAY_FISH_EYE : 0.0f); setOffsetAndScale(outputShader.get()); +#if SOSCI_FEATURES + outputShader->setUniform("uFishEye", screenType == ScreenType::VectorDisplay ? VECTOR_DISPLAY_FISH_EYE : 0.0f); outputShader->setUniform("uRealScreen", settings.parameters.screenType->isRealisticDisplay() ? 1.0f : 0.0f); +#endif outputShader->setUniform("uResizeForCanvas", lineTexture.width / 1024.0f); juce::Colour colour = juce::Colour::fromHSV(settings.getHue() / 360.0f, 1.0, 1.0, 1.0); outputShader->setUniform("uColour", colour.getFloatRed(), colour.getFloatGreen(), colour.getFloatBlue()); - drawTexture({lineTexture, blur1Texture, blur3Texture, screenTexture, reflectionTexture, glowTexture}); + drawTexture({ + lineTexture, + blur1Texture, + blur3Texture, + screenTexture, +#if SOSCI_FEATURES + reflectionTexture, + glowTexture, +#endif + }); } void VisualiserComponent::setOffsetAndScale(juce::OpenGLShaderProgram* shader) { OsciPoint offset; - OsciPoint scale; + OsciPoint scale = { 1.0f }; +#if SOSCI_FEATURES if (settings.getScreenType() == ScreenType::Real) { offset = REAL_SCREEN_OFFSET; scale = REAL_SCREEN_SCALE; } else if (settings.getScreenType() == ScreenType::VectorDisplay) { offset = VECTOR_DISPLAY_OFFSET; scale = VECTOR_DISPLAY_SCALE; - } else { - scale = { 1.0f }; } +#endif shader->setUniform("uOffset", (float) offset.x, (float) offset.y); shader->setUniform("uScale", (float) scale.x, (float) scale.y); } +#if SOSCI_FEATURES Texture VisualiserComponent::createReflectionTexture() { using namespace juce::gl; if (settings.getScreenType() == ScreenType::VectorDisplay) { reflectionOpenGLTexture.loadImage(vectorDisplayReflectionImage); + } else if (settings.getScreenType() == ScreenType::Real) { + reflectionOpenGLTexture.loadImage(oscilloscopeReflectionImage); } else { reflectionOpenGLTexture.loadImage(emptyReflectionImage); } @@ -915,16 +949,19 @@ Texture VisualiserComponent::createReflectionTexture() { return texture; } +#endif Texture VisualiserComponent::createScreenTexture() { using namespace juce::gl; if (screenType == ScreenType::Smudged || screenType == ScreenType::SmudgedGraticule) { screenOpenGLTexture.loadImage(screenTextureImage); +#if SOSCI_FEATURES } else if (screenType == ScreenType::Real) { screenOpenGLTexture.loadImage(oscilloscopeImage); } else if (screenType == ScreenType::VectorDisplay) { screenOpenGLTexture.loadImage(vectorDisplayImage); +#endif } else { screenOpenGLTexture.loadImage(emptyScreenImage); } @@ -1011,7 +1048,11 @@ void VisualiserComponent::checkGLErrors(const juce::String& location) { void VisualiserComponent::paint(juce::Graphics& g) { +#if SOSCI_FEATURES g.setColour(settings.getScreenType() == ScreenType::Real ? Colours::dark : Colours::veryDark); +#else + g.setColour(Colours::veryDark); +#endif g.fillRect(buttonRow); if (!active) { // draw a translucent overlay @@ -1030,7 +1071,9 @@ void VisualiserComponent::renderScope(const std::vector& xPoints, const s if (screenType != settings.getScreenType()) { screenType = settings.getScreenType(); +#if SOSCI_FEATURES reflectionTexture = createReflectionTexture(); +#endif screenTexture = createScreenTexture(); } diff --git a/Source/visualiser/VisualiserComponent.h b/Source/visualiser/VisualiserComponent.h index b8d5f54..2db8125 100644 --- a/Source/visualiser/VisualiserComponent.h +++ b/Source/visualiser/VisualiserComponent.h @@ -75,12 +75,14 @@ private: SvgButton fullScreenButton{ "fullScreen", BinaryData::fullscreen_svg, juce::Colours::white, juce::Colours::white }; SvgButton popOutButton{ "popOut", BinaryData::open_in_new_svg, juce::Colours::white, juce::Colours::white }; SvgButton settingsButton{ "settings", BinaryData::cog_svg, juce::Colours::white, juce::Colours::white }; + +#if SOSCI_FEATURES SvgButton sharedTextureButton{ "sharedTexture", BinaryData::spout_svg, juce::Colours::white, juce::Colours::red }; + SharedTextureSender* sharedTextureSender = nullptr; +#endif std::function fullScreenCallback; - SharedTextureSender* sharedTextureSender = nullptr; - VisualiserSettings& settings; RecordingParameters& recordingParameters; bool recordingAudio = false; @@ -170,14 +172,19 @@ private: Texture blur4Texture; Texture glowTexture; Texture renderTexture; + Texture screenTexture; juce::OpenGLTexture screenOpenGLTexture; - juce::OpenGLTexture reflectionOpenGLTexture; + std::optional targetTexture = std::nullopt; + juce::Image screenTextureImage = juce::ImageFileFormat::loadFrom(BinaryData::noise_jpg, BinaryData::noise_jpgSize); juce::Image emptyScreenImage = juce::ImageFileFormat::loadFrom(BinaryData::empty_jpg, BinaryData::empty_jpgSize); + +#if SOSCI_FEATURES juce::Image oscilloscopeImage = juce::ImageFileFormat::loadFrom(BinaryData::real_jpg, BinaryData::real_jpgSize); juce::Image vectorDisplayImage = juce::ImageFileFormat::loadFrom(BinaryData::vector_display_jpg, BinaryData::vector_display_jpgSize); juce::Image emptyReflectionImage = juce::ImageFileFormat::loadFrom(BinaryData::no_reflection_jpg, BinaryData::no_reflection_jpgSize); + juce::Image oscilloscopeReflectionImage = juce::ImageFileFormat::loadFrom(BinaryData::real_reflection_jpg, BinaryData::real_reflection_jpgSize); juce::Image vectorDisplayReflectionImage = juce::ImageFileFormat::loadFrom(BinaryData::vector_display_reflection_jpg, BinaryData::vector_display_reflection_jpgSize); OsciPoint REAL_SCREEN_OFFSET = { 0.02, -0.15 }; @@ -187,15 +194,16 @@ private: OsciPoint VECTOR_DISPLAY_SCALE = { 0.6 }; float VECTOR_DISPLAY_FISH_EYE = 0.5; - Texture screenTexture; + juce::OpenGLTexture reflectionOpenGLTexture; Texture reflectionTexture; - std::optional targetTexture = std::nullopt; + + std::unique_ptr glowShader; +#endif std::unique_ptr simpleShader; std::unique_ptr texturedShader; std::unique_ptr blurShader; std::unique_ptr wideBlurShader; - std::unique_ptr glowShader; std::unique_ptr lineShader; std::unique_ptr outputShader; juce::OpenGLShaderProgram* currentShader; @@ -209,10 +217,12 @@ private: chowdsp::ResamplingTypes::LanczosResampler<2048, 8> xResampler; chowdsp::ResamplingTypes::LanczosResampler<2048, 8> yResampler; chowdsp::ResamplingTypes::LanczosResampler<2048, 8> zResampler; - + void setOffsetAndScale(juce::OpenGLShaderProgram* shader); +#if SOSCI_FEATURES void initialiseSharedTexture(); void closeSharedTexture(); +#endif Texture makeTexture(int width, int height); void setupArrays(int num_points); void setupTextures(); diff --git a/Source/visualiser/VisualiserSettings.h b/Source/visualiser/VisualiserSettings.h index 2c8e610..9a5096e 100644 --- a/Source/visualiser/VisualiserSettings.h +++ b/Source/visualiser/VisualiserSettings.h @@ -14,13 +14,18 @@ enum class ScreenType : int { Graticule = 2, Smudged = 3, SmudgedGraticule = 4, +#if SOSCI_FEATURES Real = 5, VectorDisplay = 6, + MAX = 6, +#else + MAX = 4, +#endif }; class ScreenTypeParameter : public IntParameter { public: - ScreenTypeParameter(juce::String name, juce::String id, int versionHint, ScreenType value) : IntParameter(name, id, versionHint, (int) value, 1, 6) {} + ScreenTypeParameter(juce::String name, juce::String id, int versionHint, ScreenType value) : IntParameter(name, id, versionHint, (int) value, 1, (int)ScreenType::MAX) {} juce::String getText(float value, int maximumStringLength = 100) const override { switch ((ScreenType)(int)getUnnormalisedValue(value)) { @@ -32,10 +37,12 @@ public: return "Smudged"; case ScreenType::SmudgedGraticule: return "Smudged Graticule"; +#if SOSCI_FEATURES case ScreenType::Real: return "Real Oscilloscope"; case ScreenType::VectorDisplay: return "Vector Display"; +#endif default: return "Unknown"; } @@ -51,10 +58,12 @@ public: unnormalisedValue = (int)ScreenType::Smudged; } else if (text == "Smudged Graticule") { unnormalisedValue = (int)ScreenType::SmudgedGraticule; +#if SOSCI_FEATURES } else if (text == "Real Oscilloscope") { unnormalisedValue = (int)ScreenType::Real; } else if (text == "Vector Display") { unnormalisedValue = (int)ScreenType::VectorDisplay; +#endif } else { unnormalisedValue = (int)ScreenType::Empty; } @@ -69,10 +78,12 @@ public: setValueNotifyingHost(getValueForText(xml->getStringAttribute("screenType"))); } +#if SOSCI_FEATURES bool isRealisticDisplay() { ScreenType type = (ScreenType)(int)getValueUnnormalised(); return type == ScreenType::Real || type == ScreenType::VectorDisplay; } +#endif }; class VisualiserParameters { diff --git a/osci-render.jucer b/osci-render.jucer index 46091b1..8b277fb 100644 --- a/osci-render.jucer +++ b/osci-render.jucer @@ -5,7 +5,7 @@ pluginManufacturer="jameshball" aaxIdentifier="sh.ball.oscirender" cppLanguageStandard="20" projectLineFeed=" " headerPath="./include" version="2.3.0" companyName="James H Ball" companyWebsite="https://osci-render.com" - companyEmail="james@ball.sh" defines="NOMINMAX=1 INTERNET_FLAG_NO_AUTO_REDIRECT=0" + companyEmail="james@ball.sh" defines="NOMINMAX=1 INTERNET_FLAG_NO_AUTO_REDIRECT=0 SOSCI_FEATURES=0" pluginAUMainType="'aumf'" postExportShellCommandPosix="%%1%%/ci/remove_embed_frameworks.sh %%1%%/Builds/MacOSX/osci-render.xcodeproj/project.pbxproj osci-render"> @@ -37,6 +37,8 @@ file="Resources/oscilloscope/no_reflection.jpg"/> + + defines="NOMINMAX=1 INTERNET_FLAG_NO_AUTO_REDIRECT=0 SOSCI_FEATURES=1" + pluginManufacturerCode="Jhba" pluginCode="Sosc" pluginAUMainType="'aufx'" + postExportShellCommandPosix="%%1%%/ci/remove_embed_frameworks.sh %%1%%/Builds/sosci/MacOSX/sosci.xcodeproj/project.pbxproj sosci"> @@ -26,6 +27,8 @@ file="Resources/oscilloscope/no_reflection.jpg"/> +