This commit is contained in:
4sval
2022-10-12 02:18:54 +02:00
parent d047b56978
commit e3e5689fce
17 changed files with 641 additions and 689 deletions

View File

@@ -10,7 +10,7 @@ public static class Constants
public static readonly FGuid ZERO_GUID = new(0U);
public const float SCALE_DOWN_RATIO = 0.01F;
public const uint SAMPLES_COUNT = 4;
public const int SAMPLES_COUNT = 4;
public const string WHITE = "#DAE5F2";
public const string GRAY = "#BBBBBB";

View File

@@ -103,10 +103,6 @@
<None Remove="Resources\framebuffer.vert" />
<None Remove="Resources\outline.frag" />
<None Remove="Resources\outline.vert" />
<None Update="glfw3.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>True</ExcludeFromSingleFile>
</None>
</ItemGroup>
<ItemGroup>
@@ -141,14 +137,10 @@
<PackageReference Include="NVorbis" Version="0.10.4" />
<PackageReference Include="Oodle.NET" Version="1.0.1" />
<PackageReference Include="Ookii.Dialogs.Wpf" Version="5.0.1" />
<PackageReference Include="OpenTK" Version="4.7.5" />
<PackageReference Include="RestSharp" Version="108.0.1" />
<PackageReference Include="Serilog" Version="2.11.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Silk.NET.Input" Version="2.16.0" />
<PackageReference Include="Silk.NET.Input.Extensions" Version="2.16.0" />
<PackageReference Include="Silk.NET.OpenGL" Version="2.16.0" />
<PackageReference Include="Silk.NET.OpenGL.Extensions.ImGui" Version="2.16.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
<PackageReference Include="SkiaSharp.HarfBuzz" Version="2.88.0" />
<PackageReference Include="SkiaSharp.Svg" Version="1.60.0" />
</ItemGroup>

View File

@@ -1,56 +1,48 @@
using System;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class BufferObject<TDataType> : IDisposable where TDataType : unmanaged
{
private uint _handle;
private BufferTargetARB _bufferType;
private GL _gl;
private readonly int _handle;
private readonly BufferTarget _bufferTarget;
public BufferObject(GL gl, BufferTargetARB bufferType)
private BufferObject(BufferTarget bufferTarget)
{
_gl = gl;
_bufferType = bufferType;
_bufferTarget = bufferTarget;
_handle = GL.GenBuffer();
_handle = _gl.GenBuffer();
Bind();
}
public unsafe BufferObject(GL gl, Span<TDataType> data, BufferTargetARB bufferType) : this(gl, bufferType)
public unsafe BufferObject(TDataType[] data, BufferTarget bufferTarget) : this(bufferTarget)
{
fixed (void* d = data)
{
_gl.BufferData(bufferType, (nuint) (data.Length * sizeof(TDataType)), d, BufferUsageARB.StaticDraw);
}
GL.BufferData(bufferTarget, data.Length * sizeof(TDataType), data, BufferUsageHint.StaticDraw);
}
public unsafe void Update(int offset, TDataType data)
{
_gl.BufferSubData(_bufferType, offset * sizeof(TDataType), (nuint) sizeof(TDataType), data);
GL.BufferSubData(_bufferTarget, (IntPtr) (offset * sizeof(TDataType)), sizeof(TDataType), ref data);
}
public unsafe void Update(Span<TDataType> data)
public unsafe void Update(TDataType[] data)
{
fixed (void* d = data)
{
_gl.BufferSubData(_bufferType, 0, (nuint) (data.Length * sizeof(TDataType)), d);
}
GL.BufferSubData(_bufferTarget, IntPtr.Zero, data.Length * sizeof(TDataType), data);
}
public void Bind()
{
_gl.BindBuffer(_bufferType, _handle);
GL.BindBuffer(_bufferTarget, _handle);
}
public void Unbind()
{
_gl.BindBuffer(_bufferType, 0);
GL.BindBuffer(_bufferTarget, 0);
}
public void Dispose()
{
_gl.DeleteBuffer(_handle);
GL.DeleteBuffer(_handle);
}
}

View File

@@ -63,7 +63,7 @@ public class Cube : Model
};
Sections = new Section[1];
Sections[0] = new Section(0, (uint) Indices.Length, 0, unrealMaterial);
Sections[0] = new Section(0, Indices.Length, 0, unrealMaterial);
AddInstance(Transform.Identity);
}

View File

@@ -0,0 +1,381 @@
using System;
using System.Collections.Generic;
using System.Linq;
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.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
using OpenTK.Windowing.GraphicsLibraryFramework;
namespace FModel.Views.Snooper;
public class FWindow : GameWindow
{
private SnimGui _imGui;
private Camera _camera;
private IMouse _mouse;
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));
}
DoLoop();
}
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);
DoLoop();
}
private void DoLoop()
{
if (_options.Append) _options.Append = false;
_window.Run();
// 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();
_window.SetWindowIcon(ref _icon);
_window.Center();
var input = _window.CreateInput();
_keyboard = input.Keyboards[0];
_mouse = input.Mice[0];
_gl = GL.GetApi(_window);
_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);
_imGui = new SnimGui(_gl, _window, input);
_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);
_imGui.Update((float) args.Time);
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);
}
_imGui.Construct(ref _options, _size, _framebuffer, _camera, _mouse, _models);
_framebuffer.BindMsaa();
_framebuffer.Bind(0); // switch back to main window
_framebuffer.BindStuff();
_imGui.Render(); // render ImGui in main window
SwapBuffers();
}
private void ClearWhatHasBeenDrawn()
{
GL.ClearColor(1.0f, 0.102f, 0.129f, 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 || ImGui.GetIO().WantTextInput)
return;
var multiplier = KeyboardState.IsKeyPressed(Keys.LeftShift) ? 2f : 1f;
var moveSpeed = _camera.Speed * multiplier * (float) e.Time;
if (KeyboardState.IsKeyPressed(Keys.W))
_camera.Position += moveSpeed * _camera.Direction;
if (KeyboardState.IsKeyPressed(Keys.S))
_camera.Position -= moveSpeed * _camera.Direction;
if (KeyboardState.IsKeyPressed(Keys.A))
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyPressed(Keys.D))
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (KeyboardState.IsKeyPressed(Keys.E))
_camera.Position += moveSpeed * _camera.Up;
if (KeyboardState.IsKeyPressed(Keys.Q))
_camera.Position -= moveSpeed * _camera.Up;
if (KeyboardState.IsKeyPressed(Keys.X))
_camera.ModifyZoom(-.5f);
if (KeyboardState.IsKeyPressed(Keys.C))
_camera.ModifyZoom(+.5f);
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;
}
_imGui.Dispose();
_window.Dispose();
_gl.Dispose();
}
protected override void OnResize(ResizeEventArgs e)
{
base.OnResize(e);
GL.Viewport(0, 0, Size.X, Size.Y);
_camera.AspectRatio = Size.X / (float)Size.Y;
}
}

View File

@@ -1,14 +1,13 @@
using System;
using Silk.NET.Maths;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
using OpenTK.Mathematics;
namespace FModel.Views.Snooper;
public class FramebufferObject : IDisposable
{
private uint _framebufferHandle;
private uint _postProcessingHandle;
private GL _gl;
private int _framebufferHandle;
private int _postProcessingHandle;
private readonly int _width;
private readonly int _height;
@@ -34,77 +33,75 @@ public class FramebufferObject : IDisposable
-1.0f, 1.0f, 0.0f, 1.0f
};
public FramebufferObject(Vector2D<int> size)
public FramebufferObject(Vector2i size)
{
_width = size.X;
_height = size.Y;
_renderbuffer = new RenderbufferObject((uint) _width, (uint) _height);
_renderbuffer = new RenderbufferObject(_width, _height);
}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_framebufferHandle = _gl.GenFramebuffer();
_framebufferHandle = GL.GenFramebuffer();
Bind(_framebufferHandle);
_framebufferTexture = new Texture(_gl, (uint) _width, (uint) _height);
_framebufferTexture = new Texture((uint) _width, (uint) _height);
_renderbuffer.Setup(gl);
_renderbuffer.Setup();
_shader = new Shader(_gl, "framebuffer");
_shader = new Shader("framebuffer");
_shader.Use();
_shader.SetUniform("screenTexture", 0);
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
_ebo = new BufferObject<uint>(Indices, BufferTarget.ElementArrayBuffer);
_vbo = new BufferObject<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_vbo, _ebo);
_vao.VertexAttributePointer(0, 2, VertexAttribPointerType.Float, 4, 0); // position
_vao.VertexAttributePointer(1, 2, VertexAttribPointerType.Float, 4, 2); // uv
var status = _gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (status != GLEnum.FramebufferComplete)
var status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (status != FramebufferErrorCode.FramebufferComplete)
{
throw new Exception($"Framebuffer failed to bind with error: {_gl.GetProgramInfoLog(_framebufferHandle)}");
throw new Exception($"Framebuffer failed to bind with error: {GL.GetProgramInfoLog(_framebufferHandle)}");
}
_postProcessingHandle = _gl.GenFramebuffer();
_postProcessingHandle = GL.GenFramebuffer();
Bind(_postProcessingHandle);
_postProcessingTexture = new Texture(_gl, _width, _height);
_postProcessingTexture = new Texture(_width, _height);
status = _gl.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (status != GLEnum.FramebufferComplete)
status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (status != FramebufferErrorCode.FramebufferComplete)
{
throw new Exception($"Post-Processing framebuffer failed to bind with error: {_gl.GetProgramInfoLog(_postProcessingHandle)}");
throw new Exception($"Post-Processing framebuffer failed to bind with error: {GL.GetProgramInfoLog(_postProcessingHandle)}");
}
}
public void Bind() => Bind(_framebufferHandle);
public void Bind(uint handle)
public void Bind(int handle)
{
_gl.BindFramebuffer(FramebufferTarget.Framebuffer, handle);
GL.BindFramebuffer(FramebufferTarget.Framebuffer, handle);
}
public void BindMsaa()
{
_gl.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _framebufferHandle);
_gl.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _postProcessingHandle);
_gl.BlitFramebuffer(0, 0, _width, _height, 0, 0, _width, _height, ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
GL.BindFramebuffer(FramebufferTarget.ReadFramebuffer, _framebufferHandle);
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, _postProcessingHandle);
GL.BlitFramebuffer(0, 0, _width, _height, 0, 0, _width, _height, ClearBufferMask.ColorBufferBit, BlitFramebufferFilter.Nearest);
}
public void BindStuff()
{
_gl.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.DepthTest);
_shader.Use();
_vao.Bind();
_postProcessingTexture.Bind(TextureUnit.Texture0);
_gl.DrawArrays(PrimitiveType.Triangles, 0, (uint) Indices.Length);
_gl.Enable(EnableCap.DepthTest);
GL.DrawArrays(PrimitiveType.Triangles, 0, Indices.Length);
GL.Enable(EnableCap.DepthTest);
}
public IntPtr GetPointer() => _postProcessingTexture.GetPointer();
@@ -116,7 +113,7 @@ public class FramebufferObject : IDisposable
_framebufferTexture.Dispose();
_postProcessingTexture.Dispose();
_renderbuffer.Dispose();
_gl.DeleteFramebuffer(_framebufferHandle);
_gl.DeleteFramebuffer(_postProcessingHandle);
GL.DeleteFramebuffer(_framebufferHandle);
GL.DeleteFramebuffer(_postProcessingHandle);
}
}

View File

@@ -1,12 +1,11 @@
using System;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class Grid : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private BufferObject<uint> _ebo;
private BufferObject<float> _vbo;
@@ -26,24 +25,22 @@ public class Grid : IDisposable
public Grid() {}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = GL.CreateProgram();
_handle = _gl.CreateProgram();
_ebo = new BufferObject<uint>(Indices, BufferTarget.ElementArrayBuffer);
_vbo = new BufferObject<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_vbo, _ebo);
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
_shader = new Shader(_gl, "grid");
_shader = new Shader("grid");
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 3, 0); // position
}
public void Bind(Camera camera)
{
_gl.Disable(EnableCap.DepthTest);
GL.Disable(EnableCap.DepthTest);
_vao.Bind();
_shader.Use();
@@ -53,8 +50,8 @@ public class Grid : IDisposable
_shader.SetUniform("uNear", camera.Near);
_shader.SetUniform("uFar", camera.Far);
_gl.DrawArrays(PrimitiveType.Triangles, 0, (uint) Indices.Length);
_gl.Enable(EnableCap.DepthTest);
GL.DrawArrays(PrimitiveType.Triangles, 0, Indices.Length);
GL.Enable(EnableCap.DepthTest);
}
public void Dispose()
@@ -63,6 +60,6 @@ public class Grid : IDisposable
_vbo.Dispose();
_vao.Dispose();
_shader.Dispose();
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
}

View File

@@ -4,17 +4,15 @@ using System.Linq;
using System.Numerics;
using CUE4Parse.UE4.Assets.Exports;
using CUE4Parse.UE4.Assets.Exports.Animation;
using CUE4Parse.UE4.Objects.Engine;
using CUE4Parse.UE4.Objects.UObject;
using CUE4Parse_Conversion.Meshes.PSK;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class Model : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private BufferObject<uint> _ebo;
private BufferObject<float> _vbo;
@@ -22,9 +20,9 @@ public class Model : IDisposable
private BufferObject<Matrix4x4> _matrixVbo;
private VertexArrayObject<float, uint> _vao;
private uint _vertexSize = 9; // VertexIndex + Position + Normal + UV
private const uint _faceSize = 3; // just so we don't have to do .Length
private readonly int _vertexSize = 9; // VertexIndex + Position + Normal + UV
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;
@@ -43,7 +41,6 @@ public class Model : IDisposable
public bool Show;
public bool IsSelected;
public bool IsSavable;
public bool DisplayVertexColors;
public bool DisplayBones;
public float MorphTime;
@@ -55,7 +52,6 @@ public class Model : IDisposable
Type = type;
Transforms = new List<Transform>();
Show = true;
IsSavable = owner is not UWorld;
}
public Model(UObject owner, string name, string type, CBaseMeshLod lod, CMeshVertex[] vertices, FPackageIndex[] morphTargets = null, List<CSkelMeshBone> skeleton = null, Transform transform = null)
@@ -76,7 +72,7 @@ public class Model : IDisposable
for (var s = 0; s < sections.Length; s++)
{
var section = sections[s];
Sections[s] = new Section(section.MaterialName, section.MaterialIndex, (uint) section.NumFaces * _faceSize, section.FirstIndex, section);
Sections[s] = new Section(section.MaterialName, section.MaterialIndex, section.NumFaces * _faceSize, section.FirstIndex, section);
for (uint face = 0; face < section.NumFaces; face++)
{
foreach (var f in _facesIndex)
@@ -155,15 +151,13 @@ public class Model : IDisposable
_morphVbo.Unbind();
}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = GL.CreateProgram();
_handle = _gl.CreateProgram();
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
_ebo = new BufferObject<uint>(Indices, BufferTarget.ElementArrayBuffer);
_vbo = new BufferObject<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_vbo, _ebo);
_vao.VertexAttributePointer(0, 1, VertexAttribPointerType.Int, _vertexSize, 0); // vertex index
_vao.VertexAttributePointer(1, 3, VertexAttribPointerType.Float, _vertexSize, 1); // position
@@ -178,7 +172,7 @@ public class Model : IDisposable
var instanceMatrix = new Matrix4x4[TransformsCount];
for (var i = 0; i < instanceMatrix.Length; i++)
instanceMatrix[i] = Transforms[i].Matrix;
_matrixVbo = new BufferObject<Matrix4x4>(_gl, instanceMatrix, BufferTargetARB.ArrayBuffer);
_matrixVbo = new BufferObject<Matrix4x4>(instanceMatrix, BufferTarget.ArrayBuffer);
_vao.BindInstancing(); // VertexAttributePointer 7, 8, 9, 10
}
@@ -186,9 +180,9 @@ public class Model : IDisposable
{
for (uint morph = 0; morph < Morphs.Length; morph++)
{
Morphs[morph].Setup(gl);
Morphs[morph].Setup();
if (morph == 0)
_morphVbo = new BufferObject<float>(_gl, Morphs[morph].Vertices, BufferTargetARB.ArrayBuffer);
_morphVbo = new BufferObject<float>(Morphs[morph].Vertices, BufferTarget.ArrayBuffer);
}
_vao.Bind();
_vao.VertexAttributePointer(11, 3, VertexAttribPointerType.Float, 3, 0); // morph position
@@ -197,7 +191,7 @@ public class Model : IDisposable
for (int section = 0; section < Sections.Length; section++)
{
Sections[section].Setup(_gl);
Sections[section].Setup();
}
}
@@ -205,8 +199,8 @@ public class Model : IDisposable
{
if (IsSelected)
{
_gl.Enable(EnableCap.StencilTest);
_gl.StencilFunc(StencilFunction.Always, 1, 0xFF);
GL.Enable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Always, 1, 0xFF);
}
_vao.Bind();
@@ -214,22 +208,22 @@ public class Model : IDisposable
shader.SetUniform("display_vertex_colors", DisplayVertexColors);
for (int section = 0; section < Sections.Length; section++)
{
Sections[section].Bind(shader, (uint) TransformsCount);
Sections[section].Bind(shader, TransformsCount);
}
_vao.Unbind();
if (IsSelected)
{
_gl.StencilFunc(StencilFunction.Always, 0, 0xFF);
_gl.Disable(EnableCap.StencilTest);
GL.StencilFunc(StencilFunction.Always, 0, 0xFF);
GL.Disable(EnableCap.StencilTest);
}
}
public void Outline(Shader shader)
{
_gl.StencilMask(0x00);
_gl.Disable(EnableCap.DepthTest);
_gl.StencilFunc(StencilFunction.Notequal, 1, 0xFF);
GL.StencilMask(0x00);
GL.Disable(EnableCap.DepthTest);
GL.StencilFunc(StencilFunction.Notequal, 1, 0xFF);
_vao.Bind();
shader.Use();
@@ -237,13 +231,13 @@ public class Model : IDisposable
for (int section = 0; section < Sections.Length; section++)
{
if (!Sections[section].Show) continue;
_gl.DrawArraysInstanced(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount, (uint) TransformsCount);
GL.DrawArraysInstanced(PrimitiveType.Triangles, Sections[section].FirstFaceIndex, Sections[section].FacesCount, TransformsCount);
}
_vao.Unbind();
_gl.StencilFunc(StencilFunction.Always, 0, 0xFF);
_gl.Enable(EnableCap.DepthTest);
_gl.StencilMask(0xFF);
GL.StencilFunc(StencilFunction.Always, 0, 0xFF);
GL.Enable(EnableCap.DepthTest);
GL.StencilMask(0xFF);
}
public void Dispose()
@@ -264,6 +258,6 @@ public class Model : IDisposable
{
Sections[section].Dispose();
}
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
}

View File

@@ -1,21 +1,20 @@
using System;
using CUE4Parse.UE4.Assets.Exports.Animation;
using CUE4Parse.UE4.Objects.Core.Math;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class Morph : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private uint _vertexSize = 3; // Position
private readonly int _vertexSize = 3; // Position
public readonly string Name;
public readonly float[] Vertices;
public Morph(float[] vertices, uint vertexSize, UMorphTarget morphTarget)
public Morph(float[] vertices, int vertexSize, UMorphTarget morphTarget)
{
Name = morphTarget.Name;
Vertices = new float[vertices.Length / vertexSize * _vertexSize];
@@ -34,7 +33,7 @@ public class Morph : IDisposable
return false;
}
for (uint i = 0; i < vertices.Length; i += vertexSize)
for (int i = 0; i < vertices.Length; i += vertexSize)
{
var count = 0;
var baseIndex = i / vertexSize * _vertexSize;
@@ -53,14 +52,13 @@ public class Morph : IDisposable
}
}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = _gl.CreateProgram();
_handle = GL.CreateProgram();
}
public void Dispose()
{
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
}

View File

@@ -1,34 +1,32 @@
using System;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class RenderbufferObject : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private readonly uint _width;
private readonly uint _height;
private readonly int _width;
private readonly int _height;
public RenderbufferObject(uint width, uint height)
public RenderbufferObject(int width, int height)
{
_width = width;
_height = height;
}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = _gl.GenRenderbuffer();
_handle = GL.GenRenderbuffer();
_gl.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _handle);
_gl.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, Constants.SAMPLES_COUNT, InternalFormat.Depth24Stencil8, _width, _height);
_gl.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _handle);
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, _handle);
GL.RenderbufferStorageMultisample(RenderbufferTarget.Renderbuffer, Constants.SAMPLES_COUNT, RenderbufferStorage.Depth24Stencil8, _width, _height);
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthStencilAttachment, RenderbufferTarget.Renderbuffer, _handle);
}
public void Dispose()
{
_gl.DeleteRenderbuffer(_handle);
GL.DeleteRenderbuffer(_handle);
}
}

View File

@@ -6,15 +6,14 @@ using CUE4Parse_Conversion.Meshes.PSK;
using CUE4Parse_Conversion.Textures;
using FModel.Services;
using FModel.Settings;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
using SkiaSharp;
namespace FModel.Views.Snooper;
public class Section : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private Vector3 _ambientLight;
@@ -22,7 +21,7 @@ public class Section : IDisposable
public string Name;
public readonly int Index;
public readonly uint FacesCount;
public readonly int FacesCount;
public readonly int FirstFaceIndex;
public readonly CMaterialParams Parameters;
@@ -35,7 +34,7 @@ public class Section : IDisposable
public bool HasSpecularMap;
public bool HasDiffuseColor;
private Section(string name, int index, uint facesCount, int firstFaceIndex)
private Section(string name, int index, int facesCount, int firstFaceIndex)
{
Name = name;
Index = index;
@@ -52,7 +51,7 @@ public class Section : IDisposable
_game = ApplicationService.ApplicationView.CUE4Parse.Game;
}
public Section(string name, int index, uint facesCount, int firstFaceIndex, CMeshSection section) : this(name, index, facesCount, firstFaceIndex)
public Section(string name, int index, int facesCount, int firstFaceIndex, CMeshSection section) : this(name, index, facesCount, firstFaceIndex)
{
if (section.Material != null && section.Material.TryLoad(out var material) && material is UMaterialInterface unrealMaterial)
{
@@ -60,7 +59,7 @@ public class Section : IDisposable
}
}
public Section(int index, uint facesCount, int firstFaceIndex, UMaterialInterface unrealMaterial) : this(string.Empty, index, facesCount, firstFaceIndex)
public Section(int index, int facesCount, int firstFaceIndex, UMaterialInterface unrealMaterial) : this(string.Empty, index, facesCount, firstFaceIndex)
{
SwapMaterial(unrealMaterial);
}
@@ -71,11 +70,9 @@ public class Section : IDisposable
unrealMaterial.GetParams(Parameters);
}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = _gl.CreateProgram();
_handle = GL.CreateProgram();
if (Parameters.IsNull)
{
@@ -92,21 +89,21 @@ public class Section : IDisposable
{
var mip = diffuse.GetFirstMip();
TextureDecoder.DecodeTexture(mip, diffuse.Format, diffuse.isNormalMap, platform, out var data, out var colorType);
Textures[0] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, diffuse);
Textures[0] = new Texture(data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, diffuse);
}
if (Parameters.Normal is UTexture2D { IsVirtual: false } normal)
{
var mip = normal.GetFirstMip();
TextureDecoder.DecodeTexture(mip, normal.Format, normal.isNormalMap, platform, out var data, out var colorType);
Textures[1] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, normal);
Textures[1] = new Texture(data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, normal);
}
if (Parameters.Specular is UTexture2D { IsVirtual: false } specular)
{
var mip = specular.GetFirstMip();
SwapSpecular(specular, mip, platform, out var data, out var colorType);
Textures[2] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, specular);
Textures[2] = new Texture(data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, specular);
}
if (Parameters.HasTopEmissiveTexture &&
@@ -114,7 +111,7 @@ public class Section : IDisposable
{
var mip = emissive.GetFirstMip();
TextureDecoder.DecodeTexture(mip, emissive.Format, emissive.isNormalMap, platform, out var data, out var colorType);
Textures[3] = new Texture(_gl, data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, emissive);
Textures[3] = new Texture(data, (uint) mip.SizeX, (uint) mip.SizeY, colorType, emissive);
if (Parameters.EmissiveColor is { A: > 0 } emissiveColor)
{
EmissionColor = new Vector4(emissiveColor.R, emissiveColor.G, emissiveColor.B, emissiveColor.A);
@@ -232,7 +229,7 @@ public class Section : IDisposable
Parameters.RoughnessValue = 0;
}
public void Bind(Shader shader, uint instanceCount)
public void Bind(Shader shader, int instanceCount)
{
for (var i = 0; i < Textures.Length; i++)
{
@@ -251,8 +248,8 @@ public class Section : IDisposable
shader.SetUniform("light.ambient", _ambientLight);
_gl.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
if (Show) _gl.DrawArraysInstanced(PrimitiveType.Triangles, FirstFaceIndex, FacesCount, instanceCount);
GL.PolygonMode(MaterialFace.FrontAndBack, Wireframe ? PolygonMode.Line : PolygonMode.Fill);
if (Show) GL.DrawArraysInstanced(PrimitiveType.Triangles, FirstFaceIndex, FacesCount, instanceCount);
}
public void Dispose()
@@ -261,6 +258,6 @@ public class Section : IDisposable
{
Textures[i]?.Dispose();
}
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
}

View File

@@ -3,114 +3,111 @@ using System.Collections.Generic;
using System.IO;
using System.Numerics;
using System.Reflection;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class Shader : IDisposable
{
private readonly uint _handle;
private readonly GL _gl;
private readonly int _handle;
private readonly Dictionary<string, int> _uniformToLocation = new ();
private readonly Dictionary<string, int> _attribLocation = new ();
public Shader(GL gl) : this(gl, "default") {}
public Shader() : this("default") {}
public Shader(GL gl, string name)
public Shader(string name)
{
_gl = gl;
_handle = GL.CreateProgram();
_handle = _gl.CreateProgram();
uint v = LoadShader(ShaderType.VertexShader, $"{name}.vert");
uint f = LoadShader(ShaderType.FragmentShader, $"{name}.frag");
_gl.AttachShader(_handle, v);
_gl.AttachShader(_handle, f);
_gl.LinkProgram(_handle);
_gl.GetProgram(_handle, GLEnum.LinkStatus, out var status);
var v = LoadShader(ShaderType.VertexShader, $"{name}.vert");
var f = LoadShader(ShaderType.FragmentShader, $"{name}.frag");
GL.AttachShader(_handle, v);
GL.AttachShader(_handle, f);
GL.LinkProgram(_handle);
GL.GetProgram(_handle, GetProgramParameterName.LinkStatus, out var status);
if (status == 0)
{
throw new Exception($"Program failed to link with error: {_gl.GetProgramInfoLog(_handle)}");
throw new Exception($"Program failed to link with error: {GL.GetProgramInfoLog(_handle)}");
}
_gl.DetachShader(_handle, v);
_gl.DetachShader(_handle, f);
_gl.DeleteShader(v);
_gl.DeleteShader(f);
GL.DetachShader(_handle, v);
GL.DetachShader(_handle, f);
GL.DeleteShader(v);
GL.DeleteShader(f);
}
public void Use()
{
_gl.UseProgram(_handle);
GL.UseProgram(_handle);
}
public void SetUniform(string name, int value)
{
int location = _gl.GetUniformLocation(_handle, name);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.Uniform1(location, value);
GL.Uniform1(location, value);
}
public unsafe void SetUniform(string name, Matrix4x4 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);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.UniformMatrix4(location, 1, false, (float*) &value);
GL.UniformMatrix4(location, 1, false, (float*) &value);
}
public void SetUniform(string name, bool value) => SetUniform(name, Convert.ToUInt32(value));
public void SetUniform(string name, uint value)
{
int location = _gl.GetUniformLocation(_handle, name);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.Uniform1(location, value);
GL.Uniform1(location, value);
}
public void SetUniform(string name, float value)
{
int location = _gl.GetUniformLocation(_handle, name);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.Uniform1(location, value);
GL.Uniform1(location, value);
}
public void SetUniform(string name, Vector3 value)
{
int location = _gl.GetUniformLocation(_handle, name);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.Uniform3(location, value.X, value.Y, value.Z);
GL.Uniform3(location, value.X, value.Y, value.Z);
}
public void SetUniform(string name, Vector4 value)
{
int location = _gl.GetUniformLocation(_handle, name);
int location = GL.GetUniformLocation(_handle, name);
if (location == -1)
{
throw new Exception($"{name} uniform not found on shader.");
}
_gl.Uniform4(location, value.X, value.Y, value.Z, value.W);
GL.Uniform4(location, value.X, value.Y, value.Z, value.W);
}
public int GetUniformLocation(string uniform)
{
if (!_uniformToLocation.TryGetValue(uniform, out int location))
{
location = _gl.GetUniformLocation(_handle, uniform);
location = GL.GetUniformLocation(_handle, uniform);
_uniformToLocation.Add(uniform, location);
if (location == -1)
{
@@ -124,7 +121,7 @@ public class Shader : IDisposable
{
if (!_attribLocation.TryGetValue(attrib, out int location))
{
location = _gl.GetAttribLocation(_handle, attrib);
location = GL.GetAttribLocation(_handle, attrib);
_attribLocation.Add(attrib, location);
if (location == -1)
{
@@ -136,18 +133,18 @@ public class Shader : IDisposable
public void Dispose()
{
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
private uint LoadShader(ShaderType type, string file)
private int LoadShader(ShaderType type, string file)
{
var executingAssembly = Assembly.GetExecutingAssembly();
using var stream = executingAssembly.GetManifestResourceStream($"{executingAssembly.GetName().Name}.Resources.{file}");
using var reader = new StreamReader(stream);
uint handle = _gl.CreateShader(type);
_gl.ShaderSource(handle, reader.ReadToEnd());
_gl.CompileShader(handle);
string infoLog = _gl.GetShaderInfoLog(handle);
var handle = GL.CreateShader(type);
GL.ShaderSource(handle, reader.ReadToEnd());
GL.CompileShader(handle);
string infoLog = GL.GetShaderInfoLog(handle);
if (!string.IsNullOrWhiteSpace(infoLog))
{
throw new Exception($"Error compiling shader of type {type}, failed with error {infoLog}");

View File

@@ -1,12 +1,11 @@
using System;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class Skybox : IDisposable
{
private uint _handle;
private GL _gl;
private int _handle;
private BufferObject<uint> _ebo;
private BufferObject<float> _vbo;
@@ -65,25 +64,23 @@ public class Skybox : IDisposable
public Skybox() {}
public void Setup(GL gl)
public void Setup()
{
_gl = gl;
_handle = GL.CreateProgram();
_handle = _gl.CreateProgram();
_ebo = new BufferObject<uint>(Indices, BufferTarget.ElementArrayBuffer);
_vbo = new BufferObject<float>(Vertices, BufferTarget.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_vbo, _ebo);
_ebo = new BufferObject<uint>(_gl, Indices, BufferTargetARB.ElementArrayBuffer);
_vbo = new BufferObject<float>(_gl, Vertices, BufferTargetARB.ArrayBuffer);
_vao = new VertexArrayObject<float, uint>(_gl, _vbo, _ebo);
_cubeMap = new Texture(_gl, _textures);
_shader = new Shader(_gl, "skybox");
_cubeMap = new Texture(_textures);
_shader = new Shader("skybox");
_vao.VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 3, 0); // position
}
public void Bind(Camera camera)
{
_gl.DepthFunc(DepthFunction.Lequal);
GL.DepthFunc(DepthFunction.Lequal);
_vao.Bind();
@@ -99,9 +96,9 @@ public class Skybox : IDisposable
_shader.SetUniform("cubemap", 0);
_gl.DrawArrays(PrimitiveType.Triangles, 0, 36);
GL.DrawArrays(PrimitiveType.Triangles, 0, 36);
_gl.DepthFunc(DepthFunction.Less);
GL.DepthFunc(DepthFunction.Less);
}
public void Dispose()
@@ -110,6 +107,6 @@ public class Skybox : IDisposable
_vbo.Dispose();
_vao.Dispose();
_shader.Dispose();
_gl.DeleteProgram(_handle);
GL.DeleteProgram(_handle);
}
}

View File

@@ -1,55 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System;
using System.Threading;
using System.Windows;
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 ImGuiNET;
using Silk.NET.Core;
using Silk.NET.Input;
using Silk.NET.Maths;
using Silk.NET.OpenGL;
using Silk.NET.Windowing;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using Image = SixLabors.ImageSharp.Image;
using OpenTK.Mathematics;
using OpenTK.Windowing.Common;
using OpenTK.Windowing.Desktop;
namespace FModel.Views.Snooper;
public class Snooper
{
private readonly IWindow _window;
private GL _gl;
private SnimGui _imGui;
private Camera _camera;
private IKeyboard _keyboard;
private IMouse _mouse;
private RawImage _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 Vector2D<int> _size;
private float _previousSpeed;
private readonly FWindow _window;
public Snooper()
{
@@ -57,366 +19,23 @@ public class Snooper
var x = SystemParameters.MaximizedPrimaryScreenWidth;
var y = SystemParameters.MaximizedPrimaryScreenHeight;
var options = WindowOptions.Default;
options.Size = _size = new Vector2D<int>(Convert.ToInt32(x * ratio), Convert.ToInt32(y * ratio));
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 = Silk.NET.Windowing.Window.Create(options);
unsafe
{
var info = Application.GetResourceStream(new Uri("/FModel;component/Resources/materialicon.png", UriKind.Relative));
using var image = Image.Load<Rgba32>(info.Stream);
var memoryGroup = image.GetPixelMemoryGroup();
Memory<byte> array = new byte[memoryGroup.TotalLength * sizeof(Rgba32)];
var block = MemoryMarshal.Cast<byte, Rgba32>(array.Span);
foreach (var memory in memoryGroup)
{
memory.Span.CopyTo(block);
block = block.Slice(memory.Length);
}
_icon = new RawImage(image.Width, image.Height, array);
}
_window.Load += OnLoad;
_window.Update += OnUpdate;
_window.Render += OnRender;
_window.Closing += OnClose;
_window.FramebufferResize += delegate(Vector2D<int> vector2D)
{
_gl.Viewport(vector2D);
_size = vector2D;
};
_options = new Options();
_framebuffer = new FramebufferObject(_size);
_skybox = new Skybox();
_grid = new Grid();
_models = new Dictionary<FGuid, Model>();
_window = new FWindow(GameWindowSettings.Default, options);
}
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));
}
DoLoop();
_window.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);
DoLoop();
}
private void DoLoop()
{
if (_options.Append) _options.Append = false;
_window.Run();
// 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;
}
}
private void OnLoad()
{
_window.SetWindowIcon(ref _icon);
_window.Center();
var input = _window.CreateInput();
_keyboard = input.Keyboards[0];
_mouse = input.Mice[0];
_gl = GL.GetApi(_window);
_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);
_imGui = new SnimGui(_gl, _window, input);
_framebuffer.Setup(_gl);
_skybox.Setup(_gl);
_grid.Setup(_gl);
_shader = new Shader(_gl);
_outline = new Shader(_gl, "outline");
_diffuseLight = new Vector3(0.75f);
_specularLight = new Vector3(0.5f);
foreach (var model in _models.Values)
{
model.Setup(_gl);
}
}
/// <summary>
/// friendly reminder this is called each frame
/// don't do crazy things inside
/// </summary>
private void OnRender(double deltaTime)
{
_imGui.Update((float) deltaTime);
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);
}
_imGui.Construct(ref _options, _size, _framebuffer, _camera, _mouse, _models);
_framebuffer.BindMsaa();
_framebuffer.Bind(0); // switch back to main window
_framebuffer.BindStuff();
_imGui.Render(); // render ImGui in main window
}
private void ClearWhatHasBeenDrawn()
{
_gl.ClearColor(1.0f, 0.102f, 0.129f, 1.0f);
_gl.Clear((uint) ClearBufferMask.ColorBufferBit | (uint) ClearBufferMask.DepthBufferBit | (uint) ClearBufferMask.StencilBufferBit);
_gl.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill);
}
private void OnUpdate(double deltaTime)
{
if (ImGui.GetIO().WantTextInput) return;
var multiplier = _keyboard.IsKeyPressed(Key.ShiftLeft) ? 2f : 1f;
var moveSpeed = _camera.Speed * multiplier * (float) deltaTime;
if (_keyboard.IsKeyPressed(Key.W))
_camera.Position += moveSpeed * _camera.Direction;
if (_keyboard.IsKeyPressed(Key.S))
_camera.Position -= moveSpeed * _camera.Direction;
if (_keyboard.IsKeyPressed(Key.A))
_camera.Position -= Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (_keyboard.IsKeyPressed(Key.D))
_camera.Position += Vector3.Normalize(Vector3.Cross(_camera.Direction, _camera.Up)) * moveSpeed;
if (_keyboard.IsKeyPressed(Key.E))
_camera.Position += moveSpeed * _camera.Up;
if (_keyboard.IsKeyPressed(Key.Q))
_camera.Position -= moveSpeed * _camera.Up;
if (_keyboard.IsKeyPressed(Key.X))
_camera.ModifyZoom(-.5f);
if (_keyboard.IsKeyPressed(Key.C))
_camera.ModifyZoom(+.5f);
if (_keyboard.IsKeyPressed(Key.H))
{
// because we lose GLContext when the window is invisible after a few seconds (it's apparently a bug)
// we can't use GLContext back on next load and so, for now, we basically have to reset the window
// if we can't use GLContext, we can't generate handles, can't interact with IsVisible, State, etc
// tldr we dispose everything but don't clear models, so the more you append, the longer it takes to load
_options.Append = true;
_window.Close();
// _window.IsVisible = false;
}
if (_keyboard.IsKeyPressed(Key.Escape))
_window.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;
}
_imGui.Dispose();
_window.Dispose();
_gl.Dispose();
_window.SwapMaterial(mi);
}
}

View File

@@ -1,17 +1,14 @@
using Silk.NET.OpenGL;
using System;
using System;
using System.Windows;
using CUE4Parse.UE4.Assets.Exports.Texture;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using OpenTK.Graphics.OpenGL4;
using SkiaSharp;
namespace FModel.Views.Snooper;
public class Texture : IDisposable
{
private readonly uint _handle;
private readonly GL _gl;
private readonly int _handle;
private readonly TextureType _type;
public readonly string Type;
@@ -20,52 +17,50 @@ public class Texture : IDisposable
public readonly EPixelFormat Format;
public readonly uint ImportedWidth;
public readonly uint ImportedHeight;
public readonly uint Width;
public readonly uint Height;
public readonly int Width;
public readonly int Height;
public string Label;
public Texture(GL gl, TextureType type)
public Texture(TextureType type)
{
_gl = gl;
_handle = _gl.GenTexture();
_handle = GL.GenTexture();
_type = type;
Label = "(?) Click to Copy Path";
}
public Texture(GL gl, uint width, uint height) : this(gl, TextureType.MsaaFramebuffer)
public Texture(uint width, uint height) : this(TextureType.MsaaFramebuffer)
{
Width = width;
Height = height;
Bind(TextureUnit.Texture0);
_gl.TexImage2DMultisample(TextureTarget.Texture2DMultisample, Constants.SAMPLES_COUNT, InternalFormat.Rgb, Width, Height, Silk.NET.OpenGL.Boolean.True);
GL.TexImage2DMultisample(TextureTargetMultisample.Texture2DMultisample, Constants.SAMPLES_COUNT, PixelInternalFormat.Rgb, Width, Height, true);
_gl.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMinFilter, (int) GLEnum.Nearest);
_gl.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMagFilter, (int) GLEnum.Nearest);
_gl.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMinFilter, (int) GLEnum.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureMagFilter, (int) GLEnum.Nearest);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2DMultisample, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
_gl.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2DMultisample, _handle, 0);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2DMultisample, _handle, 0);
}
public unsafe Texture(GL gl, int width, int height) : this(gl, TextureType.Framebuffer)
public unsafe Texture(int width, int height) : this(TextureType.Framebuffer)
{
Width = (uint) width;
Height = (uint) height;
Width = width;
Height = height;
Bind(TextureUnit.Texture0);
_gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, null);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgb, PixelType.UnsignedByte, null);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
_gl.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, _handle, 0);
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, _handle, 0);
}
public unsafe Texture(GL gl, byte[] data, uint width, uint height, SKColorType colorType, UTexture2D texture2D) : this(gl, TextureType.Normal)
public unsafe Texture(byte[] data, uint width, uint height, SKColorType colorType, UTexture2D texture2D) : this(TextureType.Normal)
{
Type = texture2D.ExportType;
Name = texture2D.Name;
@@ -79,17 +74,17 @@ public class Texture : IDisposable
fixed (void* d = &data[0])
{
_gl.TexImage2D(TextureTarget.Texture2D, 0, (int) InternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.LinearMipmapLinear);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
_gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgb, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, d);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.LinearMipmapLinear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 8);
_gl.GenerateMipmap(TextureTarget.Texture2D);
GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
}
}
public unsafe Texture(GL gl, string[] textures) : this(gl, TextureType.Cubemap)
public unsafe Texture(string[] textures) : this(TextureType.Cubemap)
{
Bind(TextureUnit.Texture0);
@@ -99,7 +94,7 @@ public class Texture : IDisposable
using var img = Image.Load<Rgba32>(info.Stream);
Width = (uint) img.Width; // we don't care anyway
Height = (uint) img.Height; // we don't care anyway
_gl.TexImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, InternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null);
GL.TexImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, PixelInternalFormat.Rgba8, Width, Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, null);
img.ProcessPixelRows(accessor =>
{
@@ -107,37 +102,37 @@ public class Texture : IDisposable
{
fixed (void* data = accessor.GetRowSpan(y))
{
gl.TexSubImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data);
GL.TexSubImage2D(TextureTarget.TextureCubeMapPositiveX + t, 0, 0, y, (uint) accessor.Width, 1, PixelFormat.Rgba, PixelType.UnsignedByte, data);
}
}
});
}
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int) GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
_gl.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMinFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureMagFilter, (int) GLEnum.Linear);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapR, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge);
GL.TexParameter(TextureTarget.TextureCubeMap, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge);
}
public unsafe Texture(GL gl, uint width, uint height, IntPtr data) : this(gl, TextureType.Normal)
public unsafe Texture(uint width, uint height, IntPtr data) : this(TextureType.Normal)
{
Width = width;
Height = height;
Bind(TextureTarget.Texture2D);
_gl.TexStorage2D(GLEnum.Texture2D, 1, SizedInternalFormat.Rgba8, Width, Height);
_gl.TexSubImage2D(GLEnum.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, (void*) data);
GL.TexStorage2D(TextureTarget2d.Texture2D, 1, SizedInternalFormat.Rgba8, Width, Height);
GL.TexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, Width, Height, PixelFormat.Bgra, PixelType.UnsignedByte, (void*) data);
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.Repeat);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.Repeat);
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMaxLevel, 1 - 1);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, 1 - 1);
}
public void Bind(TextureUnit textureSlot)
{
_gl.ActiveTexture(textureSlot);
GL.ActiveTexture(textureSlot);
Bind(_type switch
{
TextureType.Cubemap => TextureTarget.TextureCubeMap,
@@ -148,24 +143,24 @@ public class Texture : IDisposable
public void Bind(TextureTarget target)
{
_gl.BindTexture(target, _handle);
GL.BindTexture(target, _handle);
}
public void SetMinFilter(TextureMinFilter filter)
public void SetMinFilter(int filter)
{
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMinFilter, (int)filter);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, ref filter);
}
public void SetMagFilter(TextureMagFilter filter)
public void SetMagFilter(int filter)
{
_gl.TexParameterI(GLEnum.Texture2D, TextureParameterName.TextureMagFilter, (int)filter);
GL.TexParameterI(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, ref filter);
}
public IntPtr GetPointer() => (IntPtr) _handle;
public void Dispose()
{
_gl.DeleteTexture(_handle);
GL.DeleteTexture(_handle);
}
}

View File

@@ -1,72 +1,70 @@
using System;
using System.Numerics;
using Silk.NET.OpenGL;
using OpenTK.Graphics.OpenGL4;
namespace FModel.Views.Snooper;
public class VertexArrayObject<TVertexType, TIndexType> : IDisposable where TVertexType : unmanaged where TIndexType : unmanaged
{
private readonly uint _handle;
private readonly GL _gl;
private readonly int _handle;
public VertexArrayObject(GL gl, BufferObject<TVertexType> vbo, BufferObject<TIndexType> ebo)
public VertexArrayObject(BufferObject<TVertexType> vbo, BufferObject<TIndexType> ebo)
{
_gl = gl;
_handle = GL.GenVertexArray();
_handle = _gl.GenVertexArray();
Bind();
vbo.Bind();
ebo.Bind();
}
public unsafe void VertexAttributePointer(uint index, int count, VertexAttribPointerType type, uint vertexSize, int offSet)
public unsafe void VertexAttributePointer(uint index, int count, VertexAttribPointerType type, int vertexSize, int offset)
{
switch (type)
{
case VertexAttribPointerType.Int:
_gl.VertexAttribIPointer(index, count, VertexAttribIType.Int, vertexSize * (uint) sizeof(TVertexType), (void*) (offSet * sizeof(TVertexType)));
GL.VertexAttribIPointer(index, count, VertexAttribIntegerType.Int, vertexSize * sizeof(TVertexType), (IntPtr) (offset * sizeof(TVertexType)));
break;
default:
_gl.VertexAttribPointer(index, count, type, false, vertexSize * (uint) sizeof(TVertexType), (void*) (offSet * sizeof(TVertexType)));
GL.VertexAttribPointer(index, count, type, false, vertexSize * sizeof(TVertexType), offset * sizeof(TVertexType));
break;
}
_gl.EnableVertexAttribArray(index);
GL.EnableVertexAttribArray(index);
}
public void Bind()
{
_gl.BindVertexArray(_handle);
GL.BindVertexArray(_handle);
}
public unsafe void BindInstancing()
{
Bind();
var vec4Size = (uint) sizeof(Vector4);
_gl.EnableVertexAttribArray(7);
_gl.VertexAttribPointer(7, 4, VertexAttribPointerType.Float, false, 4 * vec4Size, (void*)0);
_gl.EnableVertexAttribArray(8);
_gl.VertexAttribPointer(8, 4, VertexAttribPointerType.Float, false, 4 * vec4Size, (void*)(1 * vec4Size));
_gl.EnableVertexAttribArray(9);
_gl.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * vec4Size, (void*)(2 * vec4Size));
_gl.EnableVertexAttribArray(10);
_gl.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * vec4Size, (void*)(3 * vec4Size));
var size = sizeof(Vector4);
GL.EnableVertexAttribArray(7);
GL.VertexAttribPointer(7, 4, VertexAttribPointerType.Float, false, 4 * size, 0);
GL.EnableVertexAttribArray(8);
GL.VertexAttribPointer(8, 4, VertexAttribPointerType.Float, false, 4 * size, 1 * size);
GL.EnableVertexAttribArray(9);
GL.VertexAttribPointer(9, 4, VertexAttribPointerType.Float, false, 4 * size, 2 * size);
GL.EnableVertexAttribArray(10);
GL.VertexAttribPointer(10, 4, VertexAttribPointerType.Float, false, 4 * size, 3 * size);
_gl.VertexAttribDivisor(7, 1);
_gl.VertexAttribDivisor(8, 1);
_gl.VertexAttribDivisor(9, 1);
_gl.VertexAttribDivisor(10, 1);
GL.VertexAttribDivisor(7, 1);
GL.VertexAttribDivisor(8, 1);
GL.VertexAttribDivisor(9, 1);
GL.VertexAttribDivisor(10, 1);
Unbind();
}
public void Unbind()
{
_gl.BindVertexArray(0);
GL.BindVertexArray(0);
}
public void Dispose()
{
_gl.DeleteVertexArray(_handle);
GL.DeleteVertexArray(_handle);
}
}

Binary file not shown.