1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Plugin Client: Remove unnecessary wrapper files

This commit is contained in:
reuk 2023-03-13 13:14:18 +00:00
parent 22c8f0fe7e
commit 33ef4a86f4
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C
31 changed files with 16454 additions and 16805 deletions

View file

@ -1,774 +0,0 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
#include <juce_core/system/juce_TargetPlatform.h>
#if JucePlugin_Build_Unity
#include <juce_audio_plugin_client/detail/juce_PluginUtilities.h>
#include <juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp>
#if JUCE_WINDOWS
#include <juce_audio_plugin_client/detail/juce_IncludeSystemHeaders.h>
#endif
#include "juce_UnityPluginInterface.h"
//==============================================================================
namespace juce
{
typedef ComponentPeer* (*createUnityPeerFunctionType) (Component&);
extern createUnityPeerFunctionType juce_createUnityPeerFn;
//==============================================================================
class UnityPeer : public ComponentPeer,
public AsyncUpdater
{
public:
UnityPeer (Component& ed)
: ComponentPeer (ed, 0),
mouseWatcher (*this)
{
getEditor().setResizable (false, false);
}
//==============================================================================
Rectangle<int> getBounds() const override { return bounds; }
Point<float> localToGlobal (Point<float> relativePosition) override { return relativePosition + getBounds().getPosition().toFloat(); }
Point<float> globalToLocal (Point<float> screenPosition) override { return screenPosition - getBounds().getPosition().toFloat(); }
using ComponentPeer::localToGlobal;
using ComponentPeer::globalToLocal;
StringArray getAvailableRenderingEngines() override { return StringArray ("Software Renderer"); }
void setBounds (const Rectangle<int>& newBounds, bool) override
{
bounds = newBounds;
mouseWatcher.setBoundsToWatch (bounds);
}
bool contains (Point<int> localPos, bool) const override
{
if (isPositiveAndBelow (localPos.getX(), getBounds().getWidth())
&& isPositiveAndBelow (localPos.getY(), getBounds().getHeight()))
return true;
return false;
}
void handleAsyncUpdate() override
{
fillPixels();
}
//==============================================================================
AudioProcessorEditor& getEditor() { return *dynamic_cast<AudioProcessorEditor*> (&getComponent()); }
void setPixelDataHandle (uint8* handle, int width, int height)
{
pixelData = handle;
textureWidth = width;
textureHeight = height;
renderImage = Image (new UnityBitmapImage (pixelData, width, height));
}
// N.B. This is NOT an efficient way to do this and you shouldn't use this method in your own code.
// It works for our purposes here but a much more efficient way would be to use a GL texture.
void fillPixels()
{
if (pixelData == nullptr)
return;
LowLevelGraphicsSoftwareRenderer renderer (renderImage);
renderer.addTransform (AffineTransform::verticalFlip ((float) getComponent().getHeight()));
handlePaint (renderer);
for (int i = 0; i < textureWidth * textureHeight * 4; i += 4)
{
auto r = pixelData[i + 2];
auto g = pixelData[i + 1];
auto b = pixelData[i + 0];
pixelData[i + 0] = r;
pixelData[i + 1] = g;
pixelData[i + 2] = b;
}
}
void forwardMouseEvent (Point<float> position, ModifierKeys mods)
{
ModifierKeys::currentModifiers = mods;
handleMouseEvent (juce::MouseInputSource::mouse, position, mods, juce::MouseInputSource::defaultPressure,
juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
}
void forwardKeyPress (int code, String name, ModifierKeys mods)
{
ModifierKeys::currentModifiers = mods;
handleKeyPress (getKeyPress (code, name));
}
private:
//==============================================================================
struct UnityBitmapImage : public ImagePixelData
{
UnityBitmapImage (uint8* data, int w, int h)
: ImagePixelData (Image::PixelFormat::ARGB, w, h),
imageData (data),
lineStride (width * pixelStride)
{
}
std::unique_ptr<ImageType> createType() const override
{
return std::make_unique<SoftwareImageType>();
}
std::unique_ptr<LowLevelGraphicsContext> createLowLevelContext() override
{
return std::make_unique<LowLevelGraphicsSoftwareRenderer> (Image (this));
}
void initialiseBitmapData (Image::BitmapData& bitmap, int x, int y, [[maybe_unused]] Image::BitmapData::ReadWriteMode mode) override
{
const auto offset = (size_t) x * (size_t) pixelStride + (size_t) y * (size_t) lineStride;
bitmap.data = imageData + offset;
bitmap.size = (size_t) (lineStride * height) - offset;
bitmap.pixelFormat = pixelFormat;
bitmap.lineStride = lineStride;
bitmap.pixelStride = pixelStride;
}
ImagePixelData::Ptr clone() override
{
auto im = new UnityBitmapImage (imageData, width, height);
for (int i = 0; i < height; ++i)
memcpy (im->imageData + i * lineStride, imageData + i * lineStride, (size_t) lineStride);
return im;
}
uint8* imageData;
int pixelStride = 4, lineStride;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityBitmapImage)
};
//==============================================================================
struct MouseWatcher : public Timer
{
MouseWatcher (ComponentPeer& o) : owner (o) {}
void timerCallback() override
{
auto pos = Desktop::getMousePosition();
if (boundsToWatch.contains (pos) && pos != lastMousePos)
{
auto ms = Desktop::getInstance().getMainMouseSource();
if (! ms.getCurrentModifiers().isLeftButtonDown())
owner.handleMouseEvent (juce::MouseInputSource::mouse, owner.globalToLocal (pos.toFloat()), {},
juce::MouseInputSource::defaultPressure, juce::MouseInputSource::defaultOrientation, juce::Time::currentTimeMillis());
lastMousePos = pos;
}
}
void setBoundsToWatch (Rectangle<int> b)
{
if (boundsToWatch != b)
boundsToWatch = b;
startTimer (250);
}
ComponentPeer& owner;
Rectangle<int> boundsToWatch;
Point<int> lastMousePos;
};
//==============================================================================
KeyPress getKeyPress (int keyCode, String name)
{
if (keyCode >= 32 && keyCode <= 64)
return { keyCode, ModifierKeys::currentModifiers, juce::juce_wchar (keyCode) };
if (keyCode >= 91 && keyCode <= 122)
return { keyCode, ModifierKeys::currentModifiers, name[0] };
if (keyCode >= 256 && keyCode <= 265)
return { juce::KeyPress::numberPad0 + (keyCode - 256), ModifierKeys::currentModifiers, juce::String (keyCode - 256).getCharPointer()[0] };
if (keyCode == 8) return { juce::KeyPress::backspaceKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 127) return { juce::KeyPress::deleteKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 9) return { juce::KeyPress::tabKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 13) return { juce::KeyPress::returnKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 27) return { juce::KeyPress::escapeKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 32) return { juce::KeyPress::spaceKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 266) return { juce::KeyPress::numberPadDecimalPoint, ModifierKeys::currentModifiers, {} };
if (keyCode == 267) return { juce::KeyPress::numberPadDivide, ModifierKeys::currentModifiers, {} };
if (keyCode == 268) return { juce::KeyPress::numberPadMultiply, ModifierKeys::currentModifiers, {} };
if (keyCode == 269) return { juce::KeyPress::numberPadSubtract, ModifierKeys::currentModifiers, {} };
if (keyCode == 270) return { juce::KeyPress::numberPadAdd, ModifierKeys::currentModifiers, {} };
if (keyCode == 272) return { juce::KeyPress::numberPadEquals, ModifierKeys::currentModifiers, {} };
if (keyCode == 273) return { juce::KeyPress::upKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 274) return { juce::KeyPress::downKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 275) return { juce::KeyPress::rightKey, ModifierKeys::currentModifiers, {} };
if (keyCode == 276) return { juce::KeyPress::leftKey, ModifierKeys::currentModifiers, {} };
return {};
}
//==============================================================================
Rectangle<int> bounds;
MouseWatcher mouseWatcher;
uint8* pixelData = nullptr;
int textureWidth, textureHeight;
Image renderImage;
//==============================================================================
void setMinimised (bool) override {}
bool isMinimised() const override { return false; }
void setFullScreen (bool) override {}
bool isFullScreen() const override { return false; }
bool setAlwaysOnTop (bool) override { return false; }
void toFront (bool) override {}
void toBehind (ComponentPeer*) override {}
bool isFocused() const override { return true; }
void grabFocus() override {}
void* getNativeHandle() const override { return nullptr; }
OptionalBorderSize getFrameSizeIfPresent() const override { return {}; }
BorderSize<int> getFrameSize() const override { return {}; }
void setVisible (bool) override {}
void setTitle (const String&) override {}
void setIcon (const Image&) override {}
void textInputRequired (Point<int>, TextInputTarget&) override {}
void setAlpha (float) override {}
void performAnyPendingRepaintsNow() override {}
void repaint (const Rectangle<int>&) override {}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UnityPeer)
};
static ComponentPeer* createUnityPeer (Component& c) { return new UnityPeer (c); }
//==============================================================================
class AudioProcessorUnityWrapper
{
public:
AudioProcessorUnityWrapper (bool isTemporary)
{
pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_Unity);
if (! isTemporary && pluginInstance->hasEditor())
{
pluginInstanceEditor.reset (pluginInstance->createEditorIfNeeded());
pluginInstanceEditor->setVisible (true);
detail::PluginUtilities::addToDesktop (*pluginInstanceEditor, nullptr);
}
juceParameters.update (*pluginInstance, false);
}
~AudioProcessorUnityWrapper()
{
if (pluginInstanceEditor != nullptr)
{
pluginInstanceEditor->removeFromDesktop();
PopupMenu::dismissAllActiveMenus();
pluginInstanceEditor->processor.editorBeingDeleted (pluginInstanceEditor.get());
pluginInstanceEditor = nullptr;
}
}
void create (UnityAudioEffectState* state)
{
// only supported in Unity plugin API > 1.0
if (state->structSize >= sizeof (UnityAudioEffectState))
samplesPerBlock = static_cast<int> (state->dspBufferSize);
#ifdef JucePlugin_PreferredChannelConfigurations
short configs[][2] = { JucePlugin_PreferredChannelConfigurations };
const int numConfigs = sizeof (configs) / sizeof (short[2]);
jassertquiet (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], state->sampleRate, samplesPerBlock);
#else
pluginInstance->setRateAndBufferSizeDetails (state->sampleRate, samplesPerBlock);
#endif
pluginInstance->prepareToPlay (state->sampleRate, samplesPerBlock);
scratchBuffer.setSize (jmax (pluginInstance->getTotalNumInputChannels(), pluginInstance->getTotalNumOutputChannels()), samplesPerBlock);
}
void release()
{
pluginInstance->releaseResources();
}
void reset()
{
pluginInstance->reset();
}
void process (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
{
// If the plugin has a bypass parameter, set it to the current bypass state
if (auto* param = pluginInstance->getBypassParameter())
if (isBypassed != (param->getValue() >= 0.5f))
param->setValueNotifyingHost (isBypassed ? 1.0f : 0.0f);
for (int pos = 0; pos < bufferSize;)
{
auto max = jmin (bufferSize - pos, samplesPerBlock);
processBuffers (inBuffer + (pos * numInChannels), outBuffer + (pos * numOutChannels), max, numInChannels, numOutChannels, isBypassed);
pos += max;
}
}
void declareParameters (UnityAudioEffectDefinition& definition)
{
static std::unique_ptr<UnityAudioParameterDefinition> parametersPtr;
static int numParams = 0;
if (parametersPtr == nullptr)
{
numParams = (int) juceParameters.size();
parametersPtr.reset (static_cast<UnityAudioParameterDefinition*> (std::calloc (static_cast<size_t> (numParams),
sizeof (UnityAudioParameterDefinition))));
parameterDescriptions.clear();
for (int i = 0; i < numParams; ++i)
{
auto* parameter = juceParameters.getParamForIndex (i);
auto& paramDef = parametersPtr.get()[i];
const auto nameLength = (size_t) numElementsInArray (paramDef.name);
const auto unitLength = (size_t) numElementsInArray (paramDef.unit);
parameter->getName ((int) nameLength - 1).copyToUTF8 (paramDef.name, nameLength);
if (parameter->getLabel().isNotEmpty())
parameter->getLabel().copyToUTF8 (paramDef.unit, unitLength);
parameterDescriptions.add (parameter->getName (15));
paramDef.description = parameterDescriptions[i].toRawUTF8();
paramDef.defaultVal = parameter->getDefaultValue();
paramDef.min = 0.0f;
paramDef.max = 1.0f;
paramDef.displayScale = 1.0f;
paramDef.displayExponent = 1.0f;
}
}
definition.numParameters = static_cast<uint32> (numParams);
definition.parameterDefintions = parametersPtr.get();
}
void setParameter (int index, float value) { juceParameters.getParamForIndex (index)->setValueNotifyingHost (value); }
float getParameter (int index) const noexcept { return juceParameters.getParamForIndex (index)->getValue(); }
String getParameterString (int index) const noexcept
{
auto* param = juceParameters.getParamForIndex (index);
return param->getText (param->getValue(), 16);
}
int getNumInputChannels() const noexcept { return pluginInstance->getTotalNumInputChannels(); }
int getNumOutputChannels() const noexcept { return pluginInstance->getTotalNumOutputChannels(); }
bool hasEditor() const noexcept { return pluginInstance->hasEditor(); }
UnityPeer& getEditorPeer() const
{
auto* peer = dynamic_cast<UnityPeer*> (pluginInstanceEditor->getPeer());
jassert (peer != nullptr);
return *peer;
}
private:
//==============================================================================
void processBuffers (float* inBuffer, float* outBuffer, int bufferSize, int numInChannels, int numOutChannels, bool isBypassed)
{
int ch;
for (ch = 0; ch < numInChannels; ++ch)
{
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst>;
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::Const>;
DstSampleType dstData (scratchBuffer.getWritePointer (ch));
SrcSampleType srcData (inBuffer + ch, numInChannels);
dstData.convertSamples (srcData, bufferSize);
}
for (; ch < numOutChannels; ++ch)
scratchBuffer.clear (ch, 0, bufferSize);
{
const ScopedLock sl (pluginInstance->getCallbackLock());
if (pluginInstance->isSuspended())
{
scratchBuffer.clear();
}
else
{
MidiBuffer mb;
if (isBypassed && pluginInstance->getBypassParameter() == nullptr)
pluginInstance->processBlockBypassed (scratchBuffer, mb);
else
pluginInstance->processBlock (scratchBuffer, mb);
}
}
for (ch = 0; ch < numOutChannels; ++ch)
{
using DstSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::Interleaved, AudioData::NonConst>;
using SrcSampleType = AudioData::Pointer<AudioData::Float32, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const>;
DstSampleType dstData (outBuffer + ch, numOutChannels);
SrcSampleType srcData (scratchBuffer.getReadPointer (ch));
dstData.convertSamples (srcData, bufferSize);
}
}
//==============================================================================
std::unique_ptr<AudioProcessor> pluginInstance;
std::unique_ptr<AudioProcessorEditor> pluginInstanceEditor;
int samplesPerBlock = 1024;
StringArray parameterDescriptions;
AudioBuffer<float> scratchBuffer;
LegacyAudioParametersWrapper juceParameters;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorUnityWrapper)
};
//==============================================================================
static HashMap<int, AudioProcessorUnityWrapper*>& getWrapperMap()
{
static HashMap<int, AudioProcessorUnityWrapper*> wrapperMap;
return wrapperMap;
}
static void onWrapperCreation (AudioProcessorUnityWrapper* wrapperToAdd)
{
getWrapperMap().set (std::abs (Random::getSystemRandom().nextInt (65536)), wrapperToAdd);
}
static void onWrapperDeletion (AudioProcessorUnityWrapper* wrapperToRemove)
{
getWrapperMap().removeValue (wrapperToRemove);
}
//==============================================================================
static UnityAudioEffectDefinition getEffectDefinition()
{
const auto wrapper = std::make_unique<AudioProcessorUnityWrapper> (true);
const String originalName { JucePlugin_Name };
const auto name = (! originalName.startsWithIgnoreCase ("audioplugin") ? "audioplugin_" : "") + originalName;
UnityAudioEffectDefinition result{};
name.copyToUTF8 (result.name, (size_t) numElementsInArray (result.name));
result.structSize = sizeof (UnityAudioEffectDefinition);
result.parameterStructSize = sizeof (UnityAudioParameterDefinition);
result.apiVersion = UNITY_AUDIO_PLUGIN_API_VERSION;
result.pluginVersion = JucePlugin_VersionCode;
// effects must set this to 0, generators > 0
result.channels = (wrapper->getNumInputChannels() != 0 ? 0
: static_cast<uint32> (wrapper->getNumOutputChannels()));
wrapper->declareParameters (result);
result.create = [] (UnityAudioEffectState* state)
{
auto* pluginInstance = new AudioProcessorUnityWrapper (false);
pluginInstance->create (state);
state->effectData = pluginInstance;
onWrapperCreation (pluginInstance);
return 0;
};
result.release = [] (UnityAudioEffectState* state)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->release();
onWrapperDeletion (pluginInstance);
delete pluginInstance;
if (getWrapperMap().size() == 0)
shutdownJuce_GUI();
return 0;
};
result.reset = [] (UnityAudioEffectState* state)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->reset();
return 0;
};
result.setPosition = [] (UnityAudioEffectState* state, unsigned int pos)
{
ignoreUnused (state, pos);
return 0;
};
result.process = [] (UnityAudioEffectState* state,
float* inBuffer,
float* outBuffer,
unsigned int bufferSize,
int numInChannels,
int numOutChannels)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
if (pluginInstance != nullptr)
{
auto isPlaying = ((state->flags & stateIsPlaying) != 0);
auto isMuted = ((state->flags & stateIsMuted) != 0);
auto isPaused = ((state->flags & stateIsPaused) != 0);
const auto bypassed = ! isPlaying || (isMuted || isPaused);
pluginInstance->process (inBuffer, outBuffer, static_cast<int> (bufferSize), numInChannels, numOutChannels, bypassed);
}
else
{
FloatVectorOperations::clear (outBuffer, static_cast<int> (bufferSize) * numOutChannels);
}
return 0;
};
result.setFloatParameter = [] (UnityAudioEffectState* state, int index, float value)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
pluginInstance->setParameter (index, value);
return 0;
};
result.getFloatParameter = [] (UnityAudioEffectState* state, int index, float* value, char* valueStr)
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
*value = pluginInstance->getParameter (index);
pluginInstance->getParameterString (index).copyToUTF8 (valueStr, 15);
return 0;
};
result.getFloatBuffer = [] (UnityAudioEffectState* state, const char* kind, float* buffer, int numSamples)
{
ignoreUnused (numSamples);
const StringRef kindStr { kind };
if (kindStr == StringRef ("Editor"))
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
buffer[0] = pluginInstance->hasEditor() ? 1.0f : 0.0f;
}
else if (kindStr == StringRef ("ID"))
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
for (HashMap<int, AudioProcessorUnityWrapper*>::Iterator i (getWrapperMap()); i.next();)
{
if (i.getValue() == pluginInstance)
{
buffer[0] = (float) i.getKey();
break;
}
}
return 0;
}
else if (kindStr == StringRef ("Size"))
{
auto* pluginInstance = state->getEffectData<AudioProcessorUnityWrapper>();
auto& editor = pluginInstance->getEditorPeer().getEditor();
buffer[0] = (float) editor.getBounds().getWidth();
buffer[1] = (float) editor.getBounds().getHeight();
buffer[2] = (float) editor.getConstrainer()->getMinimumWidth();
buffer[3] = (float) editor.getConstrainer()->getMinimumHeight();
buffer[4] = (float) editor.getConstrainer()->getMaximumWidth();
buffer[5] = (float) editor.getConstrainer()->getMaximumHeight();
}
return 0;
};
return result;
}
} // namespace juce
// From reading the example code, it seems that the triple indirection indicates
// an out-value of an array of pointers. That is, after calling this function, definitionsPtr
// should point to a pre-existing/static array of pointer-to-effect-definition.
UNITY_INTERFACE_EXPORT int UNITY_INTERFACE_API UnityGetAudioEffectDefinitions (UnityAudioEffectDefinition*** definitionsPtr)
{
if (juce::getWrapperMap().size() == 0)
juce::initialiseJuce_GUI();
static std::once_flag flag;
std::call_once (flag, [] { juce::juce_createUnityPeerFn = juce::createUnityPeer; });
static auto definition = juce::getEffectDefinition();
static UnityAudioEffectDefinition* definitions[] { &definition };
*definitionsPtr = definitions;
return 1;
}
//==============================================================================
static juce::ModifierKeys unityModifiersToJUCE (UnityEventModifiers mods, bool mouseDown, int mouseButton = -1)
{
int flags = 0;
if (mouseDown)
{
if (mouseButton == 0)
flags |= juce::ModifierKeys::leftButtonModifier;
else if (mouseButton == 1)
flags |= juce::ModifierKeys::rightButtonModifier;
else if (mouseButton == 2)
flags |= juce::ModifierKeys::middleButtonModifier;
}
if (mods == 0)
return flags;
if ((mods & UnityEventModifiers::shift) != 0) flags |= juce::ModifierKeys::shiftModifier;
if ((mods & UnityEventModifiers::control) != 0) flags |= juce::ModifierKeys::ctrlModifier;
if ((mods & UnityEventModifiers::alt) != 0) flags |= juce::ModifierKeys::altModifier;
if ((mods & UnityEventModifiers::command) != 0) flags |= juce::ModifierKeys::commandModifier;
return { flags };
}
//==============================================================================
static juce::AudioProcessorUnityWrapper* getWrapperChecked (int id)
{
auto* wrapper = juce::getWrapperMap()[id];
jassert (wrapper != nullptr);
return wrapper;
}
//==============================================================================
static void UNITY_INTERFACE_API onRenderEvent (int id)
{
getWrapperChecked (id)->getEditorPeer().triggerAsyncUpdate();
}
UNITY_INTERFACE_EXPORT renderCallback UNITY_INTERFACE_API getRenderCallback()
{
return onRenderEvent;
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityInitialiseTexture (int id, void* data, int w, int h)
{
getWrapperChecked (id)->getEditorPeer().setPixelDataHandle (reinterpret_cast<juce::uint8*> (data), w, h);
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDown (int id, float x, float y, UnityEventModifiers unityMods, int button)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseDrag (int id, float x, float y, UnityEventModifiers unityMods, int button)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, true, button));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityMouseUp (int id, float x, float y, UnityEventModifiers unityMods)
{
getWrapperChecked (id)->getEditorPeer().forwardMouseEvent ({ x, y }, unityModifiersToJUCE (unityMods, false));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unityKeyEvent (int id, int code, UnityEventModifiers mods, const char* name)
{
getWrapperChecked (id)->getEditorPeer().forwardKeyPress (code, name, unityModifiersToJUCE (mods, false));
}
UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API unitySetScreenBounds (int id, float x, float y, float w, float h)
{
getWrapperChecked (id)->getEditorPeer().getEditor().setBounds ({ (int) x, (int) y, (int) w, (int) h });
}
//==============================================================================
#if JUCE_WINDOWS
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmissing-prototypes")
extern "C" BOOL WINAPI DllMain (HINSTANCE instance, DWORD reason, LPVOID)
{
if (reason == DLL_PROCESS_ATTACH)
juce::Process::setCurrentModuleInstanceHandle (instance);
return true;
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
#endif
#endif