mirror of
https://github.com/4sval/FModel.git
synced 2026-04-16 22:46:09 -05:00
fmodel { -viewer: save !important; }
This commit is contained in:
parent
c8f0d9f014
commit
41319ad2a3
|
|
@ -1 +1 @@
|
|||
Subproject commit 5ea2543cefa613ac7e49481bfb8977bf20d38238
|
||||
Subproject commit 00664537d9f861161e18f2e93308d77b8d3c7372
|
||||
|
|
@ -79,7 +79,7 @@ public partial class MainWindow
|
|||
#if DEBUG
|
||||
await _threadWorkerView.Begin(cancellationToken =>
|
||||
_applicationView.CUE4Parse.Extract(cancellationToken,
|
||||
"FortniteGame/Content/Characters/Player/Male/Medium/Bodies/M_MED_Despair/Meshes/M_MED_Despair.uasset"));
|
||||
"FortniteGame/Content/Environments/Apollo/Props/Log_Sign/Meshes/SM_Apollo_Log_Sign.uasset"));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ using FModel.Views;
|
|||
using FModel.Views.Resources.Controls;
|
||||
using FModel.Views.Snooper;
|
||||
using Newtonsoft.Json;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using Serilog;
|
||||
using SkiaSharp;
|
||||
|
||||
|
|
@ -69,8 +72,28 @@ public class CUE4ParseViewModel : ViewModel
|
|||
set => SetProperty(ref _modelIsOverwritingMaterial, value);
|
||||
}
|
||||
|
||||
public Snooper SnooperViewer => _snooper ??= new Snooper();
|
||||
private Snooper _snooper;
|
||||
public Snooper SnooperViewer
|
||||
{
|
||||
get
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
return _snooper ??= new Snooper(GameWindowSettings.Default,
|
||||
new NativeWindowSettings
|
||||
{
|
||||
Size = new Vector2i(
|
||||
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenWidth * .7),
|
||||
Convert.ToInt32(SystemParameters.MaximizedPrimaryScreenHeight * .7)),
|
||||
NumberOfSamples = Constants.SAMPLES_COUNT,
|
||||
WindowBorder = WindowBorder.Resizable,
|
||||
StartVisible = false,
|
||||
StartFocused = false,
|
||||
Title = "Title"
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractVfsFileProvider Provider { get; }
|
||||
public GameDirectoryViewModel GameDirectory { get; }
|
||||
|
|
@ -757,15 +780,14 @@ public class CUE4ParseViewModel : ViewModel
|
|||
export.Owner.Name.EndsWith($"/RenderSwitch_Materials/{export.Name}", StringComparison.OrdinalIgnoreCase) ||
|
||||
export.Owner.Name.EndsWith($"/MI_BPTile/{export.Name}", StringComparison.OrdinalIgnoreCase))):
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
SnooperViewer.Run(cancellationToken, export);
|
||||
});
|
||||
SnooperViewer.LoadExport(cancellationToken, export);
|
||||
SnooperViewer.Run();
|
||||
return true;
|
||||
}
|
||||
case UMaterialInstance m when ModelIsOverwritingMaterial:
|
||||
{
|
||||
SnooperViewer.SwapMaterial(m);
|
||||
SnooperViewer.Run();
|
||||
return true;
|
||||
}
|
||||
case UStaticMesh when UserSettings.Default.SaveStaticMeshes:
|
||||
|
|
|
|||
77
FModel/Views/Snooper/Cache.cs
Normal file
77
FModel/Views/Snooper/Cache.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class Cache : IDisposable
|
||||
{
|
||||
private readonly Dictionary<FGuid, Model> _models;
|
||||
private readonly Dictionary<FGuid, Texture> _textures;
|
||||
|
||||
public Cache()
|
||||
{
|
||||
_models = new Dictionary<FGuid, Model>();
|
||||
_textures = new Dictionary<FGuid, Texture>();
|
||||
}
|
||||
|
||||
public void AddModel(FGuid guid, Model model) => _models.Add(guid, model);
|
||||
public void AddTexture(FGuid guid, Texture texture) => _textures.Add(guid, texture);
|
||||
|
||||
public bool HasModel(FGuid guid) => _models.ContainsKey(guid);
|
||||
public bool HasTexture(FGuid guid) => _textures.ContainsKey(guid);
|
||||
|
||||
public bool TryGetModel(FGuid guid, out Model model) => _models.TryGetValue(guid, out model);
|
||||
public bool TryGetTexture(FGuid guid, out Texture texture) => _textures.TryGetValue(guid, out texture);
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
model.Setup();
|
||||
}
|
||||
}
|
||||
public void Render(Shader shader)
|
||||
{
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
if (!model.Show) continue;
|
||||
model.Render(shader);
|
||||
}
|
||||
}
|
||||
public void Outline(Shader shader)
|
||||
{
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
if (!model.IsSelected) continue;
|
||||
model.Outline(shader);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearModels() => _models.Clear();
|
||||
public void ClearTextures() => _textures.Clear();
|
||||
|
||||
public void DisposeModels()
|
||||
{
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
model.Dispose();
|
||||
}
|
||||
}
|
||||
public void DisposeTextures()
|
||||
{
|
||||
foreach (var texture in _textures.Values)
|
||||
{
|
||||
texture.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeModels();
|
||||
ClearModels();
|
||||
|
||||
DisposeTextures();
|
||||
ClearTextures();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -54,13 +54,13 @@ public class Camera
|
|||
Direction = Vector3.Normalize(direction);
|
||||
}
|
||||
|
||||
public Matrix4x4 GetViewMatrix()
|
||||
public Matrix4 GetViewMatrix()
|
||||
{
|
||||
return Matrix4x4.CreateLookAt(Position, Position + Direction, Up);
|
||||
return Matrix4.LookAt(Position, Position + Direction, Up);
|
||||
}
|
||||
|
||||
public Matrix4x4 GetProjectionMatrix()
|
||||
public Matrix4 GetProjectionMatrix()
|
||||
{
|
||||
return Matrix4x4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, Near, Far);
|
||||
return Matrix4.CreatePerspectiveFieldOfView(Helper.DegreesToRadians(Zoom), AspectRatio, Near, Far);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace FModel.Views.Snooper;
|
|||
|
||||
public class Cube : Model
|
||||
{
|
||||
public Cube(UObject owner, string name, string type, UMaterialInterface unrealMaterial) : base(owner, name, type)
|
||||
public Cube(UMaterialInterface unrealMaterial) : base(unrealMaterial.Name, unrealMaterial.ExportType)
|
||||
{
|
||||
Indices = new uint[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,364 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.Core.Misc;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse_Conversion.Meshes;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class FWindow : GameWindow
|
||||
{
|
||||
private Camera _camera;
|
||||
private Image _icon;
|
||||
private Options _options;
|
||||
|
||||
// private readonly FramebufferObject _framebuffer;
|
||||
private readonly Skybox _skybox;
|
||||
private readonly Grid _grid;
|
||||
|
||||
private Shader _shader;
|
||||
private Shader _outline;
|
||||
private Vector3 _diffuseLight;
|
||||
private Vector3 _specularLight;
|
||||
private readonly Dictionary<FGuid, Model> _models;
|
||||
|
||||
private float _previousSpeed;
|
||||
|
||||
public FWindow(GameWindowSettings gameWindowSettings, NativeWindowSettings nativeWindowSettings) : base(gameWindowSettings, nativeWindowSettings)
|
||||
{
|
||||
_options = new Options();
|
||||
// _framebuffer = new FramebufferObject(Size);
|
||||
_skybox = new Skybox();
|
||||
_grid = new Grid();
|
||||
_models = new Dictionary<FGuid, Model>();
|
||||
}
|
||||
|
||||
public void Run(CancellationToken cancellationToken, UObject export)
|
||||
{
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st:
|
||||
{
|
||||
var guid = st.LightingGuid;
|
||||
if (!_models.TryGetValue(guid, out _) && st.TryConvert(out var mesh))
|
||||
{
|
||||
_models[guid] = new Model(export, st.Name, st.ExportType, mesh.LODs[0], mesh.LODs[0].Verts);
|
||||
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
_options.SelectModel(guid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USkeletalMesh sk:
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
if (!_models.TryGetValue(guid, out _) && sk.TryConvert(out var mesh))
|
||||
{
|
||||
_models[guid] = new Model(export, sk.Name, sk.ExportType, mesh.LODs[0], mesh.LODs[0].Verts, sk.MorphTargets, mesh.RefSkeleton);
|
||||
SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
_options.SelectModel(guid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UMaterialInstance mi:
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
if (!_models.TryGetValue(guid, out _))
|
||||
{
|
||||
_models[guid] = new Cube(export, mi.Name, mi.ExportType, mi);
|
||||
SetupCamera(new FBox(new FVector(-.65f), new FVector(.65f)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UWorld wd:
|
||||
{
|
||||
var persistentLevel = wd.PersistentLevel.Load<ULevel>();
|
||||
var length = persistentLevel.Actors.Length;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if (persistentLevel.Actors[i].Load() is not { } actor || actor.ExportType == "LODActor" ||
|
||||
!actor.TryGetValue(out FPackageIndex staticMeshComponent, "StaticMeshComponent") ||
|
||||
staticMeshComponent.Load() is not { } staticMeshComp) continue;
|
||||
|
||||
if (!staticMeshComp.TryGetValue(out FPackageIndex staticMesh, "StaticMesh") && actor.Class is UBlueprintGeneratedClass)
|
||||
foreach (var actorExp in actor.Class.Owner.GetExports())
|
||||
if (actorExp.TryGetValue(out staticMesh, "StaticMesh"))
|
||||
break;
|
||||
if (staticMesh?.Load() is not UStaticMesh m)
|
||||
continue;
|
||||
|
||||
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"Actor {i}/{length}");
|
||||
|
||||
var guid = m.LightingGuid;
|
||||
var transform = new Transform
|
||||
{
|
||||
Position = staticMeshComp.GetOrDefault("RelativeLocation", FVector.ZeroVector) * Constants.SCALE_DOWN_RATIO,
|
||||
Rotation = staticMeshComp.GetOrDefault("RelativeRotation", FRotator.ZeroRotator),
|
||||
Scale = staticMeshComp.GetOrDefault("RelativeScale3D", FVector.OneVector)
|
||||
};
|
||||
transform.Rotation.Yaw = -transform.Rotation.Yaw;
|
||||
|
||||
if (_models.TryGetValue(guid, out var model))
|
||||
{
|
||||
model.AddInstance(transform);
|
||||
}
|
||||
else if (m.TryConvert(out var mesh))
|
||||
{
|
||||
model = new Model(export, m.Name, m.ExportType, mesh.LODs[0], mesh.LODs[0].Verts, null, null, transform);
|
||||
|
||||
if (actor.TryGetAllValues(out FPackageIndex[] textureData, "TextureData"))
|
||||
{
|
||||
for (int j = 0; j < textureData.Length; j++)
|
||||
{
|
||||
if (textureData[j].Load() is not { } textureDataIdx)
|
||||
continue;
|
||||
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex diffuse, "Diffuse") &&
|
||||
diffuse.Load() is UTexture2D diffuseTexture)
|
||||
model.Sections[j].Parameters.Diffuse = diffuseTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex normal, "Normal") &&
|
||||
normal.Load() is UTexture2D normalTexture)
|
||||
model.Sections[j].Parameters.Normal = normalTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex specular, "Specular") &&
|
||||
specular.Load() is UTexture2D specularTexture)
|
||||
model.Sections[j].Parameters.Specular = specularTexture;
|
||||
}
|
||||
}
|
||||
if (staticMeshComp.TryGetValue(out FPackageIndex[] overrideMaterials, "OverrideMaterials"))
|
||||
{
|
||||
var max = model.Sections.Length - 1;
|
||||
for (var j = 0; j < overrideMaterials.Length; j++)
|
||||
{
|
||||
if (j > max) break;
|
||||
if (overrideMaterials[j].Load() is not UMaterialInterface unrealMaterial) continue;
|
||||
model.Sections[j].SwapMaterial(unrealMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
_models[guid] = model;
|
||||
}
|
||||
}
|
||||
_camera = new Camera(new Vector3(0f, 5f, 5f), Vector3.Zero, 0.01f, 1000f, 5f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(export));
|
||||
}
|
||||
|
||||
Run();
|
||||
}
|
||||
|
||||
public void SwapMaterial(UMaterialInstance mi)
|
||||
{
|
||||
if (!_models.TryGetValue(_options.SelectedModel, out var model) ||
|
||||
!_options.TryGetSection(model, out var section)) return;
|
||||
|
||||
section.SwapMaterial(mi);
|
||||
_options.SwapMaterial(false);
|
||||
Run();
|
||||
}
|
||||
|
||||
private void DoLoop()
|
||||
{
|
||||
if (_options.Append) _options.Append = false;
|
||||
// if (_window.IsInitialized)
|
||||
// {
|
||||
// if (!_window.GLContext.IsCurrent)
|
||||
// {
|
||||
// _window.GLContext.MakeCurrent();
|
||||
// }
|
||||
//
|
||||
// _append = false;
|
||||
// _window.IsVisible = true;
|
||||
// var model = _models.Last();
|
||||
// model.Value.Setup(_gl);
|
||||
// _imGui.Increment(model.Key);
|
||||
// }
|
||||
// else _window.Initialize();
|
||||
//
|
||||
// while (!_window.IsClosing && _window.IsVisible)
|
||||
// {
|
||||
// _window.DoEvents();
|
||||
// if (!_window.IsClosing && _window.IsVisible)
|
||||
// _window.DoUpdate();
|
||||
// if (_window.IsClosing || !_window.IsVisible)
|
||||
// return;
|
||||
// _window.DoRender();
|
||||
// }
|
||||
//
|
||||
// _window.DoEvents();
|
||||
// if (_window.IsClosing) _window.Reset();
|
||||
}
|
||||
|
||||
private void SetupCamera(FBox box)
|
||||
{
|
||||
var far = box.Max.Max();
|
||||
var center = box.GetCenter();
|
||||
var position = new Vector3(0f, center.Z, box.Max.Y * 3);
|
||||
var speed = far / 2f;
|
||||
if (speed > _previousSpeed)
|
||||
{
|
||||
_camera = new Camera(position, center, 0.01f, far * 50f, speed);
|
||||
_previousSpeed = _camera.Speed;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
base.OnLoad();
|
||||
CenterWindow();
|
||||
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.Multisample);
|
||||
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
// _framebuffer.Setup();
|
||||
_skybox.Setup();
|
||||
_grid.Setup();
|
||||
|
||||
_shader = new Shader();
|
||||
_outline = new Shader("outline");
|
||||
_diffuseLight = new Vector3(0.75f);
|
||||
_specularLight = new Vector3(0.5f);
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
model.Setup();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs args)
|
||||
{
|
||||
base.OnRenderFrame(args);
|
||||
|
||||
ClearWhatHasBeenDrawn(); // in main window
|
||||
|
||||
// _framebuffer.Bind(); // switch to dedicated window
|
||||
// ClearWhatHasBeenDrawn(); // in dedicated window
|
||||
|
||||
_skybox.Bind(_camera);
|
||||
_grid.Bind(_camera);
|
||||
|
||||
var viewMatrix = _camera.GetViewMatrix();
|
||||
var projMatrix = _camera.GetProjectionMatrix();
|
||||
|
||||
_outline.Use();
|
||||
_outline.SetUniform("uView", viewMatrix);
|
||||
_outline.SetUniform("uProjection", projMatrix);
|
||||
_outline.SetUniform("viewPos", _camera.Position);
|
||||
|
||||
_shader.Use();
|
||||
_shader.SetUniform("uView", viewMatrix);
|
||||
_shader.SetUniform("uProjection", projMatrix);
|
||||
_shader.SetUniform("viewPos", _camera.Position);
|
||||
|
||||
_shader.SetUniform("material.diffuseMap", 0);
|
||||
_shader.SetUniform("material.normalMap", 1);
|
||||
_shader.SetUniform("material.specularMap", 2);
|
||||
_shader.SetUniform("material.emissionMap", 3);
|
||||
|
||||
_shader.SetUniform("light.position", _camera.Position);
|
||||
_shader.SetUniform("light.diffuse", _diffuseLight);
|
||||
_shader.SetUniform("light.specular", _specularLight);
|
||||
|
||||
foreach (var model in _models.Values.Where(model => model.Show))
|
||||
{
|
||||
model.Bind(_shader);
|
||||
}
|
||||
GL.Enable(EnableCap.StencilTest); // I don't get why this must be here but it works now so...
|
||||
foreach (var model in _models.Values.Where(model => model.IsSelected && model.Show))
|
||||
{
|
||||
model.Outline(_outline);
|
||||
}
|
||||
|
||||
// _framebuffer.BindMsaa();
|
||||
// _framebuffer.Bind(0); // switch back to main window
|
||||
// _framebuffer.BindStuff();
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
private void ClearWhatHasBeenDrawn()
|
||||
{
|
||||
GL.ClearColor(1.0f, 0f, 0f, 1.0f);
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnUpdateFrame(e);
|
||||
if (!IsFocused)
|
||||
return;
|
||||
|
||||
var multiplier = KeyboardState.IsKeyDown(Keys.LeftShift) ? 2f : 1f;
|
||||
var moveSpeed = _camera.Speed * multiplier * (float) e.Time;
|
||||
if (KeyboardState.IsKeyDown(Keys.W))
|
||||
_camera.Position += moveSpeed * _camera.Direction;
|
||||
if (KeyboardState.IsKeyDown(Keys.S))
|
||||
_camera.Position -= moveSpeed * _camera.Direction;
|
||||
if (KeyboardState.IsKeyDown(Keys.A))
|
||||
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
if (KeyboardState.IsKeyDown(Keys.D))
|
||||
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
if (KeyboardState.IsKeyDown(Keys.E))
|
||||
_camera.Position += moveSpeed * _camera.Up;
|
||||
if (KeyboardState.IsKeyDown(Keys.Q))
|
||||
_camera.Position -= moveSpeed * _camera.Up;
|
||||
if (KeyboardState.IsKeyDown(Keys.X))
|
||||
_camera.ModifyZoom(-.5f);
|
||||
if (KeyboardState.IsKeyDown(Keys.C))
|
||||
_camera.ModifyZoom(+.5f);
|
||||
|
||||
const float lookSensitivity = 0.1f;
|
||||
var delta = MouseState.Delta * lookSensitivity;
|
||||
_camera.ModifyDirection(delta.X, delta.Y);
|
||||
|
||||
if (KeyboardState.IsKeyPressed(Keys.H))
|
||||
IsVisible = false;
|
||||
if (KeyboardState.IsKeyPressed(Keys.Escape))
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OnClose()
|
||||
{
|
||||
// _framebuffer.Dispose();
|
||||
_grid.Dispose();
|
||||
_skybox.Dispose();
|
||||
_shader.Dispose();
|
||||
_outline.Dispose();
|
||||
foreach (var model in _models.Values)
|
||||
{
|
||||
model.Dispose();
|
||||
}
|
||||
if (!_options.Append)
|
||||
{
|
||||
_models.Clear();
|
||||
_options.Reset();
|
||||
_previousSpeed = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnResize(ResizeEventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
GL.Viewport(0, 0, Size.X, Size.Y);
|
||||
// _camera.AspectRatio = Size.X / (float)Size.Y;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ public class Grid : IDisposable
|
|||
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 3, 0); // position
|
||||
}
|
||||
|
||||
public void Bind(Camera camera)
|
||||
public void Render(Camera camera)
|
||||
{
|
||||
GL.Disable(EnableCap.DepthTest);
|
||||
_vao.Bind();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Animation;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
|
|
@ -24,7 +23,6 @@ public class Model : IDisposable
|
|||
private readonly uint[] _facesIndex = { 1, 0, 2 };
|
||||
private const int _faceSize = 3; // just so we don't have to do .Length
|
||||
|
||||
public readonly UObject Owner;
|
||||
public readonly string Name;
|
||||
public readonly string Type;
|
||||
public readonly bool HasVertexColors;
|
||||
|
|
@ -45,24 +43,44 @@ public class Model : IDisposable
|
|||
public bool DisplayBones;
|
||||
public float MorphTime;
|
||||
|
||||
protected Model(UObject owner, string name, string type)
|
||||
protected Model(string name, string type)
|
||||
{
|
||||
Owner = owner;
|
||||
Name = name;
|
||||
Type = type;
|
||||
Transforms = new List<Transform>();
|
||||
Show = true;
|
||||
}
|
||||
|
||||
public Model(UObject owner, string name, string type, CBaseMeshLod lod, CMeshVertex[] vertices, FPackageIndex[] morphTargets = null, List<CSkelMeshBone> skeleton = null, Transform transform = null)
|
||||
: this(owner, name, type)
|
||||
public Model(string name, string type, CStaticMesh staticMesh) : this(name, type, staticMesh.LODs[0], staticMesh.LODs[0].Verts) {}
|
||||
public Model(string name, string type, CStaticMesh staticMesh, Transform transform) : this(name, type, staticMesh.LODs[0], staticMesh.LODs[0].Verts, null, transform) {}
|
||||
public Model(string name, string type, CSkeletalMesh skeletalMesh) : this(name, type, skeletalMesh.LODs[0], skeletalMesh.LODs[0].Verts, skeletalMesh.RefSkeleton) {}
|
||||
public Model(string name, string type, FPackageIndex[] morphTargets, CSkeletalMesh skeletalMesh) : this(name, type, skeletalMesh)
|
||||
{
|
||||
HasVertexColors = lod.VertexColors != null;
|
||||
if (HasVertexColors) _vertexSize += 4; // + Color
|
||||
if (morphTargets is not { Length: > 0 })
|
||||
return;
|
||||
|
||||
Skeleton = skeleton;
|
||||
HasBones = Skeleton != null;
|
||||
if (HasBones) _vertexSize += 8; // + BoneIds + BoneWeights
|
||||
HasMorphTargets = true;
|
||||
Morphs = new Morph[morphTargets.Length];
|
||||
for (var i = 0; i < Morphs.Length; i++)
|
||||
{
|
||||
Morphs[i] = new Morph(Vertices, _vertexSize, morphTargets[i].Load<UMorphTarget>());
|
||||
}
|
||||
}
|
||||
|
||||
public Model(string name, string type, CBaseMeshLod lod, CMeshVertex[] vertices, List<CSkelMeshBone> skeleton = null, Transform transform = null) : this(name, type)
|
||||
{
|
||||
if (lod.VertexColors is { Length: > 0})
|
||||
{
|
||||
HasVertexColors = true;
|
||||
_vertexSize += 4; // + Color
|
||||
}
|
||||
|
||||
if (skeleton is { Count: > 0 })
|
||||
{
|
||||
HasBones = true;
|
||||
Skeleton = skeleton;
|
||||
_vertexSize += 8; // + BoneIds + BoneWeights
|
||||
}
|
||||
|
||||
var sections = lod.Sections.Value;
|
||||
Sections = new Section[sections.Length];
|
||||
|
|
@ -122,16 +140,6 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
HasMorphTargets = morphTargets != null;
|
||||
if (HasMorphTargets)
|
||||
{
|
||||
Morphs = new Morph[morphTargets.Length];
|
||||
for (var i = 0; i < Morphs.Length; i++)
|
||||
{
|
||||
Morphs[i] = new Morph(Vertices, _vertexSize, morphTargets[i].Load<UMorphTarget>());
|
||||
}
|
||||
}
|
||||
|
||||
AddInstance(transform ?? Transform.Identity);
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +203,7 @@ public class Model : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void Bind(Shader shader)
|
||||
public void Render(Shader shader)
|
||||
{
|
||||
if (IsSelected)
|
||||
{
|
||||
|
|
@ -208,7 +216,7 @@ public class Model : IDisposable
|
|||
shader.SetUniform("display_vertex_colors", DisplayVertexColors);
|
||||
for (int section = 0; section < Sections.Length; section++)
|
||||
{
|
||||
Sections[section].Bind(shader, TransformsCount);
|
||||
Sections[section].Render(shader, TransformsCount);
|
||||
}
|
||||
_vao.Unbind();
|
||||
|
||||
|
|
|
|||
239
FModel/Views/Snooper/Renderer.cs
Normal file
239
FModel/Views/Snooper/Renderer.cs
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using CUE4Parse_Conversion.Meshes;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.SkeletalMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.StaticMesh;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse.UE4.Objects.Core.Math;
|
||||
using CUE4Parse.UE4.Objects.Engine;
|
||||
using CUE4Parse.UE4.Objects.UObject;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class Renderer : IDisposable
|
||||
{
|
||||
private Shader _shader;
|
||||
private Shader _outline;
|
||||
private Vector3 _diffuseLight;
|
||||
private Vector3 _specularLight;
|
||||
|
||||
public Cache Cache { get; }
|
||||
public Options Settings { get; }
|
||||
|
||||
public Renderer()
|
||||
{
|
||||
Cache = new Cache();
|
||||
Settings = new Options();
|
||||
}
|
||||
|
||||
public void Load(CancellationToken cancellationToken, UObject export)
|
||||
{
|
||||
switch (export)
|
||||
{
|
||||
case UStaticMesh st:
|
||||
{
|
||||
LoadStaticMesh(st);
|
||||
break;
|
||||
}
|
||||
case USkeletalMesh sk:
|
||||
{
|
||||
LoadSkeletalMesh(sk);
|
||||
break;
|
||||
}
|
||||
case UMaterialInstance mi:
|
||||
{
|
||||
LoadMaterialInstance(mi);
|
||||
break;
|
||||
}
|
||||
case UWorld wd:
|
||||
{
|
||||
LoadWorld(cancellationToken, wd);
|
||||
// _camera = new Camera(new Vector3(0f, 5f, 5f), Vector3.Zero, 0.01f, 1000f, 5f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(export));
|
||||
}
|
||||
}
|
||||
|
||||
public void Swap(UMaterialInstance unrealMaterial)
|
||||
{
|
||||
if (!Cache.TryGetModel(Settings.SelectedModel, out var model) ||
|
||||
!Settings.TryGetSection(model, out var section)) return;
|
||||
|
||||
section.SwapMaterial(unrealMaterial);
|
||||
Settings.SwapMaterial(false);
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
{
|
||||
_shader = new Shader();
|
||||
_outline = new Shader("outline");
|
||||
_diffuseLight = new Vector3(0.75f);
|
||||
_specularLight = new Vector3(0.5f);
|
||||
|
||||
Cache.Setup();
|
||||
}
|
||||
|
||||
public void Render(Camera cam)
|
||||
{
|
||||
var viewMatrix = cam.GetViewMatrix();
|
||||
var projMatrix = cam.GetProjectionMatrix();
|
||||
|
||||
_outline.Use();
|
||||
_outline.SetUniform("uView", viewMatrix);
|
||||
_outline.SetUniform("uProjection", projMatrix);
|
||||
_outline.SetUniform("viewPos", cam.Position);
|
||||
|
||||
_shader.Use();
|
||||
_shader.SetUniform("uView", viewMatrix);
|
||||
_shader.SetUniform("uProjection", projMatrix);
|
||||
_shader.SetUniform("viewPos", cam.Position);
|
||||
|
||||
_shader.SetUniform("material.diffuseMap", 0);
|
||||
_shader.SetUniform("material.normalMap", 1);
|
||||
_shader.SetUniform("material.specularMap", 2);
|
||||
_shader.SetUniform("material.emissionMap", 3);
|
||||
|
||||
_shader.SetUniform("light.position", cam.Position);
|
||||
_shader.SetUniform("light.diffuse", _diffuseLight);
|
||||
_shader.SetUniform("light.specular", _specularLight);
|
||||
|
||||
Cache.Render(_shader);
|
||||
GL.Enable(EnableCap.StencilTest); // I don't get why this must be here but it works now so...
|
||||
Cache.Outline(_outline);
|
||||
}
|
||||
|
||||
// private void SetupCamera(FBox box)
|
||||
// {
|
||||
// var far = box.Max.Max();
|
||||
// var center = box.GetCenter();
|
||||
// var position = new Vector3(0f, center.Z, box.Max.Y * 3);
|
||||
// var speed = far / 2f;
|
||||
// if (speed > _previousSpeed)
|
||||
// {
|
||||
// _camera = new Camera(position, center, 0.01f, far * 50f, speed);
|
||||
// _previousSpeed = _camera.Speed;
|
||||
// }
|
||||
// }
|
||||
|
||||
private void LoadStaticMesh(UStaticMesh original)
|
||||
{
|
||||
var guid = original.LightingGuid;
|
||||
if (Cache.TryGetModel(guid, out var model))
|
||||
{
|
||||
model.AddInstance(Transform.Identity);
|
||||
}
|
||||
else if (original.TryConvert(out var mesh))
|
||||
{
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, mesh));
|
||||
// SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
Settings.SelectModel(guid);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadSkeletalMesh(USkeletalMesh original)
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
if (Cache.HasModel(guid) || !original.TryConvert(out var mesh)) return;
|
||||
|
||||
Cache.AddModel(guid, new Model(original.Name, original.ExportType, original.MorphTargets, mesh));
|
||||
// SetupCamera(mesh.BoundingBox *= Constants.SCALE_DOWN_RATIO);
|
||||
Settings.SelectModel(guid);
|
||||
}
|
||||
|
||||
private void LoadMaterialInstance(UMaterialInstance original)
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
if (Cache.HasModel(guid)) return;
|
||||
|
||||
Cache.AddModel(guid, new Cube(original));
|
||||
// SetupCamera(new FBox(new FVector(-.65f), new FVector(.65f)));
|
||||
Settings.SelectModel(guid);
|
||||
}
|
||||
|
||||
private void LoadWorld(CancellationToken cancellationToken, UWorld original)
|
||||
{
|
||||
if (original.PersistentLevel.Load<ULevel>() is not { } persistentLevel)
|
||||
return;
|
||||
|
||||
var length = persistentLevel.Actors.Length;
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (persistentLevel.Actors[i].Load() is not { } actor ||actor.ExportType == "LODActor" ||
|
||||
!actor.TryGetValue(out FPackageIndex staticMeshComponent, "StaticMeshComponent") ||
|
||||
staticMeshComponent.Load() is not { } staticMeshComp) continue;
|
||||
|
||||
if (!staticMeshComp.TryGetValue(out FPackageIndex staticMesh, "StaticMesh") && actor.Class is UBlueprintGeneratedClass)
|
||||
foreach (var actorExp in actor.Class.Owner.GetExports())
|
||||
if (actorExp.TryGetValue(out staticMesh, "StaticMesh"))
|
||||
break;
|
||||
if (staticMesh?.Load() is not UStaticMesh m)
|
||||
continue;
|
||||
|
||||
Services.ApplicationService.ApplicationView.Status.UpdateStatusLabel($"Actor {i}/{length}");
|
||||
|
||||
var guid = m.LightingGuid;
|
||||
var transform = new Transform
|
||||
{
|
||||
Position = staticMeshComp.GetOrDefault("RelativeLocation", FVector.ZeroVector) * Constants.SCALE_DOWN_RATIO,
|
||||
Rotation = staticMeshComp.GetOrDefault("RelativeRotation", FRotator.ZeroRotator),
|
||||
Scale = staticMeshComp.GetOrDefault("RelativeScale3D", FVector.OneVector)
|
||||
};
|
||||
transform.Rotation.Yaw = -transform.Rotation.Yaw;
|
||||
|
||||
if (Cache.TryGetModel(guid, out var model))
|
||||
{
|
||||
model.AddInstance(transform);
|
||||
}
|
||||
else if (m.TryConvert(out var mesh))
|
||||
{
|
||||
model = new Model(m.Name, m.ExportType, mesh, transform);
|
||||
|
||||
if (actor.TryGetAllValues(out FPackageIndex[] textureData, "TextureData"))
|
||||
{
|
||||
for (int j = 0; j < textureData.Length; j++)
|
||||
{
|
||||
if (textureData[j].Load() is not { } textureDataIdx)
|
||||
continue;
|
||||
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex diffuse, "Diffuse") &&
|
||||
diffuse.Load() is UTexture2D diffuseTexture)
|
||||
model.Sections[j].Parameters.Diffuse = diffuseTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex normal, "Normal") &&
|
||||
normal.Load() is UTexture2D normalTexture)
|
||||
model.Sections[j].Parameters.Normal = normalTexture;
|
||||
if (textureDataIdx.TryGetValue(out FPackageIndex specular, "Specular") &&
|
||||
specular.Load() is UTexture2D specularTexture)
|
||||
model.Sections[j].Parameters.Specular = specularTexture;
|
||||
}
|
||||
}
|
||||
if (staticMeshComp.TryGetValue(out FPackageIndex[] overrideMaterials, "OverrideMaterials"))
|
||||
{
|
||||
var max = model.Sections.Length - 1;
|
||||
for (var j = 0; j < overrideMaterials.Length; j++)
|
||||
{
|
||||
if (j > max) break;
|
||||
if (overrideMaterials[j].Load() is not UMaterialInterface unrealMaterial) continue;
|
||||
model.Sections[j].SwapMaterial(unrealMaterial);
|
||||
}
|
||||
}
|
||||
|
||||
Cache.AddModel(guid, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_shader.Dispose();
|
||||
_outline.Dispose();
|
||||
Cache.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using CUE4Parse.UE4.Assets.Exports.Texture;
|
||||
using CUE4Parse_Conversion.Meshes.PSK;
|
||||
|
|
@ -7,6 +6,7 @@ using CUE4Parse_Conversion.Textures;
|
|||
using FModel.Services;
|
||||
using FModel.Settings;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
|
@ -229,7 +229,7 @@ public class Section : IDisposable
|
|||
Parameters.RoughnessValue = 0;
|
||||
}
|
||||
|
||||
public void Bind(Shader shader, int instanceCount)
|
||||
public void Render(Shader shader, int instanceCount)
|
||||
{
|
||||
for (var i = 0; i < Textures.Length; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
using System.Reflection;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
|
|
@ -50,7 +50,7 @@ public class Shader : IDisposable
|
|||
GL.Uniform1(location, value);
|
||||
}
|
||||
|
||||
public unsafe void SetUniform(string name, Matrix4x4 value)
|
||||
public unsafe void SetUniform(string name, Matrix4 value)
|
||||
{
|
||||
//A new overload has been created for setting a uniform so we can use the transform in our shader.
|
||||
int location = GL.GetUniformLocation(_handle, name);
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ public class Skybox : IDisposable
|
|||
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 3, 0); // position
|
||||
}
|
||||
|
||||
public void Bind(Camera camera)
|
||||
public void Render(Camera camera)
|
||||
{
|
||||
GL.DepthFunc(DepthFunction.Lequal);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,41 +1,148 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using CUE4Parse.UE4.Assets.Exports;
|
||||
using CUE4Parse.UE4.Assets.Exports.Material;
|
||||
using OpenTK.Graphics.OpenGL4;
|
||||
using OpenTK.Mathematics;
|
||||
using OpenTK.Windowing.Common;
|
||||
using OpenTK.Windowing.Desktop;
|
||||
using OpenTK.Windowing.GraphicsLibraryFramework;
|
||||
|
||||
namespace FModel.Views.Snooper;
|
||||
|
||||
public class Snooper
|
||||
public class Snooper : GameWindow
|
||||
{
|
||||
private readonly FWindow _window;
|
||||
// private readonly FramebufferObject _framebuffer;
|
||||
private readonly Skybox _skybox;
|
||||
private readonly Grid _grid;
|
||||
private readonly Renderer _renderer;
|
||||
|
||||
public Snooper()
|
||||
private Camera _camera;
|
||||
private float _previousSpeed;
|
||||
|
||||
public Snooper(GameWindowSettings gwSettings, NativeWindowSettings nwSettings) : base(gwSettings, nwSettings)
|
||||
{
|
||||
const double ratio = .7;
|
||||
var x = SystemParameters.MaximizedPrimaryScreenWidth;
|
||||
var y = SystemParameters.MaximizedPrimaryScreenHeight;
|
||||
|
||||
var options = NativeWindowSettings.Default;
|
||||
options.Size = new Vector2i(Convert.ToInt32(x * ratio), Convert.ToInt32(y * ratio));
|
||||
options.WindowBorder = WindowBorder.Fixed;
|
||||
options.Location = new Vector2i(Convert.ToInt32(x / 2.0) / (options.Size.X / 2), Convert.ToInt32(y / 2.0) / (options.Size.Y / 2));
|
||||
options.NumberOfSamples = Constants.SAMPLES_COUNT;
|
||||
options.Title = "Snooper";
|
||||
|
||||
_window = new FWindow(GameWindowSettings.Default, options);
|
||||
// _framebuffer = new FramebufferObject(Size);
|
||||
_skybox = new Skybox();
|
||||
_grid = new Grid();
|
||||
_renderer = new Renderer();
|
||||
}
|
||||
|
||||
public void Run(CancellationToken cancellationToken, UObject export)
|
||||
public void SwapMaterial(UMaterialInstance mi) => _renderer.Swap(mi);
|
||||
public void LoadExport(CancellationToken cancellationToken, UObject export)
|
||||
{
|
||||
_window.Run(cancellationToken, export);
|
||||
_renderer.Load(cancellationToken, export);
|
||||
_camera = new Camera(new Vector3(0f, 5f, 5f), Vector3.Zero, 0.01f, 1000f, 5f);
|
||||
}
|
||||
|
||||
public void SwapMaterial(UMaterialInstance mi)
|
||||
private unsafe void WindowShouldClose(bool value)
|
||||
{
|
||||
_window.SwapMaterial(mi);
|
||||
GLFW.SetWindowShouldClose(WindowPtr, value); // start / stop game loop
|
||||
CursorState = value ? CursorState.Normal : CursorState.Grabbed;
|
||||
IsVisible = !value;
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(delegate
|
||||
{
|
||||
WindowShouldClose(false);
|
||||
base.Run();
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnLoad()
|
||||
{
|
||||
base.OnLoad();
|
||||
|
||||
GL.ClearColor(Color4.Red);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
GL.Enable(EnableCap.DepthTest);
|
||||
GL.Enable(EnableCap.Multisample);
|
||||
GL.StencilOp(StencilOp.Keep, StencilOp.Replace, StencilOp.Replace);
|
||||
GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
|
||||
|
||||
// _framebuffer.Setup();
|
||||
_skybox.Setup();
|
||||
_grid.Setup();
|
||||
_renderer.Setup();
|
||||
}
|
||||
|
||||
protected override void OnRenderFrame(FrameEventArgs args)
|
||||
{
|
||||
base.OnRenderFrame(args);
|
||||
if (!IsVisible)
|
||||
return;
|
||||
|
||||
ClearWhatHasBeenDrawn(); // in main window
|
||||
|
||||
// _framebuffer.Bind(); // switch to dedicated window
|
||||
// ClearWhatHasBeenDrawn(); // in dedicated window
|
||||
|
||||
_skybox.Render(_camera);
|
||||
_grid.Render(_camera);
|
||||
_renderer.Render(_camera);
|
||||
|
||||
// _framebuffer.BindMsaa();
|
||||
// _framebuffer.Bind(0); // switch back to main window
|
||||
// _framebuffer.BindStuff();
|
||||
|
||||
SwapBuffers();
|
||||
}
|
||||
|
||||
private void ClearWhatHasBeenDrawn()
|
||||
{
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit | ClearBufferMask.StencilBufferBit);
|
||||
GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseMoveEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
if (!IsFocused)
|
||||
return;
|
||||
|
||||
const float lookSensitivity = 0.1f;
|
||||
var delta = e.Delta * lookSensitivity;
|
||||
_camera.ModifyDirection(delta.X, delta.Y);
|
||||
}
|
||||
|
||||
protected override void OnUpdateFrame(FrameEventArgs e)
|
||||
{
|
||||
base.OnUpdateFrame(e);
|
||||
if (!IsFocused)
|
||||
return;
|
||||
|
||||
var multiplier = KeyboardState.IsKeyDown(Keys.LeftShift) ? 2f : 1f;
|
||||
var moveSpeed = _camera.Speed * multiplier * (float) e.Time;
|
||||
if (KeyboardState.IsKeyDown(Keys.W))
|
||||
_camera.Position += moveSpeed * _camera.Direction;
|
||||
if (KeyboardState.IsKeyDown(Keys.S))
|
||||
_camera.Position -= moveSpeed * _camera.Direction;
|
||||
if (KeyboardState.IsKeyDown(Keys.A))
|
||||
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
if (KeyboardState.IsKeyDown(Keys.D))
|
||||
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
|
||||
if (KeyboardState.IsKeyDown(Keys.E))
|
||||
_camera.Position += moveSpeed * _camera.Up;
|
||||
if (KeyboardState.IsKeyDown(Keys.Q))
|
||||
_camera.Position -= moveSpeed * _camera.Up;
|
||||
if (KeyboardState.IsKeyDown(Keys.X))
|
||||
_camera.ModifyZoom(-.5f);
|
||||
if (KeyboardState.IsKeyDown(Keys.C))
|
||||
_camera.ModifyZoom(+.5f);
|
||||
|
||||
if (KeyboardState.IsKeyPressed(Keys.H))
|
||||
IsVisible = false;
|
||||
if (KeyboardState.IsKeyPressed(Keys.Escape))
|
||||
WindowShouldClose(true);
|
||||
}
|
||||
|
||||
protected override void OnResize(ResizeEventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
|
||||
GL.Viewport(0, 0, Size.X, Size.Y);
|
||||
// _camera.AspectRatio = Size.X / (float)Size.Y;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user