diff --git a/Assets/Scripts/Game/GameAssets.cs b/Assets/Scripts/Game/GameAssets.cs index d43523e..c82e983 100644 --- a/Assets/Scripts/Game/GameAssets.cs +++ b/Assets/Scripts/Game/GameAssets.cs @@ -7,6 +7,7 @@ public class GameAssets private readonly UniQuake uq; private readonly Dictionary textures = new Dictionary(); + private readonly Dictionary lightmaps = new Dictionary(); private BrushModel worldModel; private readonly List brushModels = new List(); @@ -46,6 +47,39 @@ public class GameAssets return texNum > 0 && textures.TryGetValue(texNum, out texture); } + public bool TryGetTexture(string texName, out Texture2D texture) + { + foreach (var tex in textures.Values) + { + if (tex.name == texName) + { + texture = tex; + return true; + } + } + + texture = null; + return false; + } + + public void UploadLightmap(int lightmapNum, int width, int height, byte[] data) + { + if (!lightmaps.TryGetValue(lightmapNum, out var lightmap)) + { + lightmap = new Texture2D(width, height, TextureFormat.RGBA32, true) { name = $"Lightmap_{lightmapNum}" }; + lightmaps.Add(lightmapNum, lightmap); + } + + lightmap.SetPixelData(data, 0); + lightmap.Apply(); + } + + public bool TryGetLightmap(int lightmapNum, out Texture2D lightmap) + { + lightmap = null; + return lightmapNum >= 0 && lightmaps.TryGetValue(lightmapNum, out lightmap); + } + public void AddAliasModel(AliasModel aliasModel) { aliasModels.Add(aliasModel); @@ -126,6 +160,13 @@ public class GameAssets aliasModels.Clear(); + foreach (var lightmap in lightmaps.Values) + { + Object.Destroy(lightmap); + } + + lightmaps.Clear(); + foreach (var texture in textures.Values) { Object.Destroy(texture); diff --git a/Assets/Scripts/Game/GameState.cs b/Assets/Scripts/Game/GameState.cs index 1795981..64225e4 100644 --- a/Assets/Scripts/Game/GameState.cs +++ b/Assets/Scripts/Game/GameState.cs @@ -57,8 +57,9 @@ public class GameState { uint fbNum = surfaceMesh.FullBrightNum; uq.GameAssets.TryGetTexture(fbNum, out var fullBright); + uq.GameAssets.TryGetLightmap(surfaceMesh.Lightmap, out var lightmap); - uq.CurrentStyle.SetWorldTextures(mr.material, texture, fullBright, null); + uq.CurrentStyle.SetWorldTextures(mr.material, texture, fullBright, lightmap); } } diff --git a/Assets/Scripts/Modules/RenderModule.Interop.cs b/Assets/Scripts/Modules/RenderModule.Interop.cs index 2af570a..cc5b9ca 100644 --- a/Assets/Scripts/Modules/RenderModule.Interop.cs +++ b/Assets/Scripts/Modules/RenderModule.Interop.cs @@ -18,6 +18,7 @@ public partial class RenderModule: CallbackHandler UploadWorldModel = CreateCallback(Callback_UploadWorldModel), UploadTexture = CreateCallback(Callback_UploadTexture), + UploadLightmap = CreateCallback(Callback_UploadLightmap), SetupView = CreateCallback(Callback_SetupView), }; @@ -36,6 +37,7 @@ public partial class RenderModule: CallbackHandler public IntPtr UploadBrushModel; public IntPtr UploadWorldModel; public IntPtr UploadTexture; + public IntPtr UploadLightmap; public IntPtr SetupView; } @@ -123,6 +125,18 @@ public partial class RenderModule: CallbackHandler return GetSelf(target).UploadTexture(texture, dataBytes, ref texNum); } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate bool UploadLightmapCallback(IntPtr target, int lmap, int width, int height, IntPtr data); + + [MonoPInvokeCallback(typeof(UploadLightmapCallback))] + private static bool Callback_UploadLightmap(IntPtr target, int lmap, int width, int height, IntPtr data) + { + // TODO: this is a fairly pointless additional data copy step; we could probably make this faster by wrapping the IntPtr directly into a NativeArray + byte[] dataBytes = new byte[width * height * 4]; // 32 bits per pixel (RGBA) + Marshal.Copy(data, dataBytes, 0, dataBytes.Length); + return GetSelf(target).UploadLightmap(lmap, width, height, dataBytes); + } + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void SetupViewCallback(IntPtr target, ref QVec3 origin, ref QVec3 angles, ref QLeaf viewLeaf); diff --git a/Assets/Scripts/Modules/RenderModule.cs b/Assets/Scripts/Modules/RenderModule.cs index da350b9..bf75e35 100644 --- a/Assets/Scripts/Modules/RenderModule.cs +++ b/Assets/Scripts/Modules/RenderModule.cs @@ -67,6 +67,15 @@ public partial class RenderModule texNum = uq.GameAssets.SetTexture(texNum, tex); return true; } + + private bool UploadLightmap(int lightmapNum, int width, int height, byte[] data) + { + if (width == 0 || height == 0) + return false; + + uq.GameAssets.UploadLightmap(lightmapNum, width, height, data); + return true; + } private void SetupView(QVec3 origin, QVec3 angles, QLeaf viewLeaf) { diff --git a/engine/Quake/gl_texmgr.h b/engine/Quake/gl_texmgr.h index b39b09c..d982b3e 100644 --- a/engine/Quake/gl_texmgr.h +++ b/engine/Quake/gl_texmgr.h @@ -107,6 +107,7 @@ void GL_Bind (gltexture_t *texture); void GL_ClearBindings (void); extern qboolean UQ_GL_UploadTexture(gltexture_t *texture, unsigned *data); +extern qboolean UQ_GL_UploadLightmap(int lmap, int width, int height, byte *data); #endif /* _GL_TEXMAN_H */ diff --git a/engine/Quake/r_brush.c b/engine/Quake/r_brush.c index 796ae4c..2ca839d 100644 --- a/engine/Quake/r_brush.c +++ b/engine/Quake/r_brush.c @@ -940,6 +940,8 @@ void GL_BuildLightmaps (void) lm->texture = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, SRC_LIGHTMAP, lm->data, "", (src_offset_t)lm->data, TEXPREF_LINEAR | TEXPREF_NOPICMIP); //johnfitz + + UQ_GL_UploadLightmap(i, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, lm->data); } //johnfitz -- warn about exceeding old limits @@ -1270,6 +1272,8 @@ static void R_UploadLightmap(int lmap) lm->rectchange.h = 0; lm->rectchange.w = 0; + UQ_GL_UploadLightmap(lmap, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, lm->data); + rs_dynamiclightmaps++; } diff --git a/engine/UniQuake/gl_uniquake.c b/engine/UniQuake/gl_uniquake.c index 41e8215..3ac445c 100644 --- a/engine/UniQuake/gl_uniquake.c +++ b/engine/UniQuake/gl_uniquake.c @@ -11,6 +11,7 @@ typedef struct unity_glcalls_s 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, int width, int height, byte *data); void(*SetupView)(void *target, vec3_t origin, vec3_t angles, mleaf_t *viewLeaf); } unity_glcalls_t; @@ -39,6 +40,11 @@ qboolean UQ_GL_UploadTexture(gltexture_t *texture, unsigned *data) return unity_glcalls->UploadTexture(unity_glcalls->target, texture, data, &texture->texnum); } +qboolean UQ_GL_UploadLightmap(int lmap, int width, int height, byte *data) +{ + return unity_glcalls->UploadLightmap(unity_glcalls->target, lmap, width, height, data); +} + void UQ_GL_SetupView(vec3_t origin, vec3_t angles, mleaf_t *viewLeaf) { unity_glcalls->SetupView(unity_glcalls->target, origin, angles, viewLeaf);