Browse Source

Implemented uploading of skin texture data to Unity, and linking loaded alias models to their primary skin texture

console
Nico de Poel 5 years ago
parent
commit
e70d363998
  1. 6
      Assets/Scripts/Data/QConstants.cs
  2. 3
      Assets/Scripts/Data/QConstants.cs.meta
  3. 27
      Assets/Scripts/Data/QModel.cs
  4. 57
      Assets/Scripts/Data/QTexture.cs
  5. 3
      Assets/Scripts/Data/QTexture.cs.meta
  6. 2
      Assets/Scripts/Modules/AliasModel.cs
  7. 24
      Assets/Scripts/Modules/RenderModule.Interop.cs
  8. 48
      Assets/Scripts/Modules/RenderModule.cs
  9. 2
      engine/Quake/gl_texmgr.c
  10. 2
      engine/Quake/gl_texmgr.h
  11. 7
      engine/UniQuake/gl_uniquake.c

6
Assets/Scripts/Data/QConstants.cs

@ -0,0 +1,6 @@
public static class QConstants
{
public const int MaxQPath = 64; // Should correspond to MAX_QPATH
public const int MaxMapHulls = 4; // Should correspond to MAX_MAP_HULLS
public const int MaxSkins = 32; // Should correspond to MAX_SKINS
}

3
Assets/Scripts/Data/QConstants.cs.meta

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d507e6306af34f16916b95a6b6427762
timeCreated: 1619100138

27
Assets/Scripts/Data/QModel.cs

@ -1,6 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
/// <summary> /// <summary>
@ -9,10 +7,7 @@ using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, Pack = 0, CharSet = CharSet.Ansi)] [StructLayout(LayoutKind.Sequential, Pack = 0, CharSet = CharSet.Ansi)]
public class QModel 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;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = QConstants.MaxQPath)] public string name;
public uint pathId; public uint pathId;
public bool needLoad; public bool needLoad;
@ -67,7 +62,7 @@ public class QModel
public int numMarkSurfaces; public int numMarkSurfaces;
public IntPtr markSurfaces; // Array of msurface_t pointers public IntPtr markSurfaces; // Array of msurface_t pointers
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MaxMapHulls)] public QHull[] hulls;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = QConstants.MaxMapHulls)] public QHull[] hulls;
public int numTextures; public int numTextures;
public IntPtr textures; // Array of texture_t pointers public IntPtr textures; // Array of texture_t pointers
@ -79,6 +74,7 @@ public class QModel
public bool visWarn; public bool visWarn;
public int bspVersion; public int bspVersion;
// VBO data from QuakeSpasm; unused by UniQuake
public uint meshvbo; public uint meshvbo;
public uint meshIndexesVbo; public uint meshIndexesVbo;
public int vboIndexOfs; public int vboIndexOfs;
@ -94,8 +90,6 @@ public class QModel
[StructLayout(LayoutKind.Sequential, Pack = 0)] [StructLayout(LayoutKind.Sequential, Pack = 0)]
public class QAliasHeader public class QAliasHeader
{ {
private const int MaxSkins = 32; // Should correspond to MAX_SKINS
public int ident; public int ident;
public int version; public int version;
public QVec3 scale; public QVec3 scale;
@ -112,15 +106,20 @@ public class QAliasHeader
public int flags; public int flags;
public float size; public float size;
// VBO data from QuakeSpasm; unused by UniQuake
public int numVertsVbo;
public IntPtr meshDesc;
public int numIndexes;
public IntPtr indexes;
public IntPtr vertexes;
public int numPoses; public int numPoses;
public int poseVerts; public int poseVerts;
public int poseData; public int poseData;
public int commands; 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;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = QConstants.MaxSkins)] public IntPtr[] glTextures;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = QConstants.MaxSkins)] public IntPtr[] fbTextures;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = QConstants.MaxSkins)] public int[] texels;
// Actually variable sized, but we receive an additional pointer to the first element so we can manually marshal the entire array // 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; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] public QAliasFrameDesc[] frames;

57
Assets/Scripts/Data/QTexture.cs

@ -0,0 +1,57 @@
using System;
using System.Runtime.InteropServices;
/// <summary>
/// Managed equivalent of gltexture_t
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 0, CharSet = CharSet.Ansi)]
public class QGLTexture
{
public uint texNum;
public IntPtr next;
public IntPtr owner;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string name;
public uint width;
public uint height;
public QTexPrefs flags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = QConstants.MaxQPath)] public string sourceFile;
public UIntPtr sourceOffset;
public QTexSourceFormat sourceFormat;
public uint sourceWidth;
public uint sourceHeight;
public ushort sourceCrc;
public char shirt;
public char pants;
public int visFrame;
}
/// <summary>
/// Managed equivalent of srcformat
/// </summary>
public enum QTexSourceFormat
{
Indexed,
Lightmap,
Rgba,
}
/// <summary>
/// Managed equivalent of TEXPRF_ defines
/// </summary>
[Flags]
public enum QTexPrefs: uint
{
None = 0x0000,
Mipmap = 0x0001,
Linear = 0x0002,
Nearest = 0x0004,
Alpha = 0x0008,
Pad = 0x0010,
Persist = 0x0020,
Overwrite = 0x0040,
NoPicMip = 0x0080,
FullBright = 0x0100,
NoBright = 0x0200,
ConChars = 0x0400,
WarpImage = 0x0800,
}

3
Assets/Scripts/Data/QTexture.cs.meta

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 08aab07be00d450fb56bcfa0c24a1b99
timeCreated: 1619095043

2
Assets/Scripts/Modules/AliasModel.cs

@ -248,7 +248,7 @@ public class AliasModel
for (int i = 0; i < numVerts; ++i) for (int i = 0; i < numVerts; ++i)
{ {
uvs[i] = Vector2.Scale(new Vector2(stVerts[i].s, skinHeight - stVerts[i].t), scale);
uvs[i] = Vector2.Scale(new Vector2(stVerts[i].s, stVerts[i].t), scale);
} }
} }

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

@ -15,6 +15,7 @@ public partial class RenderModule: CallbackHandler<RenderModule>
UploadAliasModel = CreateCallback<UploadAliasModelCallback>(Callback_UploadAliasModel), UploadAliasModel = CreateCallback<UploadAliasModelCallback>(Callback_UploadAliasModel),
UploadBrushModel = CreateCallback<UploadBrushModelCallback>(Callback_UploadBrushModel), UploadBrushModel = CreateCallback<UploadBrushModelCallback>(Callback_UploadBrushModel),
UploadTexture = CreateCallback<UploadTextureCallback>(Callback_UploadTexture),
}; };
RegisterCallbacks(callbacks); RegisterCallbacks(callbacks);
@ -30,6 +31,7 @@ public partial class RenderModule: CallbackHandler<RenderModule>
public IntPtr UploadAliasModel; public IntPtr UploadAliasModel;
public IntPtr UploadBrushModel; public IntPtr UploadBrushModel;
public IntPtr UploadTexture;
} }
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
@ -66,10 +68,19 @@ public partial class RenderModule: CallbackHandler<RenderModule>
poseVertices[i] = poseVerts[i].ToStructArray<QTriVertex>(header.numVerts); 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].ToStructArray<QGLTexture>(4);
fbTextures[i] = header.fbTextures[i].ToStructArray<QGLTexture>(4);
}
return GetSelf(target).UploadAliasModel( return GetSelf(target).UploadAliasModel(
name, header, frameType, poseVertices, name, header, frameType, poseVertices,
triangles.ToStructArray<QTriangle>(header.numTriangles), triangles.ToStructArray<QTriangle>(header.numTriangles),
stVerts.ToStructArray<QSTVert>(header.numVerts));
stVerts.ToStructArray<QSTVert>(header.numVerts),
glTextures, fbTextures);
} }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
@ -80,4 +91,15 @@ public partial class RenderModule: CallbackHandler<RenderModule>
{ {
return GetSelf(target).UploadBrushModel(model); return GetSelf(target).UploadBrushModel(model);
} }
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate bool UploadTextureCallback(IntPtr target, QGLTexture texture, IntPtr data, ref uint texNum);
[MonoPInvokeCallback(typeof(UploadTextureCallback))]
private static bool Callback_UploadTexture(IntPtr target, QGLTexture texture, IntPtr data, ref uint texNum)
{
byte[] dataBytes = new byte[texture.width * texture.height * 4]; // 32 bits per pixel
Marshal.Copy(data, dataBytes, 0, dataBytes.Length);
return GetSelf(target).UploadTexture(texture, dataBytes, ref texNum);
}
} }

48
Assets/Scripts/Modules/RenderModule.cs

@ -6,7 +6,8 @@ public partial class RenderModule
{ {
private readonly UniQuake uq; private readonly UniQuake uq;
private readonly List<AliasModel> aliasModels = new List<AliasModel>(); private readonly List<AliasModel> aliasModels = new List<AliasModel>();
private readonly Dictionary<uint, Texture2D> textures = new Dictionary<uint, Texture2D>();
public RenderModule(UniQuake uniQuake) public RenderModule(UniQuake uniQuake)
{ {
uq = uniQuake; uq = uniQuake;
@ -23,12 +24,20 @@ public partial class RenderModule
} }
aliasModels.Clear(); aliasModels.Clear();
foreach (var texture in textures.Values)
{
// Object.Destroy(texture); // TODO: reactivate when done testing in editor
}
textures.Clear();
} }
private float xPos = -8f; private float xPos = -8f;
private int UploadAliasModel(string name, QAliasHeader header, QAliasFrameType frameType, private int UploadAliasModel(string name, QAliasHeader header, QAliasFrameType frameType,
QTriVertex[][] poseVertices, QTriangle[] triangles, QSTVert[] stVertices)
QTriVertex[][] poseVertices, QTriangle[] triangles, QSTVert[] stVertices,
QGLTexture[][] glTextures, QGLTexture[][] fbTextures)
{ {
var sb = new System.Text.StringBuilder(); var sb = new System.Text.StringBuilder();
foreach (var frame in header.frames) foreach (var frame in header.frames)
@ -48,10 +57,17 @@ public partial class RenderModule
aliasModel.Animate(0, out Mesh mesh, out float blendWeight); aliasModel.Animate(0, out Mesh mesh, out float blendWeight);
var material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
uint texNum = glTextures[0][0].texNum;
if (texNum > 0 && textures.ContainsKey(texNum))
{
material.mainTexture = textures[texNum];
}
if (header.numPoses > 1) if (header.numPoses > 1)
{ {
var mr = go.AddComponent<SkinnedMeshRenderer>(); var mr = go.AddComponent<SkinnedMeshRenderer>();
mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
mr.material = material;
mr.sharedMesh = mesh; mr.sharedMesh = mesh;
mr.shadowCastingMode = ShadowCastingMode.Off; mr.shadowCastingMode = ShadowCastingMode.Off;
mr.receiveShadows = false; mr.receiveShadows = false;
@ -66,7 +82,7 @@ public partial class RenderModule
var mf = go.AddComponent<MeshFilter>(); var mf = go.AddComponent<MeshFilter>();
mf.sharedMesh = mesh; mf.sharedMesh = mesh;
var mr = go.AddComponent<MeshRenderer>(); var mr = go.AddComponent<MeshRenderer>();
mr.material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
mr.material = material;
mr.shadowCastingMode = ShadowCastingMode.Off; mr.shadowCastingMode = ShadowCastingMode.Off;
mr.receiveShadows = false; mr.receiveShadows = false;
mr.lightProbeUsage = LightProbeUsage.Off; mr.lightProbeUsage = LightProbeUsage.Off;
@ -85,4 +101,28 @@ public partial class RenderModule
Debug.Log($"Brush model '{model.name}' with {model.numLeafs} leafs, {model.numVertices} vertices, {model.numSurfaces} surfaces"); Debug.Log($"Brush model '{model.name}' with {model.numLeafs} leafs, {model.numVertices} vertices, {model.numSurfaces} surfaces");
return 1; return 1;
} }
private uint nextTexNum = 0x10001;
private bool UploadTexture(QGLTexture texture, byte[] data, ref uint texNum)
{
Debug.Log($"Texture '{texture.name}' with dimensions {texture.width}x{texture.height}, data size = {data.Length} bytes");
if (texNum == 0)
{
// Assign a new texture number
while (textures.ContainsKey(nextTexNum))
++nextTexNum;
texNum = nextTexNum++;
}
var tex = new Texture2D((int)texture.width, (int)texture.height, TextureFormat.RGBA32, texture.flags.HasFlag(QTexPrefs.Mipmap));
tex.name = texture.name;
tex.SetPixelData(data, 0);
tex.Apply();
textures[texNum] = tex;
return true;
}
} }

2
engine/Quake/gl_texmgr.c

@ -1071,6 +1071,8 @@ static void TexMgr_LoadImage32 (gltexture_t *glt, unsigned *data)
// set filter modes // set filter modes
TexMgr_SetFilterModes (glt); TexMgr_SetFilterModes (glt);
UQ_GL_UploadTexture(glt, data);
} }
/* /*

2
engine/Quake/gl_texmgr.h

@ -106,5 +106,7 @@ void GL_EnableMultitexture (void); //selects texture unit 1
void GL_Bind (gltexture_t *texture); void GL_Bind (gltexture_t *texture);
void GL_ClearBindings (void); void GL_ClearBindings (void);
extern qboolean UQ_GL_UploadTexture(gltexture_t *texture, unsigned *data);
#endif /* _GL_TEXMAN_H */ #endif /* _GL_TEXMAN_H */

7
engine/UniQuake/gl_uniquake.c

@ -9,6 +9,7 @@ typedef struct unity_glcalls_s
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(*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(*UploadBrushModel)(void *target, qmodel_t *model);
qboolean(*UploadTexture)(void *target, gltexture_t *texture, unsigned *data, GLuint *texnum);
} unity_glcalls_t; } unity_glcalls_t;
const unity_glcalls_t *unity_glcalls; const unity_glcalls_t *unity_glcalls;
@ -24,3 +25,9 @@ int UQ_GL_UploadBrushModel(qmodel_t *model)
{ {
return unity_glcalls->UploadBrushModel(unity_glcalls->target, model); return unity_glcalls->UploadBrushModel(unity_glcalls->target, 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);
}
Loading…
Cancel
Save