mirror of
https://github.com/Facepunch/sbox-public.git
synced 2025-12-23 22:48:07 -05:00
unfuck the ordering of rebuilding in mesh component so mesh is built before collider, also don't use gameobject scale to scale geometry (#3572)
This commit is contained in:
@@ -18,18 +18,15 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
Hull
|
||||
}
|
||||
|
||||
private PolygonMesh _mesh;
|
||||
|
||||
[Property, Order( 0 )]
|
||||
public PolygonMesh Mesh
|
||||
{
|
||||
get => _mesh;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _mesh == value )
|
||||
return;
|
||||
if ( field == value ) return;
|
||||
|
||||
_mesh = value;
|
||||
field = value;
|
||||
|
||||
Update();
|
||||
}
|
||||
@@ -38,60 +35,55 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
[Property, Order( 1 )]
|
||||
public CollisionType Collision
|
||||
{
|
||||
get => _collisionType;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _collisionType == value )
|
||||
return;
|
||||
if ( field == value ) return;
|
||||
|
||||
_collisionType = value;
|
||||
field = value;
|
||||
|
||||
RebuildImmediately();
|
||||
}
|
||||
}
|
||||
} = CollisionType.Mesh;
|
||||
|
||||
[Property, Title( "Tint" ), Order( 2 )]
|
||||
public Color Color
|
||||
{
|
||||
get => _color;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _color == value )
|
||||
return;
|
||||
if ( field == value ) return;
|
||||
|
||||
_color = value;
|
||||
field = value;
|
||||
|
||||
if ( SceneObject.IsValid() )
|
||||
{
|
||||
SceneObject.ColorTint = Color;
|
||||
}
|
||||
_sceneObject?.ColorTint = Color;
|
||||
}
|
||||
}
|
||||
} = Color.White;
|
||||
|
||||
[Property, Order( 3 )]
|
||||
public float SmoothingAngle
|
||||
{
|
||||
get => _smoothingAngle;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _smoothingAngle == value )
|
||||
if ( field == value )
|
||||
return;
|
||||
|
||||
_smoothingAngle = value;
|
||||
Mesh?.SetSmoothingAngle( _smoothingAngle );
|
||||
field = value;
|
||||
Mesh?.SetSmoothingAngle( field );
|
||||
}
|
||||
}
|
||||
|
||||
[Property, Order( 4 )]
|
||||
public bool HideInGame
|
||||
{
|
||||
get => _hideInGame;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _hideInGame == value )
|
||||
if ( field == value )
|
||||
return;
|
||||
|
||||
_hideInGame = value;
|
||||
field = value;
|
||||
|
||||
if ( Scene.IsEditor )
|
||||
return;
|
||||
@@ -100,78 +92,63 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
{
|
||||
DeleteSceneObject();
|
||||
}
|
||||
else if ( !SceneObject.IsValid() && Model is not null )
|
||||
else if ( !_sceneObject.IsValid() && Model is not null )
|
||||
{
|
||||
SceneObject = new SceneObject( Scene.SceneWorld, Model, WorldTransform );
|
||||
_sceneObject = new SceneObject( Scene.SceneWorld, Model, WorldTransform );
|
||||
UpdateSceneObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ShadowRenderType _renderType = ShadowRenderType.On;
|
||||
|
||||
[Title( "Cast Shadows" ), Property, Category( "Lighting" )]
|
||||
public ShadowRenderType RenderType
|
||||
{
|
||||
get => _renderType;
|
||||
get;
|
||||
set
|
||||
{
|
||||
if ( _renderType == value )
|
||||
return;
|
||||
if ( field == value ) return;
|
||||
|
||||
_renderType = value;
|
||||
if ( SceneObject.IsValid() )
|
||||
field = value;
|
||||
if ( _sceneObject.IsValid() )
|
||||
{
|
||||
SceneObject.Flags.CastShadows = RenderType == ShadowRenderType.On || RenderType == ShadowRenderType.ShadowsOnly;
|
||||
_sceneObject.Flags.CastShadows = RenderType == ShadowRenderType.On || RenderType == ShadowRenderType.ShadowsOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
} = ShadowRenderType.On;
|
||||
|
||||
[JsonIgnore, Hide]
|
||||
public Model Model { get; private set; }
|
||||
|
||||
public override bool IsConcave => Collision == CollisionType.Mesh;
|
||||
|
||||
private bool Hidden => !Scene.IsEditor && HideInGame;
|
||||
private SceneObject SceneObject;
|
||||
private Color _color = Color.White;
|
||||
private CollisionType _collisionType = CollisionType.Mesh;
|
||||
private float _smoothingAngle;
|
||||
private bool _hideInGame;
|
||||
bool Hidden => !Scene.IsEditor && HideInGame;
|
||||
|
||||
SceneObject _sceneObject;
|
||||
|
||||
public void SetMaterial( Material material, int triangle )
|
||||
{
|
||||
if ( Mesh is null )
|
||||
return;
|
||||
if ( Mesh is null ) return;
|
||||
|
||||
var face = Mesh.TriangleToFace( triangle );
|
||||
if ( !face.IsValid )
|
||||
return;
|
||||
if ( !face.IsValid ) return;
|
||||
|
||||
Mesh.SetFaceMaterial( face, material );
|
||||
}
|
||||
|
||||
public Material GetMaterial( int triangle )
|
||||
{
|
||||
if ( Mesh is null )
|
||||
return default;
|
||||
if ( Mesh is null ) return default;
|
||||
|
||||
var face = Mesh.TriangleToFace( triangle );
|
||||
return Mesh.GetFaceMaterial( face );
|
||||
}
|
||||
|
||||
protected override void OnValidate()
|
||||
internal override void OnEnabledInternal()
|
||||
{
|
||||
WorldScale = 1;
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
protected override void OnEnabled()
|
||||
{
|
||||
base.OnEnabled();
|
||||
|
||||
// Mesh needs to build before collider.
|
||||
RebuildMesh();
|
||||
|
||||
base.OnEnabledInternal();
|
||||
}
|
||||
|
||||
protected override void OnDisabled()
|
||||
@@ -181,14 +158,13 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
DeleteSceneObject();
|
||||
}
|
||||
|
||||
private void DeleteSceneObject()
|
||||
void DeleteSceneObject()
|
||||
{
|
||||
if ( !SceneObject.IsValid() )
|
||||
return;
|
||||
if ( !_sceneObject.IsValid() ) return;
|
||||
|
||||
SceneObject.RenderingEnabled = false;
|
||||
SceneObject.Delete();
|
||||
SceneObject = null;
|
||||
_sceneObject.RenderingEnabled = false;
|
||||
_sceneObject.Delete();
|
||||
_sceneObject = null;
|
||||
}
|
||||
|
||||
protected override void OnUpdate()
|
||||
@@ -198,51 +174,40 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
void Update()
|
||||
{
|
||||
if ( !Active )
|
||||
return;
|
||||
|
||||
if ( Mesh is null )
|
||||
return;
|
||||
|
||||
if ( Scene.IsEditor )
|
||||
{
|
||||
Mesh.Transform = WorldTransform;
|
||||
}
|
||||
|
||||
if ( !Mesh.IsDirty )
|
||||
return;
|
||||
// Only rebuild dirty meshes in editor.
|
||||
if ( !Active ) return;
|
||||
if ( !Scene.IsEditor ) return;
|
||||
if ( Mesh is null || !Mesh.IsDirty ) return;
|
||||
|
||||
RebuildMesh();
|
||||
RebuildImmediately();
|
||||
}
|
||||
|
||||
internal override void OnTagsUpdatedInternal()
|
||||
protected override void OnTagsChanged()
|
||||
{
|
||||
if ( SceneObject.IsValid() )
|
||||
{
|
||||
SceneObject.Tags.SetFrom( Tags );
|
||||
}
|
||||
base.OnTagsChanged();
|
||||
|
||||
base.OnTagsUpdatedInternal();
|
||||
if ( _sceneObject.IsValid() )
|
||||
{
|
||||
_sceneObject.Tags.SetFrom( Tags );
|
||||
}
|
||||
}
|
||||
|
||||
internal override void TransformChanged( GameTransform root )
|
||||
{
|
||||
if ( WorldScale != 1 && Mesh is not null )
|
||||
if ( _sceneObject.IsValid() )
|
||||
{
|
||||
Mesh.Scale( WorldScale );
|
||||
WorldScale = 1;
|
||||
_sceneObject.Transform = WorldTransform;
|
||||
}
|
||||
|
||||
if ( Mesh is not null && Scene.IsEditor )
|
||||
{
|
||||
// Compute face texture parameters on transform change but don't rebuild mesh now.
|
||||
var wasDirty = Mesh.IsDirty;
|
||||
Mesh.Transform = WorldTransform;
|
||||
}
|
||||
|
||||
if ( SceneObject.IsValid() )
|
||||
{
|
||||
SceneObject.Transform = WorldTransform;
|
||||
Mesh.IsDirty = wasDirty;
|
||||
}
|
||||
|
||||
base.TransformChanged( root );
|
||||
@@ -290,56 +255,50 @@ public sealed class MeshComponent : Collider, ExecuteInEditor, ITintable, IMater
|
||||
|
||||
public void RebuildMesh()
|
||||
{
|
||||
if ( !Active )
|
||||
return;
|
||||
|
||||
if ( Mesh is null )
|
||||
return;
|
||||
if ( !Active ) return;
|
||||
if ( Mesh is null ) return;
|
||||
|
||||
Mesh.Transform = WorldTransform;
|
||||
Mesh.SetSmoothingAngle( SmoothingAngle );
|
||||
Model = Mesh.Rebuild();
|
||||
|
||||
RebuildImmediately();
|
||||
|
||||
if ( Model is null || Model.MeshCount == 0 )
|
||||
{
|
||||
if ( SceneObject.IsValid() )
|
||||
if ( _sceneObject.IsValid() )
|
||||
{
|
||||
SceneObject.RenderingEnabled = false;
|
||||
SceneObject.Delete();
|
||||
SceneObject = null;
|
||||
_sceneObject.RenderingEnabled = false;
|
||||
_sceneObject.Delete();
|
||||
_sceneObject = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Hidden )
|
||||
return;
|
||||
if ( Hidden ) return;
|
||||
|
||||
if ( !SceneObject.IsValid() )
|
||||
if ( !_sceneObject.IsValid() )
|
||||
{
|
||||
SceneObject = new SceneObject( Scene.SceneWorld, Model, WorldTransform );
|
||||
_sceneObject = new SceneObject( Scene.SceneWorld, Model, WorldTransform );
|
||||
}
|
||||
else
|
||||
{
|
||||
SceneObject.Model = Model;
|
||||
SceneObject.Transform = WorldTransform;
|
||||
_sceneObject.Model = Model;
|
||||
_sceneObject.Transform = WorldTransform;
|
||||
|
||||
// We manually set the model, sceneobject needs to update based on any new materials in it
|
||||
SceneObject.UpdateFlagsBasedOnMaterial();
|
||||
_sceneObject.UpdateFlagsBasedOnMaterial();
|
||||
}
|
||||
|
||||
UpdateSceneObject();
|
||||
}
|
||||
|
||||
private void UpdateSceneObject()
|
||||
void UpdateSceneObject()
|
||||
{
|
||||
if ( !SceneObject.IsValid() ) return;
|
||||
if ( !_sceneObject.IsValid() ) return;
|
||||
|
||||
SceneObject.Component = this;
|
||||
SceneObject.Tags.SetFrom( GameObject.Tags );
|
||||
SceneObject.ColorTint = Color;
|
||||
SceneObject.Flags.CastShadows = RenderType == ShadowRenderType.On || RenderType == ShadowRenderType.ShadowsOnly;
|
||||
_sceneObject.Component = this;
|
||||
_sceneObject.Tags.SetFrom( GameObject.Tags );
|
||||
_sceneObject.ColorTint = Color;
|
||||
_sceneObject.Flags.CastShadows = RenderType == ShadowRenderType.On || RenderType == ShadowRenderType.ShadowsOnly;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ public sealed partial class PolygonMesh : IJsonConvert
|
||||
/// <summary>
|
||||
/// Has there been changes to the mesh that need rebuilding?
|
||||
/// </summary>
|
||||
public bool IsDirty { get; private set; }
|
||||
public bool IsDirty { get; internal set; }
|
||||
|
||||
private Transform _transform = Transform.Zero;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user