Browse Source

Reworked setup of native-to-managed callbacks. The "target" pointer is no longer a part of the callbacks struct, instead this is now supplied and stored as an opaque "context" pointer along with a pointer to the callbacks struct. These are provided through separate SetCallbacks functions before initializing the UniQuake native plugin. This cleans up several functions and requires less use of global pointers, while also making it easier to see how things fit together and how to add new modules in the future.

readme
Nico de Poel 5 years ago
parent
commit
2a4ec90ff1
  1. 4
      Assets/Scripts/CallbackHandler.cs
  2. 4
      Assets/Scripts/Modules/GameModule.Interop.cs
  3. 4
      Assets/Scripts/Modules/RenderModule.Interop.cs
  4. 4
      Assets/Scripts/Modules/SystemModule.Interop.cs
  5. 19
      Assets/Scripts/UniQuake.Interop.cs
  6. 7
      Assets/Scripts/UniQuake.cs
  7. 31
      engine/UniQuake/game_uniquake.c
  8. 35
      engine/UniQuake/gl_uniquake.c
  9. 61
      engine/UniQuake/sys_uniquake.c
  10. 6
      engine/UniQuake/uniquake.c
  11. 9
      engine/UniQuake/uniquake.h

4
Assets/Scripts/CallbackHandler.cs

@ -8,9 +8,9 @@ public abstract class CallbackHandler<THandler>
private GCHandle selfHandle;
private GCHandle callbacksHandle;
public IntPtr CallbacksPtr => callbacksHandle.AddrOfPinnedObject();
public IntPtr ContextPtr => GCHandle.ToIntPtr(selfHandle);
protected IntPtr TargetPtr => GCHandle.ToIntPtr(selfHandle);
public IntPtr CallbacksPtr => callbacksHandle.AddrOfPinnedObject();
protected CallbackHandler()
{

4
Assets/Scripts/Modules/GameModule.Interop.cs

@ -12,8 +12,6 @@ public partial class GameModule : CallbackHandler<GameModule>
{
var callbacks = new Callbacks
{
target = TargetPtr,
SetEntityModel = CreateCallback<GameSetEntityModelCallback>(Callback_GameSetEntityModel),
SetEntityTransform = CreateCallback<GameSetEntityTransformCallback>(Callback_GameSetEntityTransform),
RemoveEntity = CreateCallback<GameRemoveEntityCallback>(Callback_GameRemoveEntity),
@ -30,8 +28,6 @@ public partial class GameModule : CallbackHandler<GameModule>
[StructLayout(LayoutKind.Sequential, Pack = 0)]
private class Callbacks
{
public IntPtr target;
public IntPtr SetEntityModel;
public IntPtr SetEntityTransform;
public IntPtr RemoveEntity;

4
Assets/Scripts/Modules/RenderModule.Interop.cs

@ -12,8 +12,6 @@ public partial class RenderModule: CallbackHandler<RenderModule>
{
var callbacks = new Callbacks
{
target = TargetPtr,
UploadAliasModel = CreateCallback<UploadAliasModelCallback>(Callback_UploadAliasModel),
UploadBrushModel = CreateCallback<UploadBrushModelCallback>(Callback_UploadBrushModel),
UploadWorldModel = CreateCallback<UploadWorldModelCallback>(Callback_UploadWorldModel),
@ -32,8 +30,6 @@ public partial class RenderModule: CallbackHandler<RenderModule>
[StructLayout(LayoutKind.Sequential, Pack = 0)]
private class Callbacks
{
public IntPtr target;
public IntPtr UploadAliasModel;
public IntPtr UploadBrushModel;
public IntPtr UploadWorldModel;

4
Assets/Scripts/Modules/SystemModule.Interop.cs

@ -8,8 +8,6 @@ public partial class SystemModule: CallbackHandler<SystemModule>
{
var callbacks = new Callbacks
{
target = TargetPtr,
SysPrint = CreateCallback<SysPrintCallback>(Callback_SysPrint),
SysError = CreateCallback<SysErrorCallback>(Callback_SysError),
SysQuit = CreateCallback<SysQuitCallback>(Callback_SysQuit),
@ -34,8 +32,6 @@ public partial class SystemModule: CallbackHandler<SystemModule>
[StructLayout(LayoutKind.Sequential, Pack = 0)]
private class Callbacks
{
public IntPtr target;
public IntPtr SysPrint;
public IntPtr SysError;
public IntPtr SysQuit;

19
Assets/Scripts/UniQuake.Interop.cs

@ -18,7 +18,7 @@ public partial class UniQuake
private IntPtr libraryHandle;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void UniQuake_InitFunc(IntPtr parms, IntPtr sysCalls, IntPtr glCalls, IntPtr gameCalls);
private delegate void UniQuake_InitFunc(IntPtr parms);
private UniQuake_InitFunc UniQuake_Init;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -33,6 +33,12 @@ public partial class UniQuake
private delegate void UniQuake_SetFmodSystemFunc(IntPtr fmodSystem, int playerNumber = 0);
private UniQuake_SetFmodSystemFunc UniQuake_SetFmodSystem;
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void UniQuake_SetCallbacksFunc(IntPtr context, IntPtr callbacks);
private UniQuake_SetCallbacksFunc UniQuake_SetSysCallbacks;
private UniQuake_SetCallbacksFunc UniQuake_SetRenderCallbacks;
private UniQuake_SetCallbacksFunc UniQuake_SetGameCallbacks;
private void LoadLibrary()
{
string dllFile = Path.Combine(Application.dataPath, DllPath);
@ -51,10 +57,13 @@ public partial class UniQuake
throw new DllNotFoundException($"Failed to load UniQuake library from path: {dllFile}, last error = {Marshal.GetLastWin32Error()}");
}
UniQuake_Init = LoadLibraryFunction<UniQuake_InitFunc>("UniQuake_Init");
UniQuake_Update = LoadLibraryFunction<UniQuake_UpdateFunc>("UniQuake_Update");
UniQuake_Shutdown = LoadLibraryFunction<UniQuake_ShutdownFunc>("UniQuake_Shutdown");
UniQuake_SetFmodSystem = LoadLibraryFunction<UniQuake_SetFmodSystemFunc>("UniQuake_SetFmodSystem");
UniQuake_Init = LoadLibraryFunction<UniQuake_InitFunc>(nameof(UniQuake_Init));
UniQuake_Update = LoadLibraryFunction<UniQuake_UpdateFunc>(nameof(UniQuake_Update));
UniQuake_Shutdown = LoadLibraryFunction<UniQuake_ShutdownFunc>(nameof(UniQuake_Shutdown));
UniQuake_SetFmodSystem = LoadLibraryFunction<UniQuake_SetFmodSystemFunc>(nameof(UniQuake_SetFmodSystem));
UniQuake_SetSysCallbacks = LoadLibraryFunction<UniQuake_SetCallbacksFunc>(nameof(UniQuake_SetSysCallbacks));
UniQuake_SetRenderCallbacks = LoadLibraryFunction<UniQuake_SetCallbacksFunc>(nameof(UniQuake_SetRenderCallbacks));
UniQuake_SetGameCallbacks = LoadLibraryFunction<UniQuake_SetCallbacksFunc>(nameof(UniQuake_SetGameCallbacks));
}
private TDelegate LoadLibraryFunction<TDelegate>(string functionName)

7
Assets/Scripts/UniQuake.cs

@ -102,8 +102,11 @@ public partial class UniQuake: MonoBehaviour
try
{
UniQuake_SetFmodSystem(AudioManager.Instance.FmodSystem.handle);
UniQuake_Init(quakeParms.ToNativePtr(),
systemModule.CallbacksPtr, renderModule.CallbacksPtr, gameModule.CallbacksPtr);
UniQuake_SetSysCallbacks(systemModule.ContextPtr, systemModule.CallbacksPtr);
UniQuake_SetRenderCallbacks(renderModule.ContextPtr, renderModule.CallbacksPtr);
UniQuake_SetGameCallbacks(gameModule.ContextPtr, gameModule.CallbacksPtr);
UniQuake_Init(quakeParms.ToNativePtr());
initialized = true;
}

31
engine/UniQuake/game_uniquake.c

@ -4,38 +4,43 @@
typedef struct unity_gamecalls_s
{
void *target;
void(*SetEntityModel)(void *target, int entityNum, const char *modelName);
void(*SetEntityTransform)(void *target, int entityNum, vec3_t origin, vec3_t angles);
void(*RemoveEntity)(void *target, int entityNum);
void(*UpdateEntityAnimation)(void *target, int entityNum, int pose1, int pose2, float blend);
void(*SetEntitySkin)(void *target, int entityNum, int skinNum);
void(*SetEntityModel)(void *context, int entityNum, const char *modelName);
void(*SetEntityTransform)(void *context, int entityNum, vec3_t origin, vec3_t angles);
void(*RemoveEntity)(void *context, int entityNum);
void(*UpdateEntityAnimation)(void *context, int entityNum, int pose1, int pose2, float blend);
void(*SetEntitySkin)(void *context, int entityNum, int skinNum);
} unity_gamecalls_t;
const unity_gamecalls_t *unity_gamecalls;
static void *unity_context;
static const unity_gamecalls_t *unity_gamecalls;
UNIQUAKE_API void UniQuake_SetGameCallbacks(void *context, const unity_gamecalls_t *callbacks)
{
unity_context = context;
unity_gamecalls = callbacks;
}
void UQ_Game_SetEntityModel(int entityNum, const char *modelName)
{
unity_gamecalls->SetEntityModel(unity_gamecalls->target, entityNum, modelName);
unity_gamecalls->SetEntityModel(unity_context, entityNum, modelName);
}
void UQ_Game_SetEntityTransform(int entityNum, vec3_t origin, vec3_t angles)
{
unity_gamecalls->SetEntityTransform(unity_gamecalls->target, entityNum, origin, angles);
unity_gamecalls->SetEntityTransform(unity_context, entityNum, origin, angles);
}
void UQ_Game_RemoveEntity(int entityNum)
{
unity_gamecalls->RemoveEntity(unity_gamecalls->target, entityNum);
unity_gamecalls->RemoveEntity(unity_context, entityNum);
}
void UQ_Game_UpdateEntityAnimation(int entityNum, int pose1, int pose2, float blend)
{
unity_gamecalls->UpdateEntityAnimation(unity_gamecalls->target, entityNum, pose1, pose2, blend);
unity_gamecalls->UpdateEntityAnimation(unity_context, entityNum, pose1, pose2, blend);
}
void UQ_Game_SetEntitySkin(int entityNum, int skinNum)
{
unity_gamecalls->SetEntitySkin(unity_gamecalls->target, entityNum, skinNum);
unity_gamecalls->SetEntitySkin(unity_context, entityNum, skinNum);
}

35
engine/UniQuake/gl_uniquake.c

@ -5,47 +5,52 @@
typedef struct unity_glcalls_s
{
void *target;
int(*UploadAliasModel)(void *target, const char *name, aliashdr_t *aliashdr, aliasframetype_t frametype, maliasframedesc_t *frames, trivertx_t **poseVerts, mtriangle_t *triangles, stvert_t *stVerts);
int(*UploadBrushModel)(void *target, qmodel_t *model);
int(*UploadWorldModel)(void *target, qmodel_t *model);
qboolean(*UploadTexture)(void *target, gltexture_t *texture, unsigned *data, GLuint *texnum);
qboolean(*UploadLightmap)(void *target, int lmap, byte *data);
void(*SetupView)(void *target, vec3_t origin, vec3_t angles, mleaf_t *viewLeaf);
int(*UploadAliasModel)(void *context, const char *name, aliashdr_t *aliashdr, aliasframetype_t frametype, maliasframedesc_t *frames, trivertx_t **poseVerts, mtriangle_t *triangles, stvert_t *stVerts);
int(*UploadBrushModel)(void *context, qmodel_t *model);
int(*UploadWorldModel)(void *context, qmodel_t *model);
qboolean(*UploadTexture)(void *context, gltexture_t *texture, unsigned *data, GLuint *texnum);
qboolean(*UploadLightmap)(void *context, int lmap, byte *data);
void(*SetupView)(void *context, vec3_t origin, vec3_t angles, mleaf_t *viewLeaf);
} unity_glcalls_t;
const unity_glcalls_t *unity_glcalls;
static void *unity_context;
static const unity_glcalls_t *unity_glcalls;
UNIQUAKE_API void UniQuake_SetRenderCallbacks(void *context, const unity_glcalls_t *callbacks)
{
unity_context = context;
unity_glcalls = callbacks;
}
int UQ_GL_UploadAliasModel(qmodel_t *model, aliashdr_t *aliashdr, aliasframetype_t frametype, trivertx_t **poseVerts, mtriangle_t *triangles, stvert_t *stVerts)
{
// C# doesn't really understand this idea of a variable-length embedded array of structs,
// so we pass along the pointer to the first frame struct which allows us to manually marshal the entire array.
return unity_glcalls->UploadAliasModel(unity_glcalls->target, model->name, aliashdr, frametype, &aliashdr->frames[0], poseVerts, triangles, stVerts);
return unity_glcalls->UploadAliasModel(unity_context, model->name, aliashdr, frametype, &aliashdr->frames[0], poseVerts, triangles, stVerts);
}
int UQ_GL_UploadBrushModel(qmodel_t *model)
{
return unity_glcalls->UploadBrushModel(unity_glcalls->target, model);
return unity_glcalls->UploadBrushModel(unity_context, model);
}
int UQ_GL_UploadWorldModel(qmodel_t *model)
{
return unity_glcalls->UploadWorldModel(unity_glcalls->target, model);
return unity_glcalls->UploadWorldModel(unity_context, model);
}
qboolean UQ_GL_UploadTexture(gltexture_t *texture, unsigned *data)
{
// Allow UniQuake to either sync up its internal texture reference number, or assign a new one.
return unity_glcalls->UploadTexture(unity_glcalls->target, texture, data, &texture->texnum);
return unity_glcalls->UploadTexture(unity_context, texture, data, &texture->texnum);
}
qboolean UQ_GL_UploadLightmap(int lmap, byte *data)
{
return unity_glcalls->UploadLightmap(unity_glcalls->target, lmap, data);
return unity_glcalls->UploadLightmap(unity_context, lmap, data);
}
void UQ_GL_SetupView(vec3_t origin, vec3_t angles, mleaf_t *viewLeaf)
{
unity_glcalls->SetupView(unity_glcalls->target, origin, angles, viewLeaf);
unity_glcalls->SetupView(unity_context, origin, angles, viewLeaf);
}

61
engine/UniQuake/sys_uniquake.c

@ -8,24 +8,29 @@ cvar_t sys_throttle = { "sys_throttle", "0.02", CVAR_ARCHIVE };
typedef struct unity_syscalls_s
{
void *target;
void(*SysPrint)(void *target, const char *msg);
void(*SysError)(void *target, const char *msg);
void(*SysQuit)(void *target);
double(*SysDoubleTime)(void *target);
int(*SysFileOpenRead)(void *target, const char *path, int *hndl);
int(*SysFileOpenWrite)(void *target, const char *path);
void(*SysFileClose)(void *target, int handle);
void(*SysFileSeek)(void *target, int handle, int position);
int(*SysFileRead)(void *target, int handle, void *dest, int count);
int(*SysFileWrite)(void *target, int handle, const void *data, int count);
int(*SysFileTime)(void *target, const char *path);
qboolean(*SysMkDir)(void *target, const char *path);
void(*SysPrint)(void *context, const char *msg);
void(*SysError)(void *context, const char *msg);
void(*SysQuit)(void *context);
double(*SysDoubleTime)(void *context);
int(*SysFileOpenRead)(void *context, const char *path, int *hndl);
int(*SysFileOpenWrite)(void *context, const char *path);
void(*SysFileClose)(void *context, int handle);
void(*SysFileSeek)(void *context, int handle, int position);
int(*SysFileRead)(void *context, int handle, void *dest, int count);
int(*SysFileWrite)(void *context, int handle, const void *data, int count);
int(*SysFileTime)(void *context, const char *path);
qboolean(*SysMkDir)(void *context, const char *path);
} unity_syscalls_t;
const unity_syscalls_t *unity_syscalls;
static void *unity_context;
static const unity_syscalls_t *unity_syscalls;
UNIQUAKE_API void UniQuake_SetSysCallbacks(void *context, const unity_syscalls_t *callbacks)
{
unity_context = context;
unity_syscalls = callbacks;
}
void Sys_Error(const char *error, ...)
{
@ -36,7 +41,7 @@ void Sys_Error(const char *error, ...)
q_vsnprintf(text, sizeof(text), error, argptr);
va_end(argptr);
unity_syscalls->SysError(unity_syscalls->target, text);
unity_syscalls->SysError(unity_context, text);
}
void Sys_Printf(const char *fmt, ...)
@ -48,57 +53,57 @@ void Sys_Printf(const char *fmt, ...)
q_vsnprintf(text, sizeof(text), fmt, argptr);
va_end(argptr);
unity_syscalls->SysPrint(unity_syscalls->target, text);
unity_syscalls->SysPrint(unity_context, text);
}
void Sys_Quit(void)
{
unity_syscalls->SysQuit(unity_syscalls->target);
unity_syscalls->SysQuit(unity_context);
}
double Sys_DoubleTime(void)
{
return unity_syscalls->SysDoubleTime(unity_syscalls->target);
return unity_syscalls->SysDoubleTime(unity_context);
}
int Sys_FileOpenRead(const char *path, int *hndl)
{
return unity_syscalls->SysFileOpenRead(unity_syscalls->target, path, hndl);
return unity_syscalls->SysFileOpenRead(unity_context, path, hndl);
}
int Sys_FileOpenWrite(const char *path)
{
return unity_syscalls->SysFileOpenWrite(unity_syscalls->target, path);
return unity_syscalls->SysFileOpenWrite(unity_context, path);
}
void Sys_FileClose(int handle)
{
unity_syscalls->SysFileClose(unity_syscalls->target, handle);
unity_syscalls->SysFileClose(unity_context, handle);
}
void Sys_FileSeek(int handle, int position)
{
unity_syscalls->SysFileSeek(unity_syscalls->target, handle, position);
unity_syscalls->SysFileSeek(unity_context, handle, position);
}
int Sys_FileRead(int handle, void *dest, int count)
{
return unity_syscalls->SysFileRead(unity_syscalls->target, handle, dest, count);
return unity_syscalls->SysFileRead(unity_context, handle, dest, count);
}
int Sys_FileWrite(int handle, const void *data, int count)
{
return unity_syscalls->SysFileWrite(unity_syscalls->target, handle, data, count);
return unity_syscalls->SysFileWrite(unity_context, handle, data, count);
}
int Sys_FileTime(const char *path)
{
return unity_syscalls->SysFileTime(unity_syscalls->target, path);
return unity_syscalls->SysFileTime(unity_context, path);
}
void Sys_mkdir(const char *path)
{
if (!unity_syscalls->SysMkDir(unity_syscalls->target, path))
if (!unity_syscalls->SysMkDir(unity_context, path))
Sys_Error("Unable to create directory %s", path);
}

6
engine/UniQuake/uniquake.c

@ -14,14 +14,10 @@ UNIQUAKE_API void UniQuake_SetFmodSystem(FMOD_SYSTEM *system, int playernumber)
}
#endif
UNIQUAKE_API void UniQuake_Init(quakeparms_t *parms, const unity_syscalls_t *syscalls, const unity_glcalls_t *glcalls, const unity_gamecalls_t *gamecalls)
UNIQUAKE_API void UniQuake_Init(quakeparms_t *parms)
{
host_parms = parms;
unity_syscalls = syscalls;
unity_glcalls = glcalls;
unity_gamecalls = gamecalls;
COM_InitArgv(parms->argc, parms->argv);
parms->argc = com_argc;
parms->argv = com_argv;

9
engine/UniQuake/uniquake.h

@ -8,12 +8,3 @@
#else
#define UNIQUAKE_API __declspec(dllimport)
#endif
typedef struct unity_syscalls_s unity_syscalls_t;
extern const unity_syscalls_t *unity_syscalls;
typedef struct unity_glcalls_s unity_glcalls_t;
extern const unity_glcalls_t *unity_glcalls;
typedef struct unity_gamecalls_s unity_gamecalls_t;
extern const unity_gamecalls_t *unity_gamecalls;
Loading…
Cancel
Save