diff --git a/Assets/Scripts/Game/Entity.cs b/Assets/Scripts/Game/Entity.cs index 3b3d06e..f1c60dd 100644 --- a/Assets/Scripts/Game/Entity.cs +++ b/Assets/Scripts/Game/Entity.cs @@ -151,7 +151,7 @@ public class Entity private void AssignMeshRenderer() { - material = visualStyle.CreateEntityMaterial(); + material = visualStyle.CreateEntityMaterial(true); if (aliasModel.IsAnimated) { diff --git a/Assets/Scripts/Game/GameState.cs b/Assets/Scripts/Game/GameState.cs index 64225e4..7baea81 100644 --- a/Assets/Scripts/Game/GameState.cs +++ b/Assets/Scripts/Game/GameState.cs @@ -31,11 +31,11 @@ public class GameState // The first sub-model contains all of the static geometry var subModel = worldModel.GetSubModel(0); - var subModelGO = CreateBrushGameObject(subModel); + var subModelGO = CreateWorldBrushObject(subModel); subModelGO.transform.SetParent(worldGameObject.transform); } - private GameObject CreateBrushGameObject(BrushModel.SubModel subModel) + private GameObject CreateWorldBrushObject(BrushModel.SubModel subModel) { var subModelGO = new GameObject(subModel.Name) { layer = (int)uq.GameLayer }; @@ -44,13 +44,12 @@ public class GameState var meshGO = new GameObject(surfaceMesh.Mesh.name) { layer = (int)uq.GameLayer }; meshGO.transform.SetParent(subModelGO.transform); - var mf = meshGO.AddComponent(); - var mr = meshGO.AddComponent(); - mf.sharedMesh = surfaceMesh.Mesh; - - // TODO FIXME This is wrong for brush model entities - uq.CurrentStyle.SetupWorldRenderer(mr); - mr.material = uq.CurrentStyle.CreateWorldMaterial(surfaceMesh.Flags); // TODO FIXME this currently leaks Materials + var meshFilter = meshGO.AddComponent(); + meshFilter.sharedMesh = surfaceMesh.Mesh; + + var meshRenderer = meshGO.AddComponent(); + uq.CurrentStyle.SetupWorldRenderer(meshRenderer); + meshRenderer.material = uq.CurrentStyle.CreateWorldMaterial(surfaceMesh.Flags); // TODO FIXME this currently leaks Materials uint texNum = surfaceMesh.TextureNum; if (uq.GameAssets.TryGetTexture(texNum, out var texture)) @@ -59,7 +58,36 @@ public class GameState uq.GameAssets.TryGetTexture(fbNum, out var fullBright); uq.GameAssets.TryGetLightmap(surfaceMesh.Lightmap, out var lightmap); - uq.CurrentStyle.SetWorldTextures(mr.material, texture, fullBright, lightmap); + uq.CurrentStyle.SetWorldTextures(meshRenderer.material, texture, fullBright, lightmap); + } + } + + return subModelGO; + } + + private GameObject CreateEntityBrushObject(BrushModel.SubModel subModel) + { + var subModelGO = new GameObject(subModel.Name) { layer = (int)uq.GameLayer }; + + foreach (var surfaceMesh in subModel.SurfaceMeshes) + { + var meshGO = new GameObject(surfaceMesh.Mesh.name) { layer = (int)uq.GameLayer }; + meshGO.transform.SetParent(subModelGO.transform); + + var meshFilter = meshGO.AddComponent(); + meshFilter.sharedMesh = surfaceMesh.Mesh; + + var meshRenderer = meshGO.AddComponent(); + uq.CurrentStyle.SetupEntityRenderer(meshRenderer); + meshRenderer.material = uq.CurrentStyle.CreateEntityMaterial(false); // TODO FIXME this currently leaks Materials + + uint texNum = surfaceMesh.TextureNum; + if (uq.GameAssets.TryGetTexture(texNum, out var texture)) + { + uint fbNum = surfaceMesh.FullBrightNum; + uq.GameAssets.TryGetTexture(fbNum, out var fullBright); + + uq.CurrentStyle.SetEntityTextures(meshRenderer.material, texture, fullBright); } } @@ -112,7 +140,7 @@ public class GameState var brushModelGO = new GameObject(brushModel.Name) { layer = (int)Layers.Game1 }; for (int i = 0; i < brushModel.SubModelCount; ++i) { - var subModelGO = CreateBrushGameObject(brushModel.GetSubModel(i)); + var subModelGO = CreateEntityBrushObject(brushModel.GetSubModel(i)); subModelGO.transform.SetParent(brushModelGO.transform); } @@ -132,7 +160,7 @@ public class GameState // TODO: these relatively complex world game objects are going to get destroyed and re-created all the time // as the player moves through the map and moves in and out of range of these entities. This can and should // be done more efficiently by creating the game objects only once and enabling/disabling them on demand. - var worldModelGO = CreateBrushGameObject(subModel); + var worldModelGO = CreateWorldBrushObject(subModel); entity.SetWorldModel(worldModelGO); } diff --git a/Assets/Scripts/VisualStyle.cs b/Assets/Scripts/VisualStyle.cs index 88422b5..a4c7194 100644 --- a/Assets/Scripts/VisualStyle.cs +++ b/Assets/Scripts/VisualStyle.cs @@ -36,13 +36,22 @@ public class VisualStyle : ScriptableObject Shader.DisableKeyword("_POINT_SAMPLING"); } - public virtual Material CreateEntityMaterial() + public virtual Material CreateEntityMaterial(bool aliasModel) { - return new Material(entityMaterial); + var material = new Material(entityMaterial); + + if (aliasModel && affineTexturing) + material.EnableKeyword("_AFFINE_ON"); + else + material.DisableKeyword("_AFFINE_ON"); + + return material; } public virtual Material CreateWorldMaterial(QSurfaceFlags surfaceFlags) { + Material material; + if (surfaceFlags.HasFlag(QSurfaceFlags.DrawTurbulence) && liquidMaterial != null) { float alpha = 1f; @@ -55,14 +64,20 @@ public class VisualStyle : ScriptableObject else if (surfaceFlags.HasFlag(QSurfaceFlags.DrawTeleporter)) alpha = liquidProperties.teleAlpha; - var material = new Material(liquidMaterial); + material = new Material(liquidMaterial); material.SetColor("_BaseColor", new Color(1, 1, 1, alpha)); - return material; + } + else + { + material = new Material(worldMaterial); } - // TODO: enable alpha test for DrawFence flag - - return new Material(worldMaterial); + if (surfaceFlags.HasFlag(QSurfaceFlags.DrawFence)) + { + material.EnableKeyword("_ALPHATEST_ON"); + } + + return material; } public virtual void SetupEntityRenderer(MeshRenderer meshRenderer) @@ -100,11 +115,6 @@ public class VisualStyle : ScriptableObject material.EnableKeyword("_EMISSION"); else material.DisableKeyword("_EMISSION"); - - if (affineTexturing) - material.EnableKeyword("_AFFINE_ON"); - else - material.DisableKeyword("_AFFINE_ON"); } public virtual void SetWorldTextures(Material material, Texture2D mainTexture, Texture2D fullBright, Texture2D lightmap) @@ -119,19 +129,15 @@ public class VisualStyle : ScriptableObject else material.DisableKeyword("_EMISSION"); + material.SetTexture("_LightMap", lightmap); + if (lightmap != null) - { - material.SetTexture("_LightMap", lightmap); material.EnableKeyword("_QLIGHTMAP_ON"); - } else - { material.DisableKeyword("_QLIGHTMAP_ON"); - } } } -// TODO: should probably just use the cvars for this (r_wateralpha and such) [System.Serializable] public class LiquidProperties {