mirror of
https://github.com/4sval/FModel.git
synced 2026-09-11 11:06:31 -05:00
convex collision preview
This commit is contained in:
Submodule CUE4Parse updated: 38be126747...fb9413d036
@@ -41,8 +41,6 @@ public partial class App
|
|||||||
{
|
{
|
||||||
UserSettings.Default = JsonConvert.DeserializeObject<UserSettings>(
|
UserSettings.Default = JsonConvert.DeserializeObject<UserSettings>(
|
||||||
File.ReadAllText(UserSettings.FilePath), JsonNetSerializer.SerializerSettings);
|
File.ReadAllText(UserSettings.FilePath), JsonNetSerializer.SerializerSettings);
|
||||||
|
|
||||||
/*if (UserSettings.Default.ShowChangelog) */MigrateV1Games();
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -143,17 +141,6 @@ public partial class App
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MigrateV1Games()
|
|
||||||
{
|
|
||||||
foreach ((var gameDir, var setting) in UserSettings.Default.ManualGames)
|
|
||||||
{
|
|
||||||
if (!Directory.Exists(gameDir)) continue;
|
|
||||||
UserSettings.Default.PerDirectory[gameDir] =
|
|
||||||
DirectorySettings.Default(setting.GameName, setting.GameDirectory, true, setting.OverridedGame, setting.AesKeys?.MainKey);
|
|
||||||
}
|
|
||||||
UserSettings.Default.ManualGames.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetOperatingSystemProductName()
|
private string GetOperatingSystemProductName()
|
||||||
{
|
{
|
||||||
var productName = string.Empty;
|
var productName = string.Empty;
|
||||||
|
|||||||
@@ -116,6 +116,7 @@
|
|||||||
<None Remove="Resources\light.vert" />
|
<None Remove="Resources\light.vert" />
|
||||||
<None Remove="Resources\bone.frag" />
|
<None Remove="Resources\bone.frag" />
|
||||||
<None Remove="Resources\bone.vert" />
|
<None Remove="Resources\bone.vert" />
|
||||||
|
<None Remove="Resources\collision.vert" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -141,6 +142,7 @@
|
|||||||
<EmbeddedResource Include="Resources\light.vert" />
|
<EmbeddedResource Include="Resources\light.vert" />
|
||||||
<EmbeddedResource Include="Resources\bone.frag" />
|
<EmbeddedResource Include="Resources\bone.frag" />
|
||||||
<EmbeddedResource Include="Resources\bone.vert" />
|
<EmbeddedResource Include="Resources\bone.vert" />
|
||||||
|
<EmbeddedResource Include="Resources\collision.vert" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -83,9 +83,9 @@ public partial class MainWindow
|
|||||||
).ConfigureAwait(false);
|
).ConfigureAwait(false);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
await _threadWorkerView.Begin(cancellationToken =>
|
// await _threadWorkerView.Begin(cancellationToken =>
|
||||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
// _applicationView.CUE4Parse.Extract(cancellationToken,
|
||||||
"ShooterGame/Content/Characters/Smonk/S0/3P/Models/TP_Smonk_S0_Skelmesh.uasset"));
|
// "FortniteGame/Content/Environments/Asteria/Props/Coastal/Coastal_Boat_B/Meshes/SM_Coastal_Boat_B.uasset"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
FModel/Resources/collision.vert
Normal file
20
FModel/Resources/collision.vert
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 vPos;
|
||||||
|
|
||||||
|
uniform mat4 uView;
|
||||||
|
uniform mat4 uProjection;
|
||||||
|
uniform mat4 uInstanceMatrix;
|
||||||
|
uniform mat4 uCollisionMatrix;
|
||||||
|
uniform float uScaleDown;
|
||||||
|
|
||||||
|
out vec3 fPos;
|
||||||
|
out vec3 fColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_PointSize = 7.5f;
|
||||||
|
gl_Position = uProjection * uView * uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0);
|
||||||
|
fPos = vec3(uInstanceMatrix * uCollisionMatrix * vec4(vPos.xzy * uScaleDown, 1.0));
|
||||||
|
fColor = vec3(1.0);
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@ public class EndpointSettings : ViewModel
|
|||||||
return new EndpointSettings[]
|
return new EndpointSettings[]
|
||||||
{
|
{
|
||||||
new("https://fortnitecentral.genxgames.gg/api/v1/aes", "$.['mainKey','dynamicKeys']"),
|
new("https://fortnitecentral.genxgames.gg/api/v1/aes", "$.['mainKey','dynamicKeys']"),
|
||||||
// new("https://fortnitecentral.genxgames.gg/api/v1/mappings", "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']")
|
|
||||||
new("https://fortnitecentral.genxgames.gg/api/v1/mappings", "$.[0].['url','fileName']") // just get the first available, not just oodle! (Unfortunately not default except when resetting settings)
|
new("https://fortnitecentral.genxgames.gg/api/v1/mappings", "$.[0].['url','fileName']") // just get the first available, not just oodle! (Unfortunately not default except when resetting settings)
|
||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -399,6 +399,7 @@ public class CUE4ParseViewModel : ViewModel
|
|||||||
else if (endpoint.IsValid)
|
else if (endpoint.IsValid)
|
||||||
{
|
{
|
||||||
var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
|
var mappingsFolder = Path.Combine(UserSettings.Default.OutputDirectory, ".data");
|
||||||
|
if (endpoint.Path == "$.[?(@.meta.compressionMethod=='Oodle')].['url','fileName']") endpoint.Path = "$.[0].['url','fileName']";
|
||||||
var mappings = _apiEndpointView.DynamicApi.GetMappings(default, endpoint.Url, endpoint.Path);
|
var mappings = _apiEndpointView.DynamicApi.GetMappings(default, endpoint.Url, endpoint.Path);
|
||||||
if (mappings is { Length: > 0 })
|
if (mappings is { Length: > 0 })
|
||||||
{
|
{
|
||||||
|
|||||||
62
FModel/Views/Snooper/Models/Collision.cs
Normal file
62
FModel/Views/Snooper/Models/Collision.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using CUE4Parse.UE4.Objects.Core.Math;
|
||||||
|
using CUE4Parse.UE4.Objects.PhysicsEngine;
|
||||||
|
using FModel.Views.Snooper.Buffers;
|
||||||
|
using FModel.Views.Snooper.Shading;
|
||||||
|
using OpenTK.Graphics.OpenGL4;
|
||||||
|
|
||||||
|
namespace FModel.Views.Snooper.Models;
|
||||||
|
|
||||||
|
public class Collision : IDisposable
|
||||||
|
{
|
||||||
|
private readonly int[] _indexData;
|
||||||
|
private readonly FVector[] _vertexData;
|
||||||
|
private readonly Transform _transform;
|
||||||
|
|
||||||
|
private int _handle;
|
||||||
|
private BufferObject<int> _ebo { get; set; }
|
||||||
|
private BufferObject<FVector> _vbo { get; set; }
|
||||||
|
private VertexArrayObject<FVector, int> _vao { get; set; }
|
||||||
|
|
||||||
|
public Collision(FKConvexElem convexElems)
|
||||||
|
{
|
||||||
|
_indexData = convexElems.IndexData;
|
||||||
|
_vertexData = convexElems.VertexData;
|
||||||
|
_transform = new Transform
|
||||||
|
{
|
||||||
|
Position = convexElems.Transform.Translation * Constants.SCALE_DOWN_RATIO,
|
||||||
|
Rotation = convexElems.Transform.Rotation,
|
||||||
|
Scale = convexElems.Transform.Scale3D
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_handle = GL.CreateProgram();
|
||||||
|
_ebo = new BufferObject<int>(_indexData, BufferTarget.ElementArrayBuffer);
|
||||||
|
_vbo = new BufferObject<FVector>(_vertexData, BufferTarget.ArrayBuffer);
|
||||||
|
_vao = new VertexArrayObject<FVector, int>(_vbo, _ebo);
|
||||||
|
|
||||||
|
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 1, 0);
|
||||||
|
_vao.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Render(Shader shader)
|
||||||
|
{
|
||||||
|
shader.SetUniform("uCollisionMatrix", _transform.Matrix);
|
||||||
|
|
||||||
|
_vao.Bind();
|
||||||
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line);
|
||||||
|
GL.DrawElements(PrimitiveType.Triangles, _ebo.Size, DrawElementsType.UnsignedInt, 0);
|
||||||
|
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||||
|
_vao.Unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_ebo?.Dispose();
|
||||||
|
_vbo?.Dispose();
|
||||||
|
_vao?.Dispose();
|
||||||
|
GL.DeleteProgram(_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using CUE4Parse_Conversion.Meshes.PSK;
|
|||||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||||
using CUE4Parse.UE4.Objects.Core.Math;
|
using CUE4Parse.UE4.Objects.Core.Math;
|
||||||
|
using CUE4Parse.UE4.Objects.PhysicsEngine;
|
||||||
using CUE4Parse.UE4.Objects.UObject;
|
using CUE4Parse.UE4.Objects.UObject;
|
||||||
using FModel.Views.Snooper.Animations;
|
using FModel.Views.Snooper.Animations;
|
||||||
using FModel.Views.Snooper.Buffers;
|
using FModel.Views.Snooper.Buffers;
|
||||||
@@ -44,6 +45,18 @@ public class SkeletalModel : UModel
|
|||||||
Sockets.Add(new Socket(socket));
|
Sockets.Add(new Socket(socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (export.PhysicsAsset.TryLoad(out UPhysicsAsset physicsAsset))
|
||||||
|
{
|
||||||
|
foreach (var skeletalBodySetup in physicsAsset.SkeletalBodySetups)
|
||||||
|
{
|
||||||
|
if (!skeletalBodySetup.TryLoad(out USkeletalBodySetup bodySetup)) continue;
|
||||||
|
foreach (var convexElem in bodySetup.AggGeom.ConvexElems)
|
||||||
|
{
|
||||||
|
Collisions.Add(new Collision(convexElem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Morphs = new List<Morph>();
|
Morphs = new List<Morph>();
|
||||||
for (var i = 0; i < export.MorphTargets.Length; i++)
|
for (var i = 0; i < export.MorphTargets.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using CUE4Parse_Conversion.Meshes.PSK;
|
using CUE4Parse_Conversion.Meshes.PSK;
|
||||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||||
|
using CUE4Parse.UE4.Objects.PhysicsEngine;
|
||||||
using FModel.Views.Snooper.Shading;
|
using FModel.Views.Snooper.Shading;
|
||||||
|
|
||||||
namespace FModel.Views.Snooper.Models;
|
namespace FModel.Views.Snooper.Models;
|
||||||
@@ -52,6 +53,14 @@ public class StaticModel : UModel
|
|||||||
public StaticModel(UStaticMesh export, CStaticMesh staticMesh, Transform transform = null)
|
public StaticModel(UStaticMesh export, CStaticMesh staticMesh, Transform transform = null)
|
||||||
: base(export, staticMesh.LODs[LodLevel], export.Materials, staticMesh.LODs[LodLevel].Verts, staticMesh.LODs.Count, transform)
|
: base(export, staticMesh.LODs[LodLevel], export.Materials, staticMesh.LODs[LodLevel].Verts, staticMesh.LODs.Count, transform)
|
||||||
{
|
{
|
||||||
|
if (export.BodySetup.TryLoad(out UBodySetup bodySetup))
|
||||||
|
{
|
||||||
|
foreach (var convexElem in bodySetup.AggGeom.ConvexElems)
|
||||||
|
{
|
||||||
|
Collisions.Add(new Collision(convexElem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
Box = staticMesh.BoundingBox * Constants.SCALE_DOWN_RATIO;
|
||||||
for (int i = 0; i < export.Sockets.Length; i++)
|
for (int i = 0; i < export.Sockets.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public abstract class UModel : IRenderableModel
|
|||||||
|
|
||||||
public FBox Box;
|
public FBox Box;
|
||||||
public readonly List<Socket> Sockets;
|
public readonly List<Socket> Sockets;
|
||||||
|
public readonly List<Collision> Collisions;
|
||||||
public Material[] Materials;
|
public Material[] Materials;
|
||||||
public bool IsTwoSided;
|
public bool IsTwoSided;
|
||||||
public bool IsProp;
|
public bool IsProp;
|
||||||
@@ -67,12 +68,14 @@ public abstract class UModel : IRenderableModel
|
|||||||
public int VertexSize => _vertexAttributes.Where(x => x.Enabled).Sum(x => x.Size);
|
public int VertexSize => _vertexAttributes.Where(x => x.Enabled).Sum(x => x.Size);
|
||||||
public bool HasVertexColors => _vertexAttributes[(int) EAttribute.Colors].Enabled;
|
public bool HasVertexColors => _vertexAttributes[(int) EAttribute.Colors].Enabled;
|
||||||
public bool HasSockets => Sockets.Count > 0;
|
public bool HasSockets => Sockets.Count > 0;
|
||||||
|
public bool HasCollisions => Collisions.Count > 0;
|
||||||
public int TransformsCount => Transforms.Count;
|
public int TransformsCount => Transforms.Count;
|
||||||
|
|
||||||
public bool IsSetup { get; set; }
|
public bool IsSetup { get; set; }
|
||||||
public bool IsVisible { get; set; }
|
public bool IsVisible { get; set; }
|
||||||
public bool IsSelected { get; set; }
|
public bool IsSelected { get; set; }
|
||||||
public bool ShowWireframe { get; set; }
|
public bool ShowWireframe { get; set; }
|
||||||
|
public bool ShowCollisions { get; set; }
|
||||||
public int SelectedInstance;
|
public int SelectedInstance;
|
||||||
|
|
||||||
protected UModel()
|
protected UModel()
|
||||||
@@ -82,6 +85,7 @@ public abstract class UModel : IRenderableModel
|
|||||||
|
|
||||||
Box = new FBox(new FVector(-2f), new FVector(2f));
|
Box = new FBox(new FVector(-2f), new FVector(2f));
|
||||||
Sockets = new List<Socket>();
|
Sockets = new List<Socket>();
|
||||||
|
Collisions = new List<Collision>();
|
||||||
Transforms = new List<Transform>();
|
Transforms = new List<Transform>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +99,7 @@ public abstract class UModel : IRenderableModel
|
|||||||
|
|
||||||
Box = new FBox(new FVector(-2f), new FVector(2f));
|
Box = new FBox(new FVector(-2f), new FVector(2f));
|
||||||
Sockets = new List<Socket>();
|
Sockets = new List<Socket>();
|
||||||
|
Collisions = new List<Collision>();
|
||||||
Transforms = new List<Transform>();
|
Transforms = new List<Transform>();
|
||||||
Attachments = new Attachment(Name);
|
Attachments = new Attachment(Name);
|
||||||
|
|
||||||
@@ -209,6 +214,11 @@ public abstract class UModel : IRenderableModel
|
|||||||
Materials[i].Setup(options, broken ? 1 : UvCount);
|
Materials[i].Setup(options, broken ? 1 : UvCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var collision in Collisions)
|
||||||
|
{
|
||||||
|
collision.Setup();
|
||||||
|
}
|
||||||
|
|
||||||
if (options.Models.Count == 1 && Sections.All(x => !x.Show))
|
if (options.Models.Count == 1 && Sections.All(x => !x.Show))
|
||||||
{
|
{
|
||||||
IsVisible = true;
|
IsVisible = true;
|
||||||
@@ -294,6 +304,16 @@ public abstract class UModel : IRenderableModel
|
|||||||
if (IsTwoSided) GL.Enable(EnableCap.CullFace);
|
if (IsTwoSided) GL.Enable(EnableCap.CullFace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RenderCollision(Shader shader)
|
||||||
|
{
|
||||||
|
shader.SetUniform("uInstanceMatrix", GetTransform().Matrix);
|
||||||
|
shader.SetUniform("uScaleDown", Constants.SCALE_DOWN_RATIO);
|
||||||
|
foreach (var collision in Collisions)
|
||||||
|
{
|
||||||
|
collision.Render(shader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Update(Options options)
|
public void Update(Options options)
|
||||||
{
|
{
|
||||||
MatrixVbo.Bind();
|
MatrixVbo.Bind();
|
||||||
@@ -381,6 +401,11 @@ public abstract class UModel : IRenderableModel
|
|||||||
socket?.Dispose();
|
socket?.Dispose();
|
||||||
}
|
}
|
||||||
Sockets.Clear();
|
Sockets.Clear();
|
||||||
|
foreach (var collision in Collisions)
|
||||||
|
{
|
||||||
|
collision?.Dispose();
|
||||||
|
}
|
||||||
|
Collisions.Clear();
|
||||||
|
|
||||||
GL.DeleteProgram(Handle);
|
GL.DeleteProgram(Handle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class Renderer : IDisposable
|
|||||||
private Shader _outline;
|
private Shader _outline;
|
||||||
private Shader _light;
|
private Shader _light;
|
||||||
private Shader _bone;
|
private Shader _bone;
|
||||||
|
private Shader _collision;
|
||||||
private bool _saveCameraMode;
|
private bool _saveCameraMode;
|
||||||
|
|
||||||
public bool ShowSkybox;
|
public bool ShowSkybox;
|
||||||
@@ -227,6 +228,7 @@ public class Renderer : IDisposable
|
|||||||
_outline = new Shader("outline");
|
_outline = new Shader("outline");
|
||||||
_light = new Shader("light");
|
_light = new Shader("light");
|
||||||
_bone = new Shader("bone");
|
_bone = new Shader("bone");
|
||||||
|
_collision = new Shader("collision", "bone");
|
||||||
|
|
||||||
Picking.Setup();
|
Picking.Setup();
|
||||||
Options.SetupModelsAndLights();
|
Options.SetupModelsAndLights();
|
||||||
@@ -272,6 +274,11 @@ public class Renderer : IDisposable
|
|||||||
_bone.Render(viewMatrix, projMatrix);
|
_bone.Render(viewMatrix, projMatrix);
|
||||||
skeletalModel.RenderBones(_bone);
|
skeletalModel.RenderBones(_bone);
|
||||||
}
|
}
|
||||||
|
else if (selected.ShowCollisions)
|
||||||
|
{
|
||||||
|
_collision.Render(viewMatrix, projMatrix);
|
||||||
|
selected.RenderCollision(_collision);
|
||||||
|
}
|
||||||
|
|
||||||
_outline.Render(viewMatrix, CameraOp.Position, projMatrix);
|
_outline.Render(viewMatrix, CameraOp.Position, projMatrix);
|
||||||
selected.Render(_outline, Color == VertexColor.TextureCoordinates ? Options.Icons["checker"] : null, true);
|
selected.Render(_outline, Color == VertexColor.TextureCoordinates ? Options.Icons["checker"] : null, true);
|
||||||
@@ -642,6 +649,7 @@ public class Renderer : IDisposable
|
|||||||
_outline?.Dispose();
|
_outline?.Dispose();
|
||||||
_light?.Dispose();
|
_light?.Dispose();
|
||||||
_bone?.Dispose();
|
_bone?.Dispose();
|
||||||
|
_collision?.Dispose();
|
||||||
Picking?.Dispose();
|
Picking?.Dispose();
|
||||||
Options?.Dispose();
|
Options?.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,12 @@ public class Shader : IDisposable
|
|||||||
|
|
||||||
public Shader() : this("default") {}
|
public Shader() : this("default") {}
|
||||||
|
|
||||||
public Shader(string name)
|
public Shader(string name1, string name2 = null)
|
||||||
{
|
{
|
||||||
_handle = GL.CreateProgram();
|
_handle = GL.CreateProgram();
|
||||||
|
|
||||||
var v = LoadShader(ShaderType.VertexShader, $"{name}.vert");
|
var v = LoadShader(ShaderType.VertexShader, $"{name1}.vert");
|
||||||
var f = LoadShader(ShaderType.FragmentShader, $"{name}.frag");
|
var f = LoadShader(ShaderType.FragmentShader, $"{name2 ?? name1}.frag");
|
||||||
GL.AttachShader(_handle, v);
|
GL.AttachShader(_handle, v);
|
||||||
GL.AttachShader(_handle, f);
|
GL.AttachShader(_handle, f);
|
||||||
GL.LinkProgram(_handle);
|
GL.LinkProgram(_handle);
|
||||||
|
|||||||
@@ -421,6 +421,7 @@ Snooper aims to give an accurate preview of models, materials, skeletal animatio
|
|||||||
s.Renderer.Options.SelectModel(guid);
|
s.Renderer.Options.SelectModel(guid);
|
||||||
if (ImGui.MenuItem("Show", null, model.IsVisible)) model.IsVisible = !model.IsVisible;
|
if (ImGui.MenuItem("Show", null, model.IsVisible)) model.IsVisible = !model.IsVisible;
|
||||||
if (ImGui.MenuItem("Wireframe", null, model.ShowWireframe)) model.ShowWireframe = !model.ShowWireframe;
|
if (ImGui.MenuItem("Wireframe", null, model.ShowWireframe)) model.ShowWireframe = !model.ShowWireframe;
|
||||||
|
if (ImGui.MenuItem("Collisions", null, model.ShowCollisions, model.HasCollisions)) model.ShowCollisions = !model.ShowCollisions;
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
if (ImGui.MenuItem("Save"))
|
if (ImGui.MenuItem("Save"))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user