You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
170 lines
6.7 KiB
170 lines
6.7 KiB
using System;
|
|
using System.Runtime.InteropServices;
|
|
using AOT;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
|
|
public partial class RenderModule: CallbackHandler<RenderModule>
|
|
{
|
|
private const int MaxAliasFrames = 256; // Should match MAXALIASFRAMES
|
|
|
|
private void BuildCallbacks()
|
|
{
|
|
var callbacks = new Callbacks
|
|
{
|
|
UploadAliasModel = CreateCallback<UploadAliasModelCallback>(Callback_UploadAliasModel),
|
|
UploadBrushModel = CreateCallback<UploadBrushModelCallback>(Callback_UploadBrushModel),
|
|
UploadWorldModel = CreateCallback<UploadWorldModelCallback>(Callback_UploadWorldModel),
|
|
|
|
UploadTexture = CreateCallback<UploadTextureCallback>(Callback_UploadTexture),
|
|
UploadLightmap = CreateCallback<UploadLightmapCallback>(Callback_UploadLightmap),
|
|
SetupView = CreateCallback<SetupViewCallback>(Callback_SetupView),
|
|
};
|
|
|
|
RegisterCallbacks(callbacks);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This matches unity_modcalls_t from mod_uniquake.c in native code.
|
|
/// </summary>
|
|
[StructLayout(LayoutKind.Sequential, Pack = 0)]
|
|
private class Callbacks
|
|
{
|
|
public IntPtr UploadAliasModel;
|
|
public IntPtr UploadBrushModel;
|
|
public IntPtr UploadWorldModel;
|
|
public IntPtr UploadTexture;
|
|
public IntPtr UploadLightmap;
|
|
public IntPtr SetupView;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
|
|
private delegate int UploadAliasModelCallback(IntPtr context, [MarshalAs(UnmanagedType.LPStr)] string name,
|
|
QAliasHeader header, QAliasFrameType frameType, IntPtr frames,
|
|
[MarshalAs(UnmanagedType.LPArray, SizeConst = MaxAliasFrames)] IntPtr[] poseVerts, IntPtr triangles, IntPtr stVerts);
|
|
|
|
[MonoPInvokeCallback(typeof(UploadAliasModelCallback))]
|
|
private static int Callback_UploadAliasModel(IntPtr context,
|
|
string name, QAliasHeader header, QAliasFrameType frameType, IntPtr frames,
|
|
IntPtr[] poseVerts, IntPtr triangles, IntPtr stVerts)
|
|
{
|
|
if (header == null)
|
|
{
|
|
Debug.LogWarning($"Uploading invalid alias model, name = {name}");
|
|
return 0;
|
|
}
|
|
|
|
Profiler.BeginSample("UploadAliasModel");
|
|
|
|
if (header.numFrames > MaxAliasFrames)
|
|
header.numFrames = MaxAliasFrames;
|
|
|
|
if (frames != IntPtr.Zero)
|
|
header.frames = frames.ToStructArray<QAliasFrameDesc>(header.numFrames);
|
|
|
|
header.numPoses = 0;
|
|
for (int i = 0; i < header.numFrames; ++i)
|
|
{
|
|
header.numPoses += header.frames[i].numPoses;
|
|
}
|
|
|
|
var poseVertices = new QTriVertex[header.numPoses][];
|
|
for (int i = 0; i < header.numPoses; ++i)
|
|
{
|
|
poseVertices[i] = poseVerts[i].ToStructArray<QTriVertex>(header.numVerts);
|
|
}
|
|
|
|
var glTextures = new QGLTexture[QConstants.MaxSkins][];
|
|
var fbTextures = new QGLTexture[QConstants.MaxSkins][];
|
|
for (int i = 0; i < QConstants.MaxSkins; ++i)
|
|
{
|
|
glTextures[i] = header.glTextures[i * 4].ToStructArray<QGLTexture>(4);
|
|
fbTextures[i] = header.fbTextures[i * 4].ToStructArray<QGLTexture>(4);
|
|
}
|
|
|
|
int result = GetSelf(context).UploadAliasModel(
|
|
name, header, frameType, poseVertices,
|
|
triangles.ToStructArray<QTriangle>(header.numTriangles),
|
|
stVerts.ToStructArray<QSTVert>(header.numVerts),
|
|
glTextures, fbTextures);
|
|
|
|
Profiler.EndSample();
|
|
return result;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate int UploadBrushModelCallback(IntPtr context, QModel model);
|
|
|
|
[MonoPInvokeCallback(typeof(UploadBrushModelCallback))]
|
|
private static int Callback_UploadBrushModel(IntPtr context, QModel model)
|
|
{
|
|
if (model == null || model.type != QModelType.Brush)
|
|
return -1;
|
|
|
|
Profiler.BeginSample("UploadBrushModel");
|
|
int result = GetSelf(context).UploadBrushModel(model);
|
|
Profiler.EndSample();
|
|
return result;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate int UploadWorldModelCallback(IntPtr context, QModel model);
|
|
|
|
[MonoPInvokeCallback(typeof(UploadBrushModelCallback))]
|
|
private static int Callback_UploadWorldModel(IntPtr context, QModel model)
|
|
{
|
|
if (model == null || model.type != QModelType.Brush)
|
|
return -1;
|
|
|
|
Profiler.BeginSample("UploadWorldModel");
|
|
int result = GetSelf(context).UploadWorldModel(model);
|
|
Profiler.EndSample();
|
|
return result;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate bool UploadTextureCallback(IntPtr context, QGLTexture texture, IntPtr data, ref uint texNum);
|
|
|
|
[MonoPInvokeCallback(typeof(UploadTextureCallback))]
|
|
private static bool Callback_UploadTexture(IntPtr context, QGLTexture texture, IntPtr data, ref uint texNum)
|
|
{
|
|
Profiler.BeginSample("UploadTexture");
|
|
|
|
byte[] dataBytes = new byte[texture.width * texture.height * 4]; // 32 bits per pixel
|
|
Marshal.Copy(data, dataBytes, 0, dataBytes.Length);
|
|
bool result = GetSelf(context).UploadTexture(texture, dataBytes, ref texNum);
|
|
|
|
Profiler.EndSample();
|
|
return result;
|
|
}
|
|
|
|
private readonly byte[] lightmapBytes = new byte[QConstants.LightmapBlockWidth * QConstants.LightmapBlockHeight * 4]; // 32 bits per pixel
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate bool UploadLightmapCallback(IntPtr context, int lmap, IntPtr data);
|
|
|
|
[MonoPInvokeCallback(typeof(UploadLightmapCallback))]
|
|
private static bool Callback_UploadLightmap(IntPtr context, int lmap, IntPtr data)
|
|
{
|
|
Profiler.BeginSample("UploadLightmap");
|
|
|
|
// TODO: this is a fairly pointless additional data copy step; we could probably make this faster by wrapping the IntPtr directly into a NativeArray
|
|
var self = GetSelf(context);
|
|
Marshal.Copy(data, self.lightmapBytes, 0, self.lightmapBytes.Length);
|
|
bool result = self.UploadLightmap(lmap, QConstants.LightmapBlockWidth, QConstants.LightmapBlockHeight, self.lightmapBytes);
|
|
|
|
Profiler.EndSample();
|
|
return result;
|
|
}
|
|
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate void SetupViewCallback(IntPtr context, ref QVec3 origin, ref QVec3 angles, ref QLeaf viewLeaf);
|
|
|
|
[MonoPInvokeCallback(typeof(SetupViewCallback))]
|
|
private static void Callback_SetupView(IntPtr context, ref QVec3 origin, ref QVec3 angles, ref QLeaf viewLeaf)
|
|
{
|
|
Profiler.BeginSample("SetupView");
|
|
GetSelf(context).SetupView(origin, angles, viewLeaf);
|
|
Profiler.EndSample();
|
|
}
|
|
}
|