Browse Source
First test to upload model data (brush models and alias models) from Quake to Unity
console
First test to upload model data (brush models and alias models) from Quake to Unity
console
17 changed files with 338 additions and 3 deletions
-
21Assets/Scripts/DataDefs/QExtensions.cs
-
3Assets/Scripts/DataDefs/QExtensions.cs.meta
-
22Assets/Scripts/DataDefs/QMath.cs
-
3Assets/Scripts/DataDefs/QMath.cs.meta
-
174Assets/Scripts/DataDefs/QModel.cs
-
11Assets/Scripts/DataDefs/QModel.cs.meta
-
58Assets/Scripts/ModCalls.cs
-
3Assets/Scripts/ModCalls.cs.meta
-
7Assets/Scripts/UniQuake.cs
-
2engine/code/gl_mesh.c
-
2engine/code/gl_model.c
-
2engine/code/gl_model.h
-
23engine/projects/uniquake/mod_uniquake.c
-
3engine/projects/uniquake/uniquake.c
-
3engine/projects/uniquake/uniquake.h
-
1engine/projects/uniquake/uniquake.vcxproj
-
3engine/projects/uniquake/uniquake.vcxproj.filters
@ -0,0 +1,21 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
public static class QExtensions |
|||
{ |
|||
public static TStruct[] ToStructArray<TStruct>(this IntPtr ptr, int count) |
|||
{ |
|||
if (ptr == IntPtr.Zero) |
|||
return null; |
|||
|
|||
TStruct[] result = new TStruct[count]; |
|||
int size = Marshal.SizeOf<TStruct>(); |
|||
IntPtr current = ptr; |
|||
for (int i = 0; i < count; ++i) |
|||
{ |
|||
result[i] = Marshal.PtrToStructure<TStruct>(current); |
|||
current = new IntPtr(current.ToInt64() + size); |
|||
} |
|||
return result; |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
fileFormatVersion: 2 |
|||
guid: c414049936614c2ab8169a12cf45f430 |
|||
timeCreated: 1617358962 |
|||
@ -0,0 +1,22 @@ |
|||
using System; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of vec3_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
public struct QVec3 |
|||
{ |
|||
public float x; |
|||
public float y; |
|||
public float z; |
|||
} |
|||
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
public struct QVec4i |
|||
{ |
|||
public int x; |
|||
public int y; |
|||
public int z; |
|||
public int w; |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 23d0952cd4454f4cbd94d4c4d1ae2667 |
|||
timeCreated: 1617282271 |
|||
@ -0,0 +1,174 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of model_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0, CharSet = CharSet.Ansi)] |
|||
public class QModel |
|||
{ |
|||
private const int MaxPath = 64; // Should correspond to MAX_QPATH
|
|||
private const int MaxMapHulls = 4; // Should correspond to MAX_MAP_HULLS
|
|||
|
|||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)] public string name; |
|||
public bool needLoad; |
|||
|
|||
public QModelType type; |
|||
public int numFrames; |
|||
public QSyncType syncType; |
|||
|
|||
public int flags; |
|||
|
|||
// Volume occupied by the model graphics
|
|||
public QVec3 mins, maxs; |
|||
public float radius; |
|||
|
|||
// Solid volume for clipping
|
|||
public bool clipBox; |
|||
public QVec3 clipMins, clipMaxs; |
|||
|
|||
// Brush model
|
|||
public int firstModelSurface, numModelSurfaces; |
|||
|
|||
public int numSubModels; |
|||
public IntPtr subModels; // Array of dmodel_t
|
|||
|
|||
public int numPlanes; |
|||
public IntPtr planes; // Array of mplane_t
|
|||
|
|||
public int numLeafs; |
|||
public IntPtr leafs; // Array of mleaf_t
|
|||
|
|||
public int numVertices; |
|||
public IntPtr vertices; // Array of mvertex_t
|
|||
|
|||
public int numEdges; |
|||
public IntPtr edges; // Array of medge_t
|
|||
|
|||
public int numNodes; |
|||
public IntPtr nodes; // Array of mnode_t
|
|||
|
|||
public int numTexInfo; |
|||
public IntPtr texInfo; // Array of mtexinfo_t
|
|||
|
|||
public int numSurfaces; |
|||
public IntPtr surfaces; // Array of msurface_t
|
|||
|
|||
public int numSurfEdges; |
|||
public IntPtr surfEdges; // Array of int
|
|||
|
|||
public int numClipNodes; |
|||
public IntPtr clipNodes; // Array of dclipnode_t
|
|||
|
|||
public int numMarkSurfaces; |
|||
public IntPtr markSurfaces; // Array of msurface_t pointers
|
|||
|
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxMapHulls)] public QHull[] hulls; |
|||
|
|||
public int numTextures; |
|||
public IntPtr textures; // Array of texture_t pointers
|
|||
|
|||
public IntPtr visData; // Array of bytes
|
|||
public IntPtr lightData; // Array of bytes
|
|||
[MarshalAs(UnmanagedType.LPStr)] public string entities; |
|||
|
|||
public IntPtr userCache; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of aliashdr_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
public class QAliasHeader |
|||
{ |
|||
private const int MaxSkins = 32; // Should correspond to MAX_SKINS
|
|||
|
|||
public int ident; |
|||
public int version; |
|||
public QVec3 scale; |
|||
public QVec3 scaleOrigin; |
|||
public float boundingRadius; |
|||
public QVec3 eyePosition; |
|||
public int numSkins; |
|||
public int skinWidth; |
|||
public int skinHeight; |
|||
public int numVerts; |
|||
public int numTriangles; |
|||
public int numFrames; |
|||
public QSyncType syncType; |
|||
public int flags; |
|||
public float size; |
|||
|
|||
public int numPoses; |
|||
public int poseVerts; |
|||
public int poseData; |
|||
public int commands; |
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSkins)] public QVec4i[] glTextureNum; |
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSkins)] public int[] texels; |
|||
|
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSkins)] public bool[] skinLuma; |
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxSkins)] public bool[] skinLuma8bit; |
|||
|
|||
// Actually variable sized, but we receive an additional pointer to the first element so we can manually marshal the entire array
|
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public QAliasFrameDesc[] frames; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of modtype_t
|
|||
/// </summary>
|
|||
public enum QModelType |
|||
{ |
|||
Brush, |
|||
Sprite, |
|||
Alias, |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of synctype_t
|
|||
/// </summary>
|
|||
public enum QSyncType |
|||
{ |
|||
Sync = 0, |
|||
Rand |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of hull_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
public struct QHull |
|||
{ |
|||
public IntPtr clipNodes; // Array of dclipnode_t
|
|||
public IntPtr planes; // Array of mplane_t
|
|||
public int firstClipNode; |
|||
public int lastClipNode; |
|||
public QVec3 clipMins; |
|||
public QVec3 clipMaxs; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of maliasframedesc_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0, CharSet = CharSet.Ansi)] |
|||
public struct QAliasFrameDesc |
|||
{ |
|||
public int firstPose; |
|||
public int numPoses; |
|||
public float interval; |
|||
public QTriVertex bboxMin; |
|||
public QTriVertex bboxMax; |
|||
public int frame; |
|||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string name; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Managed equivalent of trivertx_t
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
public struct QTriVertex |
|||
{ |
|||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public byte[] v; |
|||
public byte lightNormalIndex; |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
fileFormatVersion: 2 |
|||
guid: 5c427bd710e259c40813a869b8d12150 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|||
@ -0,0 +1,58 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Runtime.InteropServices; |
|||
using AOT; |
|||
using UnityEngine; |
|||
|
|||
public class ModCalls : CallbackHandler<ModCalls> |
|||
{ |
|||
private readonly UniQuake uq; |
|||
|
|||
public ModCalls(UniQuake uniQuake) |
|||
{ |
|||
uq = uniQuake; |
|||
|
|||
var callbacks = new Callbacks |
|||
{ |
|||
target = SelfPtr, |
|||
|
|||
ModUploadModel = CreateCallback<ModUploadModelCallback>(Callback_ModUploadModel), |
|||
}; |
|||
|
|||
RegisterCallbacks(callbacks); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This matches struct unity_syscalls_s from uniquake.h in native code.
|
|||
/// </summary>
|
|||
[StructLayout(LayoutKind.Sequential, Pack = 0)] |
|||
private class Callbacks |
|||
{ |
|||
public IntPtr target; |
|||
|
|||
public IntPtr ModUploadModel; |
|||
} |
|||
|
|||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] |
|||
private delegate void ModUploadModelCallback(IntPtr target, QModel model, QAliasHeader header, IntPtr frames); |
|||
|
|||
[MonoPInvokeCallback(typeof(ModUploadModelCallback))] |
|||
private static void Callback_ModUploadModel(IntPtr target, QModel model, QAliasHeader header, IntPtr frames) |
|||
{ |
|||
if (header != null) |
|||
header.frames = frames.ToStructArray<QAliasFrameDesc>(header.numFrames); |
|||
|
|||
GetSelf(target).UploadModel(model, header); |
|||
} |
|||
|
|||
private void UploadModel(QModel model, QAliasHeader header) |
|||
{ |
|||
Debug.Log($"Model '{model?.name}' of type {model?.type}, num frames = {header?.numFrames}"); |
|||
if (header?.frames != null) |
|||
{ |
|||
string str = string.Join(", ", header.frames.Select(f => f.name)); |
|||
Debug.Log($"Frame list: {str}"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
fileFormatVersion: 2 |
|||
guid: aa8562de402f45e896cda0a84a21342c |
|||
timeCreated: 1617282485 |
|||
@ -0,0 +1,23 @@ |
|||
#include "uniquake.h" |
|||
|
|||
#include "../../code/quakedef.h" |
|||
#include "../../code/gl_model.h" |
|||
|
|||
typedef struct unity_modcalls_s |
|||
{ |
|||
void *target; |
|||
|
|||
void(*ModUploadModel)(void *target, model_t *mdl, aliashdr_t *aliashdr, maliasframedesc_t *frames); |
|||
} unity_modcalls_t; |
|||
|
|||
const unity_modcalls_t *unity_modcalls; |
|||
|
|||
void Mod_UploadModel(model_t *mdl, aliashdr_t *aliashdr) |
|||
{ |
|||
// C# doesn't really understand this idea of a variable-length embedded array of structs, |
|||
// so we pass along the pointer to the first element which allows us to manually marshal the entire array. |
|||
if (aliashdr) |
|||
unity_modcalls->ModUploadModel(unity_modcalls->target, mdl, aliashdr, &aliashdr->frames[0]); |
|||
else |
|||
unity_modcalls->ModUploadModel(unity_modcalls->target, mdl, aliashdr, NULL); |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue