306 lines
8.1 KiB
C++
306 lines
8.1 KiB
C++
// Example low level rendering Unity plugin
|
|
|
|
#include "PlatformBase.h"
|
|
#include "RenderAPI.h"
|
|
#include "IUnityLog.h"
|
|
#include "IUnityRenderingExtensions.h"
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <vector>
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// SetTimeFromUnity, an example function we export which is called by one of the scripts.
|
|
|
|
static float g_Time;
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API SetTimeFromUnity (float t) { g_Time = t; }
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// SetTextureFromUnity, an example function we export which is called by one of the scripts.
|
|
|
|
static void* g_TextureHandle = NULL;
|
|
static int g_TextureWidth = 0;
|
|
static int g_TextureHeight = 0;
|
|
|
|
|
|
|
|
static void* g_VertexBufferHandle = NULL;
|
|
static int g_VertexBufferVertexCount;
|
|
|
|
struct MeshVertex
|
|
{
|
|
float pos[3];
|
|
float normal[3];
|
|
float color[4];
|
|
float uv[2];
|
|
};
|
|
static std::vector<MeshVertex> g_VertexSource;
|
|
|
|
// --------------------------------------------------------------------------
|
|
// UnitySetInterfaces
|
|
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType);
|
|
|
|
static IUnityInterfaces* s_UnityInterfaces = NULL;
|
|
static IUnityGraphics* s_Graphics = NULL;
|
|
static IUnityLog* s_unityLogPtr = nullptr;
|
|
|
|
void UnityLog(const char* msg)
|
|
{
|
|
UNITY_LOG(s_unityLogPtr, msg);
|
|
}
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginLoad(IUnityInterfaces* unityInterfaces)
|
|
{
|
|
s_UnityInterfaces = unityInterfaces;
|
|
s_Graphics = s_UnityInterfaces->Get<IUnityGraphics>();
|
|
s_Graphics->RegisterDeviceEventCallback(OnGraphicsDeviceEvent);
|
|
s_unityLogPtr = s_UnityInterfaces->Get<IUnityLog>();
|
|
UnityLog("UnityPluginLoad");
|
|
#if SUPPORT_VULKAN
|
|
if (s_Graphics->GetRenderer() == kUnityGfxRendererNull)
|
|
{
|
|
extern void RenderAPI_Vulkan_OnPluginLoad(IUnityInterfaces*);
|
|
RenderAPI_Vulkan_OnPluginLoad(unityInterfaces);
|
|
}
|
|
#endif // SUPPORT_VULKAN
|
|
|
|
// Run OnGraphicsDeviceEvent(initialize) manually on plugin load
|
|
OnGraphicsDeviceEvent(kUnityGfxDeviceEventInitialize);
|
|
}
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API UnityPluginUnload()
|
|
{
|
|
s_Graphics->UnregisterDeviceEventCallback(OnGraphicsDeviceEvent);
|
|
}
|
|
|
|
|
|
#if UNITY_WEBGL
|
|
typedef void (UNITY_INTERFACE_API * PluginLoadFunc)(IUnityInterfaces* unityInterfaces);
|
|
typedef void (UNITY_INTERFACE_API * PluginUnloadFunc)();
|
|
|
|
extern "C" void UnityRegisterRenderingPlugin(PluginLoadFunc loadPlugin, PluginUnloadFunc unloadPlugin);
|
|
|
|
extern "C" void UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API RegisterPlugin()
|
|
{
|
|
UnityRegisterRenderingPlugin(UnityPluginLoad, UnityPluginUnload);
|
|
}
|
|
#endif
|
|
|
|
// --------------------------------------------------------------------------
|
|
// GraphicsDeviceEvent
|
|
|
|
|
|
static RenderAPI* s_CurrentAPI = NULL;
|
|
static UnityGfxRenderer s_DeviceType = kUnityGfxRendererNull;
|
|
|
|
static void UNITY_INTERFACE_API OnGraphicsDeviceEvent(UnityGfxDeviceEventType eventType)
|
|
{
|
|
// Create graphics API implementation upon initialization
|
|
if (eventType == kUnityGfxDeviceEventInitialize)
|
|
{
|
|
assert(s_CurrentAPI == NULL);
|
|
s_DeviceType = s_Graphics->GetRenderer();
|
|
s_CurrentAPI = CreateRenderAPI(s_DeviceType);
|
|
}
|
|
|
|
// Let the implementation process the device related events
|
|
if (s_CurrentAPI)
|
|
{
|
|
s_CurrentAPI->ProcessDeviceEvent(eventType, s_UnityInterfaces);
|
|
}
|
|
|
|
// Cleanup graphics API implementation upon shutdown
|
|
if (eventType == kUnityGfxDeviceEventShutdown)
|
|
{
|
|
delete s_CurrentAPI;
|
|
s_CurrentAPI = NULL;
|
|
s_DeviceType = kUnityGfxRendererNull;
|
|
}
|
|
}
|
|
|
|
|
|
// --------------------------------------------------------------------------
|
|
// OnRenderEvent
|
|
// This will be called for GL.IssuePluginEvent script calls; eventID will
|
|
// be the integer passed to IssuePluginEvent. In this example, we just ignore
|
|
// that value.
|
|
|
|
|
|
static void ModifyTexturePixels()
|
|
{
|
|
void* textureHandle = g_TextureHandle;
|
|
int width = g_TextureWidth;
|
|
int height = g_TextureHeight;
|
|
if (!textureHandle)
|
|
return;
|
|
|
|
int textureRowPitch;
|
|
void* textureDataPtr = s_CurrentAPI->BeginModifyTexture(textureHandle, width, height, &textureRowPitch);
|
|
if (!textureDataPtr)
|
|
return;
|
|
|
|
const float t = g_Time * 4.0f;
|
|
|
|
unsigned char* dst = (unsigned char*)textureDataPtr;
|
|
for (int y = 0; y < height; ++y)
|
|
{
|
|
unsigned char* ptr = dst;
|
|
for (int x = 0; x < width; ++x)
|
|
{
|
|
// Simple "plasma effect": several combined sine waves
|
|
int vv = int(
|
|
(127.0f + (127.0f * sinf(x / 7.0f + t))) +
|
|
(127.0f + (127.0f * sinf(y / 5.0f - t))) +
|
|
(127.0f + (127.0f * sinf((x + y) / 6.0f - t))) +
|
|
(127.0f + (127.0f * sinf(sqrtf(float(x*x + y*y)) / 4.0f - t)))
|
|
) / 4;
|
|
|
|
// Write the texture pixel
|
|
ptr[0] = vv;
|
|
ptr[1] = vv;
|
|
ptr[2] = vv;
|
|
ptr[3] = vv;
|
|
|
|
// To next pixel (our pixels are 4 bpp)
|
|
ptr += 4;
|
|
}
|
|
|
|
// To next image row
|
|
dst += textureRowPitch;
|
|
}
|
|
|
|
s_CurrentAPI->EndModifyTexture(textureHandle, width, height, textureRowPitch, textureDataPtr);
|
|
}
|
|
|
|
|
|
static void ModifyVertexBuffer()
|
|
{
|
|
void* bufferHandle = g_VertexBufferHandle;
|
|
int vertexCount = g_VertexBufferVertexCount;
|
|
if (!bufferHandle)
|
|
return;
|
|
|
|
size_t bufferSize;
|
|
void* bufferDataPtr = s_CurrentAPI->BeginModifyVertexBuffer(bufferHandle, &bufferSize);
|
|
if (!bufferDataPtr)
|
|
return;
|
|
int vertexStride = int(bufferSize / vertexCount);
|
|
|
|
// Unity should return us a buffer that is the size of `vertexCount * sizeof(MeshVertex)`
|
|
// If that's not the case then we should quit to avoid unexpected results.
|
|
// This can happen if https://docs.unity3d.com/ScriptReference/Mesh.GetNativeVertexBufferPtr.html returns
|
|
// a pointer to a buffer with an unexpected layout.
|
|
if (static_cast<unsigned int>(vertexStride) != sizeof(MeshVertex))
|
|
return;
|
|
|
|
const float t = g_Time * 3.0f;
|
|
|
|
char* bufferPtr = (char*)bufferDataPtr;
|
|
// modify vertex Y position with several scrolling sine waves,
|
|
// copy the rest of the source data unmodified
|
|
for (int i = 0; i < vertexCount; ++i)
|
|
{
|
|
const MeshVertex& src = g_VertexSource[i];
|
|
MeshVertex& dst = *(MeshVertex*)bufferPtr;
|
|
dst.pos[0] = src.pos[0];
|
|
dst.pos[1] = src.pos[1] + sinf(src.pos[0] * 1.1f + t) * 0.4f + sinf(src.pos[2] * 0.9f - t) * 0.3f;
|
|
dst.pos[2] = src.pos[2];
|
|
dst.normal[0] = src.normal[0];
|
|
dst.normal[1] = src.normal[1];
|
|
dst.normal[2] = src.normal[2];
|
|
dst.uv[0] = src.uv[0];
|
|
dst.uv[1] = src.uv[1];
|
|
bufferPtr += vertexStride;
|
|
}
|
|
|
|
s_CurrentAPI->EndModifyVertexBuffer(bufferHandle);
|
|
}
|
|
|
|
static void drawToPluginTexture()
|
|
{
|
|
s_CurrentAPI->drawToPluginTexture();
|
|
}
|
|
|
|
static void drawToRenderTexture()
|
|
{
|
|
s_CurrentAPI->drawToRenderTexture();
|
|
}
|
|
|
|
enum NativeRenderingEvent
|
|
{
|
|
EnableVRS = 1,
|
|
DisableVRS,
|
|
};
|
|
|
|
static void UNITY_INTERFACE_API OnRenderEventAndData(int eventID, void* data)
|
|
{
|
|
// Unknown / unsupported graphics device type? Do nothing
|
|
if (s_CurrentAPI == NULL)
|
|
return;
|
|
|
|
switch ((NativeRenderingEvent)eventID)
|
|
{
|
|
case NativeRenderingEvent::EnableVRS:
|
|
{
|
|
s_CurrentAPI->enableVRS(*(int*)data);
|
|
break;
|
|
}
|
|
case NativeRenderingEvent::DisableVRS:
|
|
{
|
|
s_CurrentAPI->disableVRS();
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
extern "C" UnityRenderingEventAndData UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API GetRenderEventAndDataFunc()
|
|
{
|
|
return OnRenderEventAndData;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// DX12 plugin specific
|
|
// --------------------------------------------------------------------------
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT void* UNITY_INTERFACE_API GetRenderTexture()
|
|
{
|
|
return s_CurrentAPI->getRenderTexture();
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT void UNITY_INTERFACE_API SetRenderTexture(UnityRenderBuffer rb)
|
|
{
|
|
s_CurrentAPI->setRenderTextureResource(rb);
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT bool UNITY_INTERFACE_API IsSwapChainAvailable()
|
|
{
|
|
return s_CurrentAPI->isSwapChainAvailable();
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT unsigned int UNITY_INTERFACE_API GetPresentFlags()
|
|
{
|
|
return s_CurrentAPI->getPresentFlags();
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT unsigned int UNITY_INTERFACE_API GetSyncInterval()
|
|
{
|
|
return s_CurrentAPI->getSyncInterval();
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT unsigned int UNITY_INTERFACE_API GetBackBufferWidth()
|
|
{
|
|
return s_CurrentAPI->getBackbufferHeight();
|
|
}
|
|
|
|
extern "C" UNITY_INTERFACE_EXPORT unsigned int UNITY_INTERFACE_API GetBackBufferHeight()
|
|
{
|
|
return s_CurrentAPI->getBackbufferWidth();
|
|
}
|