From a886f3d9932ab21cce10d86c643f0d55e46ccc50 Mon Sep 17 00:00:00 2001 From: Nico de Poel Date: Mon, 5 Jul 2021 15:37:52 +0200 Subject: [PATCH] First steps in reorganizing the project, so that assets and game state are managed separately from the interop modules. This will allow for a clearer picture of where gameplay-related interactions should take place, and how entities and such should be linked to their associated assets. --- Assets/Scripts/Game.meta | 8 ++ Assets/Scripts/Game/GameAssets.cs | 88 +++++++++++++++++++ Assets/Scripts/Game/GameAssets.cs.meta | 11 +++ Assets/Scripts/Game/GameState.cs | 13 +++ Assets/Scripts/Game/GameState.cs.meta | 11 +++ Assets/Scripts/Modules/GameModule.Interop.cs | 27 ++++++ .../Modules/GameModule.Interop.cs.meta | 11 +++ Assets/Scripts/Modules/GameModule.cs | 14 +++ Assets/Scripts/Modules/GameModule.cs.meta | 11 +++ .../Scripts/Modules/RenderModule.Interop.cs | 15 ++++ Assets/Scripts/Modules/RenderModule.cs | 83 ++++++----------- Assets/Scripts/UniQuake.cs | 14 ++- engine/Quake/gl_model.h | 1 + engine/Quake/gl_rmisc.c | 2 +- engine/UniQuake/gl_uniquake.c | 6 ++ 15 files changed, 255 insertions(+), 60 deletions(-) create mode 100644 Assets/Scripts/Game.meta create mode 100644 Assets/Scripts/Game/GameAssets.cs create mode 100644 Assets/Scripts/Game/GameAssets.cs.meta create mode 100644 Assets/Scripts/Game/GameState.cs create mode 100644 Assets/Scripts/Game/GameState.cs.meta create mode 100644 Assets/Scripts/Modules/GameModule.Interop.cs create mode 100644 Assets/Scripts/Modules/GameModule.Interop.cs.meta create mode 100644 Assets/Scripts/Modules/GameModule.cs create mode 100644 Assets/Scripts/Modules/GameModule.cs.meta diff --git a/Assets/Scripts/Game.meta b/Assets/Scripts/Game.meta new file mode 100644 index 0000000..d7d5240 --- /dev/null +++ b/Assets/Scripts/Game.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f9fc42dc891bc547be3172cab9c8ade +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Game/GameAssets.cs b/Assets/Scripts/Game/GameAssets.cs new file mode 100644 index 0000000..f36294d --- /dev/null +++ b/Assets/Scripts/Game/GameAssets.cs @@ -0,0 +1,88 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class GameAssets +{ + private readonly UniQuake uq; + + private readonly Dictionary textures = new Dictionary(); + + private BrushModel worldModel; + private readonly List brushModels = new List(); + private readonly List aliasModels = new List(); + + private uint nextTexNum = 0x10001; + + public GameAssets(UniQuake uniQuake) + { + uq = uniQuake; + } + + public uint SetTexture(uint texNum, Texture2D texture) + { + if (texNum == 0) + { + // Assign a new texture number + while (textures.ContainsKey(nextTexNum)) + ++nextTexNum; + + texNum = nextTexNum++; + } + + textures[texNum] = texture; + return texNum; + } + + public bool TryGetTexture(uint texNum, out Texture2D texture) + { + texture = null; + return texNum > 0 && textures.TryGetValue(texNum, out texture); + } + + public void AddAliasModel(AliasModel aliasModel) + { + aliasModels.Add(aliasModel); + } + + public void AddBrushModel(BrushModel brushModel) + { + brushModels.Add(brushModel); + } + + public void SetWorldModel(BrushModel brushModel) + { + worldModel?.Dispose(); // TODO: also need to clean up any GameObjects made from this + worldModel = brushModel; + } + + public void Destroy() + { + if (worldModel != null) + { + worldModel.Dispose(); + worldModel = null; + } + + foreach (var brushModel in brushModels) + { + // brushModel.Dispose(); // TODO: reactivate when done testing in editor + } + + brushModels.Clear(); + + foreach (var aliasModel in aliasModels) + { + // aliasModel.Dispose(); // TODO: reactivate when done testing in editor + } + + aliasModels.Clear(); + + foreach (var texture in textures.Values) + { + // Object.Destroy(texture); // TODO: reactivate when done testing in editor + } + + textures.Clear(); + } +} diff --git a/Assets/Scripts/Game/GameAssets.cs.meta b/Assets/Scripts/Game/GameAssets.cs.meta new file mode 100644 index 0000000..ad9bf00 --- /dev/null +++ b/Assets/Scripts/Game/GameAssets.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3821114b8377e3a458eebb55f1363672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Game/GameState.cs b/Assets/Scripts/Game/GameState.cs new file mode 100644 index 0000000..7cf71ad --- /dev/null +++ b/Assets/Scripts/Game/GameState.cs @@ -0,0 +1,13 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class GameState +{ + private readonly UniQuake uq; + + public GameState(UniQuake uniQuake) + { + uq = uniQuake; + } +} diff --git a/Assets/Scripts/Game/GameState.cs.meta b/Assets/Scripts/Game/GameState.cs.meta new file mode 100644 index 0000000..6a8b0d1 --- /dev/null +++ b/Assets/Scripts/Game/GameState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27dd2ba6514f88c4bb767eb1765546de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Modules/GameModule.Interop.cs b/Assets/Scripts/Modules/GameModule.Interop.cs new file mode 100644 index 0000000..ce5ff45 --- /dev/null +++ b/Assets/Scripts/Modules/GameModule.Interop.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using UnityEngine; + +public partial class GameModule : CallbackHandler +{ + private void BuildCallbacks() + { + var callbacks = new Callbacks + { + target = TargetPtr, + }; + + RegisterCallbacks(callbacks); + } + + /// + /// This matches unity_gamecalls_t from mod_uniquake.c in native code. + /// + [StructLayout(LayoutKind.Sequential, Pack = 0)] + private class Callbacks + { + public IntPtr target; + } +} diff --git a/Assets/Scripts/Modules/GameModule.Interop.cs.meta b/Assets/Scripts/Modules/GameModule.Interop.cs.meta new file mode 100644 index 0000000..36a95df --- /dev/null +++ b/Assets/Scripts/Modules/GameModule.Interop.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8d9b402c1d6a3d4a8634a85bece7d77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Modules/GameModule.cs b/Assets/Scripts/Modules/GameModule.cs new file mode 100644 index 0000000..120870f --- /dev/null +++ b/Assets/Scripts/Modules/GameModule.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public partial class GameModule +{ + private readonly UniQuake uq; + + public GameModule(UniQuake uniQuake) + { + uq = uniQuake; + BuildCallbacks(); + } +} diff --git a/Assets/Scripts/Modules/GameModule.cs.meta b/Assets/Scripts/Modules/GameModule.cs.meta new file mode 100644 index 0000000..fba091c --- /dev/null +++ b/Assets/Scripts/Modules/GameModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 204138db5cbbd944ebc9bd1c5adfadcc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Modules/RenderModule.Interop.cs b/Assets/Scripts/Modules/RenderModule.Interop.cs index c7de286..a02deb5 100644 --- a/Assets/Scripts/Modules/RenderModule.Interop.cs +++ b/Assets/Scripts/Modules/RenderModule.Interop.cs @@ -15,6 +15,8 @@ public partial class RenderModule: CallbackHandler UploadAliasModel = CreateCallback(Callback_UploadAliasModel), UploadBrushModel = CreateCallback(Callback_UploadBrushModel), + UploadWorldModel = CreateCallback(Callback_UploadWorldModel), + UploadTexture = CreateCallback(Callback_UploadTexture), SetupView = CreateCallback(Callback_SetupView), }; @@ -32,6 +34,7 @@ public partial class RenderModule: CallbackHandler public IntPtr UploadAliasModel; public IntPtr UploadBrushModel; + public IntPtr UploadWorldModel; public IntPtr UploadTexture; public IntPtr SetupView; } @@ -96,6 +99,18 @@ public partial class RenderModule: CallbackHandler return GetSelf(target).UploadBrushModel(model); } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate int UploadWorldModelCallback(IntPtr target, QModel model); + + [MonoPInvokeCallback(typeof(UploadBrushModelCallback))] + private static int Callback_UploadWorldModel(IntPtr target, QModel model) + { + if (model == null || model.type != QModelType.Brush) + return -1; + + return GetSelf(target).UploadWorldModel(model); + } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate bool UploadTextureCallback(IntPtr target, QGLTexture texture, IntPtr data, ref uint texNum); diff --git a/Assets/Scripts/Modules/RenderModule.cs b/Assets/Scripts/Modules/RenderModule.cs index 0f39b42..9806760 100644 --- a/Assets/Scripts/Modules/RenderModule.cs +++ b/Assets/Scripts/Modules/RenderModule.cs @@ -5,12 +5,7 @@ using UnityEngine.Rendering; public partial class RenderModule { private readonly UniQuake uq; - private readonly List brushModels = new List(); - private readonly List aliasModels = new List(); - private readonly Dictionary textures = new Dictionary(); - private BrushModel worldModel; - public RenderModule(UniQuake uniQuake) { uq = uniQuake; @@ -20,33 +15,6 @@ public partial class RenderModule globalZPos -= 256f; } - public override void Destroy() - { - base.Destroy(); - - foreach (var brushModel in brushModels) - { - // brushModel.Dispose(); // TODO: reactivate when done testing in editor - } - - brushModels.Clear(); - worldModel = null; - - foreach (var aliasModel in aliasModels) - { - // aliasModel.Dispose(); // TODO: reactivate when done testing in editor - } - - aliasModels.Clear(); - - foreach (var texture in textures.Values) - { - // Object.Destroy(texture); // TODO: reactivate when done testing in editor - } - - textures.Clear(); - } - private float xPos = -2048f; private float zPos = 0f; private static float globalZPos = 0f; @@ -66,7 +34,8 @@ public partial class RenderModule string modelName = System.IO.Path.GetFileNameWithoutExtension(name); AliasModel aliasModel = new AliasModel(modelName, frameType); aliasModel.ImportMeshData(header, poseVertices, triangles, stVertices); - aliasModels.Add(aliasModel); + + uq.GameAssets.AddAliasModel(aliasModel); var go = new GameObject(modelName); go.transform.SetPositionAndRotation(new Vector3(xPos, 0, zPos), Quaternion.identity); @@ -75,18 +44,18 @@ public partial class RenderModule var material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); uint texNum = glTextures[0][0].texNum; - if (texNum > 0 && textures.ContainsKey(texNum)) + if (uq.GameAssets.TryGetTexture(texNum, out var texture)) { - material.mainTexture = textures[texNum]; + material.mainTexture = texture; } if (fbTextures != null && fbTextures[0] != null && fbTextures[0][0] != null) { var fbTexNum = fbTextures[0][0].texNum; - if (fbTexNum > 0 && textures.ContainsKey(fbTexNum)) + if (uq.GameAssets.TryGetTexture(fbTexNum, out var fbTexture)) { material.EnableKeyword("_EMISSION"); - material.SetTexture("_EmissionMap", textures[fbTexNum]); + material.SetTexture("_EmissionMap", fbTexture); material.SetColor("_EmissionColor", Color.white); } } @@ -119,15 +88,29 @@ public partial class RenderModule } xPos += 128f; - return aliasModels.Count; + return 1; } - + private int UploadBrushModel(QModel model) { Debug.Log($"Brush model '{model.name}' with {model.numVertices} vertices, {model.numEdges} edges, {model.numSurfaces} surfaces"); var brushModel = new BrushModel(model.name); brushModel.ImportMeshData(model); + + uq.GameAssets.AddBrushModel(brushModel); + + return 1; + } + + private int UploadWorldModel(QModel model) + { + Debug.Log($"World model '{model.name}' with {model.numVertices} vertices, {model.numEdges} edges, {model.numSurfaces} surfaces"); + + var brushModel = new BrushModel(model.name); + brushModel.ImportMeshData(model); + + uq.GameAssets.SetWorldModel(brushModel); // DEBUG var worldGO = new GameObject(model.name); @@ -147,9 +130,9 @@ public partial class RenderModule var material = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); uint texNum = surfaceMesh.Texture.TextureNum; - if (texNum > 0 && textures.ContainsKey(texNum)) + if (uq.GameAssets.TryGetTexture(texNum, out var texture)) { - material.mainTexture = textures[texNum]; + material.mainTexture = texture; } var mr = meshGO.AddComponent(); @@ -161,34 +144,22 @@ public partial class RenderModule } } - brushModels.Add(brushModel); - return brushModels.Count; + 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 (texture.width == 0 || texture.height == 0) return false; - - 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; + + texNum = uq.GameAssets.SetTexture(texNum, tex); return true; } diff --git a/Assets/Scripts/UniQuake.cs b/Assets/Scripts/UniQuake.cs index 3206c22..7c0ae6d 100644 --- a/Assets/Scripts/UniQuake.cs +++ b/Assets/Scripts/UniQuake.cs @@ -12,6 +12,7 @@ public partial class UniQuake: MonoBehaviour private QuakeParms quakeParms; private SystemModule systemModule; private RenderModule renderModule; + private GameModule gameModule; private bool initialized = false; private double startTime; @@ -29,6 +30,9 @@ public partial class UniQuake: MonoBehaviour /// Time since startup for this particular instance of Quake /// public double CurrentTime => Time.realtimeSinceStartupAsDouble - startTime; + + public GameAssets GameAssets { get; private set; } + public GameState GameState { get; private set; } private Action logHandler; private StringBuilder logBuffer = new StringBuilder(); @@ -39,15 +43,19 @@ public partial class UniQuake: MonoBehaviour systemModule = new SystemModule(this); renderModule = new RenderModule(this); + gameModule = new GameModule(this); + GameAssets = new GameAssets(this); + GameState = new GameState(this); + LoadLibrary(); List arguments = new List { "", - "-window", - "-width", "1440", - "-height", "1080", + //"-fullscreen", "-width", "1920", "-height", "1080", + "-window", "-width", "1440", "-height", "1080", + //"-window", "-width", "2240", "-height", "1260", }; switch (BaseGame) diff --git a/engine/Quake/gl_model.h b/engine/Quake/gl_model.h index bcc76d9..ab620b0 100644 --- a/engine/Quake/gl_model.h +++ b/engine/Quake/gl_model.h @@ -518,5 +518,6 @@ void Mod_SetExtraFlags (qmodel_t *mod); int UQ_GL_UploadAliasModel(qmodel_t *model, aliashdr_t *aliashdr, aliasframetype_t frametype, trivertx_t **poseVerts, mtriangle_t *triangles, stvert_t *stVerts); int UQ_GL_UploadBrushModel(qmodel_t *model); +int UQ_GL_UploadWorldModel(qmodel_t *model); #endif // __MODEL__ diff --git a/engine/Quake/gl_rmisc.c b/engine/Quake/gl_rmisc.c index 54a49f4..b1d751a 100644 --- a/engine/Quake/gl_rmisc.c +++ b/engine/Quake/gl_rmisc.c @@ -404,7 +404,7 @@ void R_NewMap (void) //ericw -- no longer load alias models into a VBO here, it's done in Mod_LoadAliasModel #endif // USE_OPENGL - UQ_GL_UploadBrushModel(cl.worldmodel); + UQ_GL_UploadWorldModel(cl.worldmodel); r_framecount = 0; //johnfitz -- paranoid? r_visframecount = 0; //johnfitz -- paranoid? diff --git a/engine/UniQuake/gl_uniquake.c b/engine/UniQuake/gl_uniquake.c index f535095..41e8215 100644 --- a/engine/UniQuake/gl_uniquake.c +++ b/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(*UploadBrushModel)(void *target, qmodel_t *model); + int(*UploadWorldModel)(void *target, qmodel_t *model); qboolean(*UploadTexture)(void *target, gltexture_t *texture, unsigned *data, GLuint *texnum); void(*SetupView)(void *target, vec3_t origin, vec3_t angles, mleaf_t *viewLeaf); } unity_glcalls_t; @@ -27,6 +28,11 @@ int UQ_GL_UploadBrushModel(qmodel_t *model) return unity_glcalls->UploadBrushModel(unity_glcalls->target, model); } +int UQ_GL_UploadWorldModel(qmodel_t *model) +{ + return unity_glcalls->UploadWorldModel(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.