Browse Source

First implementation of dynamically updated lightmap textures. These are uploaded from the Quake engine to Unity on map load, and whenever a lightmap texture changes.

It has been tested and found (mostly) working by manipulating the UVs on surface meshes, applying the lightmap as main texture, and using an unlit shader. This is not part of the commit.
readme
Nico de Poel 5 years ago
parent
commit
c9a3d0430c
  1. 41
      Assets/Scripts/Game/GameAssets.cs
  2. 3
      Assets/Scripts/Game/GameState.cs
  3. 14
      Assets/Scripts/Modules/RenderModule.Interop.cs
  4. 9
      Assets/Scripts/Modules/RenderModule.cs
  5. 1
      engine/Quake/gl_texmgr.h
  6. 4
      engine/Quake/r_brush.c
  7. 6
      engine/UniQuake/gl_uniquake.c

41
Assets/Scripts/Game/GameAssets.cs

@ -7,6 +7,7 @@ public class GameAssets
private readonly UniQuake uq; private readonly UniQuake uq;
private readonly Dictionary<uint, Texture2D> textures = new Dictionary<uint, Texture2D>(); private readonly Dictionary<uint, Texture2D> textures = new Dictionary<uint, Texture2D>();
private readonly Dictionary<int, Texture2D> lightmaps = new Dictionary<int, Texture2D>();
private BrushModel worldModel; private BrushModel worldModel;
private readonly List<BrushModel> brushModels = new List<BrushModel>(); private readonly List<BrushModel> brushModels = new List<BrushModel>();
@ -46,6 +47,39 @@ public class GameAssets
return texNum > 0 && textures.TryGetValue(texNum, out texture); 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) public void AddAliasModel(AliasModel aliasModel)
{ {
aliasModels.Add(aliasModel); aliasModels.Add(aliasModel);
@ -126,6 +160,13 @@ public class GameAssets
aliasModels.Clear(); aliasModels.Clear();
foreach (var lightmap in lightmaps.Values)
{
Object.Destroy(lightmap);
}
lightmaps.Clear();
foreach (var texture in textures.Values) foreach (var texture in textures.Values)
{ {
Object.Destroy(texture); Object.Destroy(texture);

3
Assets/Scripts/Game/GameState.cs

@ -57,8 +57,9 @@ public class GameState
{ {
uint fbNum = surfaceMesh.FullBrightNum; uint fbNum = surfaceMesh.FullBrightNum;
uq.GameAssets.TryGetTexture(fbNum, out var fullBright); 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);
} }
} }

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

@ -18,6 +18,7 @@ public partial class RenderModule: CallbackHandler<RenderModule>
UploadWorldModel = CreateCallback<UploadWorldModelCallback>(Callback_UploadWorldModel), UploadWorldModel = CreateCallback<UploadWorldModelCallback>(Callback_UploadWorldModel),
UploadTexture = CreateCallback<UploadTextureCallback>(Callback_UploadTexture), UploadTexture = CreateCallback<UploadTextureCallback>(Callback_UploadTexture),
UploadLightmap = CreateCallback<UploadLightmapCallback>(Callback_UploadLightmap),
SetupView = CreateCallback<SetupViewCallback>(Callback_SetupView), SetupView = CreateCallback<SetupViewCallback>(Callback_SetupView),
}; };
@ -36,6 +37,7 @@ public partial class RenderModule: CallbackHandler<RenderModule>
public IntPtr UploadBrushModel; public IntPtr UploadBrushModel;
public IntPtr UploadWorldModel; public IntPtr UploadWorldModel;
public IntPtr UploadTexture; public IntPtr UploadTexture;
public IntPtr UploadLightmap;
public IntPtr SetupView; public IntPtr SetupView;
} }
@ -123,6 +125,18 @@ public partial class RenderModule: CallbackHandler<RenderModule>
return GetSelf(target).UploadTexture(texture, dataBytes, ref texNum); 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)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void SetupViewCallback(IntPtr target, ref QVec3 origin, ref QVec3 angles, ref QLeaf viewLeaf); private delegate void SetupViewCallback(IntPtr target, ref QVec3 origin, ref QVec3 angles, ref QLeaf viewLeaf);

9
Assets/Scripts/Modules/RenderModule.cs

@ -67,6 +67,15 @@ public partial class RenderModule
texNum = uq.GameAssets.SetTexture(texNum, tex); texNum = uq.GameAssets.SetTexture(texNum, tex);
return true; 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) private void SetupView(QVec3 origin, QVec3 angles, QLeaf viewLeaf)
{ {

1
engine/Quake/gl_texmgr.h

@ -107,6 +107,7 @@ void GL_Bind (gltexture_t *texture);
void GL_ClearBindings (void); void GL_ClearBindings (void);
extern qboolean UQ_GL_UploadTexture(gltexture_t *texture, unsigned *data); 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 */ #endif /* _GL_TEXMAN_H */

4
engine/Quake/r_brush.c

@ -940,6 +940,8 @@ void GL_BuildLightmaps (void)
lm->texture = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, lm->texture = TexMgr_LoadImage (cl.worldmodel, name, LMBLOCK_WIDTH, LMBLOCK_HEIGHT,
SRC_LIGHTMAP, lm->data, "", (src_offset_t)lm->data, TEXPREF_LINEAR | TEXPREF_NOPICMIP); SRC_LIGHTMAP, lm->data, "", (src_offset_t)lm->data, TEXPREF_LINEAR | TEXPREF_NOPICMIP);
//johnfitz //johnfitz
UQ_GL_UploadLightmap(i, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, lm->data);
} }
//johnfitz -- warn about exceeding old limits //johnfitz -- warn about exceeding old limits
@ -1270,6 +1272,8 @@ static void R_UploadLightmap(int lmap)
lm->rectchange.h = 0; lm->rectchange.h = 0;
lm->rectchange.w = 0; lm->rectchange.w = 0;
UQ_GL_UploadLightmap(lmap, LMBLOCK_WIDTH, LMBLOCK_HEIGHT, lm->data);
rs_dynamiclightmaps++; rs_dynamiclightmaps++;
} }

6
engine/UniQuake/gl_uniquake.c

@ -11,6 +11,7 @@ typedef struct unity_glcalls_s
int(*UploadBrushModel)(void *target, qmodel_t *model); int(*UploadBrushModel)(void *target, qmodel_t *model);
int(*UploadWorldModel)(void *target, qmodel_t *model); int(*UploadWorldModel)(void *target, qmodel_t *model);
qboolean(*UploadTexture)(void *target, gltexture_t *texture, unsigned *data, GLuint *texnum); 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); void(*SetupView)(void *target, vec3_t origin, vec3_t angles, mleaf_t *viewLeaf);
} unity_glcalls_t; } 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); 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) void UQ_GL_SetupView(vec3_t origin, vec3_t angles, mleaf_t *viewLeaf)
{ {
unity_glcalls->SetupView(unity_glcalls->target, origin, angles, viewLeaf); unity_glcalls->SetupView(unity_glcalls->target, origin, angles, viewLeaf);

Loading…
Cancel
Save