diff --git a/.idea/.idea.Everlook/.idea/contentModel.xml b/.idea/.idea.Everlook/.idea/contentModel.xml
index 7b6b4ea..26062e2 100644
--- a/.idea/.idea.Everlook/.idea/contentModel.xml
+++ b/.idea/.idea.Everlook/.idea/contentModel.xml
@@ -213,12 +213,18 @@
-
+
+
+
+
+
+
+
@@ -245,6 +251,7 @@
+
@@ -262,6 +269,7 @@
+
@@ -313,8 +321,10 @@
-
+
+
+
@@ -322,23 +332,11 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/.idea/.idea.Everlook/.idea/dictionaries/jarl.xml b/.idea/.idea.Everlook/.idea/dictionaries/jarl.xml
new file mode 100644
index 0000000..f5f5680
--- /dev/null
+++ b/.idea/.idea.Everlook/.idea/dictionaries/jarl.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/Directory.Build.props b/Directory.Build.props
index d8f86ec..48212c1 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -89,7 +89,7 @@
-
+
diff --git a/Everlook.sln b/Everlook.sln
index c610d0c..f8ccdbb 100644
--- a/Everlook.sln
+++ b/Everlook.sln
@@ -5,13 +5,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Everlook", "Everlook\Everlo
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x86 = Debug|x86
- Release|x86 = Release|x86
+ Release|Any CPU = Release|Any CPU
+ Debug|Any CPU = Debug|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {64BD763C-024D-477A-B05C-57152FD612DF}.Debug|x86.ActiveCfg = Debug|x86
- {64BD763C-024D-477A-B05C-57152FD612DF}.Debug|x86.Build.0 = Debug|x86
- {64BD763C-024D-477A-B05C-57152FD612DF}.Release|x86.ActiveCfg = Release|x86
- {64BD763C-024D-477A-B05C-57152FD612DF}.Release|x86.Build.0 = Release|x86
+ {64BD763C-024D-477A-B05C-57152FD612DF}.Release|Any CPU.ActiveCfg = Debug|Any CPU
+ {64BD763C-024D-477A-B05C-57152FD612DF}.Release|Any CPU.Build.0 = Debug|Any CPU
+ {64BD763C-024D-477A-B05C-57152FD612DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {64BD763C-024D-477A-B05C-57152FD612DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
EndGlobalSection
EndGlobal
diff --git a/Everlook.sln.DotSettings b/Everlook.sln.DotSettings
index 1f6e240..b13cd2c 100644
--- a/Everlook.sln.DotSettings
+++ b/Everlook.sln.DotSettings
@@ -41,6 +41,7 @@
CHOP_IF_LONG
UseExplicitType
UseExplicitType
+ API
BLP
BMP
BPP
@@ -83,9 +84,17 @@
True
True
True
+ True
+ True
True
True
True
True
+ True
+
True
- True
\ No newline at end of file
+ True
+ True
+ True
+ True
+ True
\ No newline at end of file
diff --git a/Everlook/Audio/AudioGroup.cs b/Everlook/Audio/AudioGroup.cs
index fe7c537..cc63b36 100644
--- a/Everlook/Audio/AudioGroup.cs
+++ b/Everlook/Audio/AudioGroup.cs
@@ -22,7 +22,7 @@
using System;
using System.Collections.Generic;
-using OpenTK;
+using System.Numerics;
namespace Everlook.Audio
{
diff --git a/Everlook/Audio/AudioManager.cs b/Everlook/Audio/AudioManager.cs
index dd2a6b6..146b171 100644
--- a/Everlook/Audio/AudioManager.cs
+++ b/Everlook/Audio/AudioManager.cs
@@ -22,7 +22,7 @@
using System;
using System.Collections.Generic;
-using OpenTK.Audio;
+using Silk.NET.OpenAL;
namespace Everlook.Audio
{
@@ -79,7 +79,7 @@ public static void RegisterSource(AudioSource audioSource)
/// The audio source to unregister.
public static void UnregisterSource(AudioSource audioSource)
{
- if (audioSource == null)
+ if (audioSource is null)
{
return;
}
diff --git a/Everlook/Audio/AudioSource.cs b/Everlook/Audio/AudioSource.cs
index 9d200b4..bdce425 100644
--- a/Everlook/Audio/AudioSource.cs
+++ b/Everlook/Audio/AudioSource.cs
@@ -21,12 +21,13 @@
//
using System;
+using System.Numerics;
using System.Threading.Tasks;
using Everlook.Audio.MP3;
using Everlook.Audio.Wave;
using Everlook.Explorer;
-using OpenTK;
-using OpenTK.Audio.OpenAL;
+using JetBrains.Annotations;
+using Silk.NET.OpenAL;
using Warcraft.Core;
using Warcraft.DBC.Definitions;
@@ -35,16 +36,18 @@ namespace Everlook.Audio
///
/// Represents a single audio source in 3D space.
///
- public sealed class AudioSource : IDisposable, IEquatable
+ [PublicAPI]
+ public sealed class AudioSource : IDisposable
{
+ private AL _al = AL.GetApi();
private IAudioAsset? _audioAsset;
- private int _soundBufferID;
- private int _soundSourceID;
+ private uint _soundBufferID;
+ private uint _soundSourceID;
///
/// Gets the format of the current audio source.
///
- public ALFormat SoundFormat { get; private set; }
+ public BufferFormat SoundFormat { get; private set; }
///
/// Gets the sample rate of the current audio source.
@@ -54,7 +57,14 @@ public sealed class AudioSource : IDisposable, IEquatable
///
/// Gets the current state of the sound source.
///
- public ALSourceState State => AL.GetSourceState(_soundSourceID);
+ public SourceState State
+ {
+ get
+ {
+ _al.GetSourceProperty(_soundSourceID, GetSourceInteger.SourceState, out var value);
+ return (SourceState)value;
+ }
+ }
///
/// Gets or sets the offset of the audio source into the sound (in seconds).
@@ -63,10 +73,10 @@ public float TimeOffset
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.SecOffset, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.SecOffset, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.SecOffset, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.SecOffset, value);
}
///
@@ -76,10 +86,15 @@ public bool Looping
{
get
{
- AL.GetSource(_soundSourceID, ALSourceb.Looping, out var value);
- return value;
+ // TODO: Restore
+ /*
+ * al.GetSourceProperty(_soundSourceID, SourceBoolean.Looping, out var temp);
+ * return temp > 0;
+ */
+
+ return false;
}
- set => AL.Source(_soundSourceID, ALSourceb.Looping, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceBoolean.Looping, value ? 1 : 0);
}
///
@@ -89,10 +104,10 @@ public Vector3 Position
{
get
{
- AL.GetSource(_soundSourceID, ALSource3f.Position, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceVector3.Position, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSource3f.Position, ref value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceVector3.Position, value);
}
///
@@ -102,10 +117,10 @@ public Vector3 Direction
{
get
{
- AL.GetSource(_soundSourceID, ALSource3f.Direction, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceVector3.Direction, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSource3f.Direction, ref value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceVector3.Direction, value);
}
///
@@ -115,10 +130,10 @@ public Vector3 Velocity
{
get
{
- AL.GetSource(_soundSourceID, ALSource3f.Direction, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceVector3.Direction, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSource3f.Direction, ref value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceVector3.Direction, value);
}
///
@@ -128,10 +143,15 @@ public bool RelativePositioning
{
get
{
- AL.GetSource(_soundSourceID, ALSourceb.SourceRelative, out var value);
- return value;
+ // TODO: Restore
+ /*
+ * _al.GetSourceProperty(_soundSourceID, SourceBoolean.SourceRelative, out var value);
+ * return value > 0;
+ */
+
+ return false;
}
- set => AL.Source(_soundSourceID, ALSourceb.SourceRelative, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceBoolean.SourceRelative, value ? 1 : 0);
}
///
@@ -142,10 +162,10 @@ public float Attenuation
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.MaxDistance, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.MaxDistance, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.MaxDistance, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.MaxDistance, value);
}
///
@@ -155,10 +175,10 @@ public float MinGain
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.MinGain, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.MinGain, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.MinGain, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.MinGain, value);
}
///
@@ -168,10 +188,10 @@ public float MaxGain
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.MaxGain, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.MaxGain, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.MaxGain, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.MaxGain, value);
}
///
@@ -181,10 +201,10 @@ public float ConeOuterGain
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.ConeOuterGain, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.ConeOuterGain, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.ConeOuterGain, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.ConeOuterGain, value);
}
///
@@ -194,10 +214,10 @@ public float ConeInnerAngle
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.ConeInnerAngle, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.ConeInnerAngle, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.ConeInnerAngle, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.ConeInnerAngle, value);
}
///
@@ -207,10 +227,10 @@ public float ConeOuterAngle
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.ConeOuterAngle, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.ConeOuterAngle, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.ConeOuterAngle, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.ConeOuterAngle, value);
}
///
@@ -220,10 +240,10 @@ public float Pitch
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.Pitch, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.Pitch, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.Pitch, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.Pitch, value);
}
///
@@ -234,10 +254,10 @@ public float Gain
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.Gain, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.Gain, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.Gain, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.Gain, value);
}
///
@@ -247,10 +267,10 @@ public float RolloffFactor
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.RolloffFactor, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.RolloffFactor, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.RolloffFactor, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.RolloffFactor, value);
}
///
@@ -262,10 +282,10 @@ public float ReferenceDistance
{
get
{
- AL.GetSource(_soundSourceID, ALSourcef.ReferenceDistance, out var value);
+ _al.GetSourceProperty(_soundSourceID, SourceFloat.ReferenceDistance, out var value);
return value;
}
- set => AL.Source(_soundSourceID, ALSourcef.ReferenceDistance, value);
+ set => _al.SetSourceProperty(_soundSourceID, SourceFloat.ReferenceDistance, value);
}
///
@@ -294,11 +314,6 @@ public static AudioSource CreateNew()
/// An AudioSource.
public static AudioSource CreateFromSoundEntry(SoundEntriesRecord soundEntry)
{
- if (soundEntry == null)
- {
- throw new ArgumentNullException(nameof(soundEntry));
- }
-
var source = CreateNew();
source.Attenuation = soundEntry.DistanceCutoff;
@@ -313,8 +328,8 @@ public static AudioSource CreateFromSoundEntry(SoundEntriesRecord soundEntry)
///
public void Play()
{
- AL.SourceRewind(_soundSourceID);
- AL.SourcePlay(_soundSourceID);
+ _al.SourceRewind(_soundSourceID);
+ _al.SourcePlay(_soundSourceID);
}
///
@@ -322,7 +337,7 @@ public void Play()
///
public void Resume()
{
- AL.SourcePlay(_soundSourceID);
+ _al.SourcePlay(_soundSourceID);
}
///
@@ -330,7 +345,7 @@ public void Resume()
///
public void Pause()
{
- AL.SourcePause(_soundSourceID);
+ _al.SourcePause(_soundSourceID);
}
///
@@ -338,8 +353,8 @@ public void Pause()
///
public void Stop()
{
- AL.SourceStop(_soundSourceID);
- AL.SourceRewind(_soundSourceID);
+ _al.SourceStop(_soundSourceID);
+ _al.SourceRewind(_soundSourceID);
}
///
@@ -349,11 +364,6 @@ public void Stop()
/// An asynchronous task.
public async Task SetAudioAsync(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
// First, clear the old audio
ClearAudio();
@@ -381,11 +391,19 @@ public async Task SetAudioAsync(FileReference fileReference)
this.SampleRate = _audioAsset.SampleRate;
// Create new AL data
- _soundBufferID = AL.GenBuffer();
- _soundSourceID = AL.GenSource();
+ _soundBufferID = _al.GenBuffer();
+ _soundSourceID = _al.GenSource();
- AL.BufferData(_soundBufferID, this.SoundFormat, soundData, soundData.Length, this.SampleRate);
- AL.Source(_soundSourceID, ALSourcei.Buffer, _soundBufferID);
+ unsafe
+ {
+ fixed (void* ptr = soundData)
+ {
+ _al.BufferData(_soundBufferID, this.SoundFormat, ptr, soundData.Length, this.SampleRate);
+ }
+ }
+
+ // TODO: Use correct overload
+ _al.SetSourceProperty(_soundSourceID, SourceInteger.Buffer, (int)_soundBufferID);
}
///
@@ -393,10 +411,10 @@ public async Task SetAudioAsync(FileReference fileReference)
///
private void ClearAudio()
{
- AL.SourceStop(_soundSourceID);
+ _al.SourceStop(_soundSourceID);
- AL.DeleteSource(_soundSourceID);
- AL.DeleteBuffer(_soundBufferID);
+ _al.DeleteSource(_soundSourceID);
+ _al.DeleteBuffer(_soundBufferID);
_audioAsset?.Dispose();
}
@@ -407,37 +425,5 @@ public void Dispose()
Stop();
ClearAudio();
}
-
- ///
- public override int GetHashCode()
- {
- unchecked
- {
- var hash = 17;
- hash *= 23 + _soundBufferID;
- hash *= 23 + _soundSourceID;
-
- return hash;
- }
- }
-
- ///
- public bool Equals(AudioSource other)
- {
- return Equals((object)other);
- }
-
- ///
- public override bool Equals(object obj)
- {
- if (!(obj is AudioSource))
- {
- return false;
- }
-
- var other = (AudioSource)obj;
- return other._soundSourceID == _soundSourceID &&
- other._soundBufferID == _soundBufferID;
- }
}
}
diff --git a/Everlook/Audio/IAudioAsset.cs b/Everlook/Audio/IAudioAsset.cs
index d8dfec2..21b3e10 100644
--- a/Everlook/Audio/IAudioAsset.cs
+++ b/Everlook/Audio/IAudioAsset.cs
@@ -22,7 +22,7 @@
using System;
using System.IO;
-using OpenTK.Audio.OpenAL;
+using Silk.NET.OpenAL;
namespace Everlook.Audio
{
@@ -32,9 +32,9 @@ namespace Everlook.Audio
public interface IAudioAsset : IDisposable
{
///
- /// Gets the that the PCM data is in.
+ /// Gets the that the PCM data is in.
///
- ALFormat Format { get; }
+ BufferFormat Format { get; }
///
/// Gets the raw PCM data of the audio asset.
diff --git a/Everlook/Audio/MP3/MP3AudioAsset.cs b/Everlook/Audio/MP3/MP3AudioAsset.cs
index 8b26ecf..c8d33b6 100644
--- a/Everlook/Audio/MP3/MP3AudioAsset.cs
+++ b/Everlook/Audio/MP3/MP3AudioAsset.cs
@@ -25,7 +25,7 @@
using System.Threading.Tasks;
using Everlook.Explorer;
using MP3Sharp;
-using OpenTK.Audio.OpenAL;
+using Silk.NET.OpenAL;
using Warcraft.Core;
namespace Everlook.Audio.MP3
@@ -41,7 +41,7 @@ public sealed class MP3AudioAsset : IAudioAsset
private bool _isDisposed;
///
- public ALFormat Format
+ public BufferFormat Format
{
get
{
@@ -49,11 +49,11 @@ public ALFormat Format
{
case 1:
{
- return ALFormat.Mono16;
+ return BufferFormat.Mono16;
}
case 2:
{
- return ALFormat.Stereo16;
+ return BufferFormat.Stereo16;
}
default:
{
@@ -72,7 +72,7 @@ public byte[] PCMData
{
ThrowIfDisposed();
- if (_pcmDataInternal != null)
+ if (!(_pcmDataInternal is null))
{
return _pcmDataInternal;
}
@@ -111,11 +111,6 @@ public byte[] PCMData
/// Thrown if the file data can't be extracted.
public MP3AudioAsset(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
if (fileReference.GetReferencedFileType() != WarcraftFileType.MP3Audio)
{
throw new ArgumentException
@@ -124,8 +119,7 @@ public MP3AudioAsset(FileReference fileReference)
);
}
- var fileBytes = fileReference.Extract();
- if (fileBytes == null)
+ if (!fileReference.TryExtract(out var fileBytes))
{
throw new ArgumentException("The file data could not be extracted.", nameof(fileReference));
}
@@ -151,7 +145,7 @@ public void ThrowIfDisposed()
{
if (_isDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(MP3AudioAsset));
}
}
diff --git a/Everlook/Audio/Wave/WaveAudioAsset.cs b/Everlook/Audio/Wave/WaveAudioAsset.cs
index 42fa641..eab1049 100644
--- a/Everlook/Audio/Wave/WaveAudioAsset.cs
+++ b/Everlook/Audio/Wave/WaveAudioAsset.cs
@@ -24,7 +24,7 @@
using System.IO;
using System.Threading.Tasks;
using Everlook.Explorer;
-using OpenTK.Audio.OpenAL;
+using Silk.NET.OpenAL;
using Warcraft.Core;
namespace Everlook.Audio.Wave
@@ -40,7 +40,7 @@ public sealed class WaveAudioAsset : IAudioAsset
private bool _isDisposed;
///
- public ALFormat Format
+ public BufferFormat Format
{
get
{
@@ -48,11 +48,11 @@ public ALFormat Format
{
case 1:
{
- return this.BitsPerSample == 8 ? ALFormat.Mono8 : ALFormat.Mono16;
+ return this.BitsPerSample == 8 ? BufferFormat.Mono8 : BufferFormat.Mono16;
}
case 2:
{
- return this.BitsPerSample == 8 ? ALFormat.Stereo8 : ALFormat.Stereo16;
+ return this.BitsPerSample == 8 ? BufferFormat.Stereo8 : BufferFormat.Stereo16;
}
default:
{
@@ -71,7 +71,7 @@ public byte[] PCMData
{
ThrowIfDisposed();
- if (_pcmDataInternal != null)
+ if (!(_pcmDataInternal is null))
{
return _pcmDataInternal;
}
@@ -111,11 +111,6 @@ public byte[] PCMData
/// Thrown if the file data can't be extracted.
public WaveAudioAsset(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
if (fileReference.GetReferencedFileType() != WarcraftFileType.WaveAudio)
{
throw new ArgumentException
@@ -125,65 +120,60 @@ public WaveAudioAsset(FileReference fileReference)
);
}
- var fileBytes = fileReference.Extract();
- if (fileBytes == null)
+ if (!fileReference.TryExtract(out var fileBytes))
{
throw new ArgumentException("The file data could not be extracted.", nameof(fileReference));
}
- using (var ms = new MemoryStream(fileBytes))
+ using var ms = new MemoryStream(fileBytes);
+ using var br = new BinaryReader(ms);
+ var signature = new string(br.ReadChars(4));
+ if (signature != "RIFF")
{
- using (var br = new BinaryReader(ms))
- {
- var signature = new string(br.ReadChars(4));
- if (signature != "RIFF")
- {
- throw new NotSupportedException("The file data is not a wave file.");
- }
+ throw new NotSupportedException("The file data is not a wave file.");
+ }
- // Skip chunk size
- br.BaseStream.Position += 4;
+ // Skip chunk size
+ br.BaseStream.Position += 4;
- var format = new string(br.ReadChars(4));
- if (format != "WAVE")
- {
- throw new NotSupportedException("The file data is not a wave file.");
- }
+ var format = new string(br.ReadChars(4));
+ if (format != "WAVE")
+ {
+ throw new NotSupportedException("The file data is not a wave file.");
+ }
- var formatSignature = new string(br.ReadChars(4));
- if (formatSignature != "fmt ")
- {
- throw new NotSupportedException("The file data is not a wave file.");
- }
+ var formatSignature = new string(br.ReadChars(4));
+ if (formatSignature != "fmt ")
+ {
+ throw new NotSupportedException("The file data is not a wave file.");
+ }
- // Skip format chunk size
- br.BaseStream.Position += 4;
+ // Skip format chunk size
+ br.BaseStream.Position += 4;
- // Skip audio format
- br.BaseStream.Position += 2;
+ // Skip audio format
+ br.BaseStream.Position += 2;
- this.Channels = br.ReadInt16();
- this.SampleRate = br.ReadInt32();
+ this.Channels = br.ReadInt16();
+ this.SampleRate = br.ReadInt32();
- // Skip byte rate
- br.BaseStream.Position += 4;
+ // Skip byte rate
+ br.BaseStream.Position += 4;
- // Skip block alignment
- br.BaseStream.Position += 2;
+ // Skip block alignment
+ br.BaseStream.Position += 2;
- this.BitsPerSample = br.ReadInt16();
+ this.BitsPerSample = br.ReadInt16();
- var dataSignature = new string(br.ReadChars(4));
- if (dataSignature != "data")
- {
- throw new NotSupportedException("The file data is not a wave file.");
- }
+ var dataSignature = new string(br.ReadChars(4));
+ if (dataSignature != "data")
+ {
+ throw new NotSupportedException("The file data is not a wave file.");
+ }
- var dataChunkSize = br.ReadInt32();
+ var dataChunkSize = br.ReadInt32();
- this.PCMStream = new MemoryStream(br.ReadBytes(dataChunkSize));
- }
- }
+ this.PCMStream = new MemoryStream(br.ReadBytes(dataChunkSize));
}
///
@@ -201,7 +191,7 @@ public void ThrowIfDisposed()
{
if (_isDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(WaveAudioAsset));
}
}
diff --git a/Everlook/Configuration/EverlookConfiguration.cs b/Everlook/Configuration/EverlookConfiguration.cs
index 03055ff..a48f236 100644
--- a/Everlook/Configuration/EverlookConfiguration.cs
+++ b/Everlook/Configuration/EverlookConfiguration.cs
@@ -56,7 +56,7 @@ Section names
private readonly object _writeLock = new object();
private readonly FileIniDataParser _defaultParser = new FileIniDataParser();
- private IniData _configurationData;
+ private readonly IniData _configurationData;
///
/// Gets or sets the sprinting speed multiplier.
@@ -406,11 +406,13 @@ private void AddNewConfigurationSection(IniData configData, string keySection)
private void AddNewConfigurationOption(IniData configData, string keySection, string keyName, string keyData)
{
- if (!configData.Sections[keySection].ContainsKey(keyName))
+ if (configData.Sections[keySection].ContainsKey(keyName))
{
- configData.Sections[keySection].AddKey(keyName);
- configData.Sections[keySection][keyName] = keyData;
+ return;
}
+
+ configData.Sections[keySection].AddKey(keyName);
+ configData.Sections[keySection][keyName] = keyData;
}
private void RenameConfigurationOption
@@ -421,25 +423,29 @@ private void RenameConfigurationOption
string newKeyName
)
{
- if (configData.Sections[keySection].ContainsKey(oldKeyName))
+ if (!configData.Sections[keySection].ContainsKey(oldKeyName))
{
- var oldKeyData = configData.Sections[keySection][oldKeyName];
+ return;
+ }
- AddNewConfigurationOption(configData, keySection, newKeyName, oldKeyData);
+ var oldKeyData = configData.Sections[keySection][oldKeyName];
- configData.Sections[keySection].RemoveKey(oldKeyName);
- }
+ AddNewConfigurationOption(configData, keySection, newKeyName, oldKeyData);
+
+ configData.Sections[keySection].RemoveKey(oldKeyName);
}
private void RenameConfigurationSection(IniData configData, string oldSectionName, string newSectionName)
{
- if (configData.Sections.ContainsSection(oldSectionName))
+ if (!configData.Sections.ContainsSection(oldSectionName))
{
- var oldSectionData = configData.Sections.GetSectionData(oldSectionName);
- configData.Sections.RemoveSection(oldSectionName);
- configData.Sections.AddSection(newSectionName);
- configData.Sections.SetSectionData(newSectionName, oldSectionData);
+ return;
}
+
+ var oldSectionData = configData.Sections.GetSectionData(oldSectionName);
+ configData.Sections.RemoveSection(oldSectionName);
+ configData.Sections.AddSection(newSectionName);
+ configData.Sections.SetSectionData(newSectionName, oldSectionData);
}
private void DeleteConfigurationSection(IniData configData, string sectionName)
@@ -458,13 +464,15 @@ private void MoveConfigurationOption
string keyName
)
{
- if (!configData.Sections[newKeySection].ContainsKey(keyName))
+ if (configData.Sections[newKeySection].ContainsKey(keyName))
{
- var keyValue = configData.Sections[oldKeySection][keyName];
- configData.Sections[newKeySection].AddKey(keyName, keyValue);
-
- configData.Sections[oldKeySection].RemoveKey(keyName);
+ return;
}
+
+ var keyValue = configData.Sections[oldKeySection][keyName];
+ configData.Sections[newKeySection].AddKey(keyName, keyValue);
+
+ configData.Sections[oldKeySection].RemoveKey(keyName);
}
///
@@ -479,6 +487,14 @@ private void SetOption(string section, string keyName, T optionValue, bool st
where T : notnull
{
var value = optionValue.ToString();
+ if (value is null)
+ {
+ throw new InvalidOperationException
+ (
+ "The value was null when transformed into its string representation."
+ );
+ }
+
if (storeAsLowerCase)
{
value = value.ToLowerInvariant();
diff --git a/Everlook/Configuration/GamePathStorage.cs b/Everlook/Configuration/GamePathStorage.cs
index f97dfeb..8f66420 100644
--- a/Everlook/Configuration/GamePathStorage.cs
+++ b/Everlook/Configuration/GamePathStorage.cs
@@ -71,10 +71,8 @@ private GamePathStorage()
int formatVersion;
using (var fs = File.OpenRead(GetPathStoragePath()))
{
- using (var br = new BinaryReader(fs))
- {
- formatVersion = br.ReadInt32();
- }
+ using var br = new BinaryReader(fs);
+ formatVersion = br.ReadInt32();
}
if (formatVersion != FormatVersion)
@@ -104,21 +102,19 @@ private GamePathStorage()
/// Path to store.
public void StorePath(string alias, WarcraftVersion version, string pathToStore)
{
- if (!this.GamePaths.Contains((alias, version, pathToStore)))
+ if (this.GamePaths.Contains((alias, version, pathToStore)))
{
- lock (_storageLock)
- {
- using (var fs = File.Open(GetPathStoragePath(), FileMode.Append, FileAccess.Write))
- {
- using (var bw = new BinaryWriter(fs))
- {
- bw.WriteNullTerminatedString(alias);
- bw.Write((uint)version);
- bw.WriteNullTerminatedString(pathToStore);
- bw.Flush();
- }
- }
- }
+ return;
+ }
+
+ lock (_storageLock)
+ {
+ using var fs = File.Open(GetPathStoragePath(), FileMode.Append, FileAccess.Write);
+ using var bw = new BinaryWriter(fs);
+ bw.WriteNullTerminatedString(alias);
+ bw.Write((uint)version);
+ bw.WriteNullTerminatedString(pathToStore);
+ bw.Flush();
}
}
@@ -131,26 +127,24 @@ public void StorePath(string alias, WarcraftVersion version, string pathToStore)
public void RemoveStoredPath(string alias, WarcraftVersion version, string pathToRemove)
{
var storedPaths = this.GamePaths;
- if (storedPaths.Contains((alias, version, pathToRemove)))
+ if (!storedPaths.Contains((alias, version, pathToRemove)))
{
- ClearPaths();
- lock (_storageLock)
- {
- storedPaths.Remove((alias, version, pathToRemove));
+ return;
+ }
- using (var fs = File.Open(GetPathStoragePath(), FileMode.Append, FileAccess.Write))
- {
- using (var bw = new BinaryWriter(fs))
- {
- foreach ((var remainingAlias, var remainingVersion, var remainingPath) in storedPaths)
- {
- bw.WriteNullTerminatedString(remainingAlias);
- bw.Write((uint)remainingVersion);
- bw.WriteNullTerminatedString(remainingPath);
- bw.Flush();
- }
- }
- }
+ ClearPaths();
+ lock (_storageLock)
+ {
+ storedPaths.Remove((alias, version, pathToRemove));
+
+ using var fs = File.Open(GetPathStoragePath(), FileMode.Append, FileAccess.Write);
+ using var bw = new BinaryWriter(fs);
+ foreach (var (remainingAlias, remainingVersion, remainingPath) in storedPaths)
+ {
+ bw.WriteNullTerminatedString(remainingAlias);
+ bw.Write((uint)remainingVersion);
+ bw.WriteNullTerminatedString(remainingPath);
+ bw.Flush();
}
}
}
@@ -162,29 +156,25 @@ public void RemoveStoredPath(string alias, WarcraftVersion version, string pathT
{
try
{
- using (var fs = File.OpenRead(GetPathStoragePath()))
+ using var fs = File.OpenRead(GetPathStoragePath());
+ using var br = new BinaryReader(fs);
+ var formatVersion = br.ReadInt32();
+ if (formatVersion != FormatVersion)
+ {
+ Log.Warn("Read an unsupported path store version. Aborting.");
+ }
+ else
{
- using (var br = new BinaryReader(fs))
+ while (br.BaseStream.Position != br.BaseStream.Length)
{
- var formatVersion = br.ReadInt32();
- if (formatVersion != FormatVersion)
- {
- Log.Warn("Read an unsupported path store version. Aborting.");
- }
- else
- {
- while (br.BaseStream.Position != br.BaseStream.Length)
- {
- storedPaths.Add
- (
- (
- br.ReadNullTerminatedString(),
- (WarcraftVersion)br.ReadUInt32(),
- br.ReadNullTerminatedString()
- )
- );
- }
- }
+ storedPaths.Add
+ (
+ (
+ br.ReadNullTerminatedString(),
+ (WarcraftVersion)br.ReadUInt32(),
+ br.ReadNullTerminatedString()
+ )
+ );
}
}
}
@@ -204,13 +194,9 @@ private void ClearPaths()
{
File.Delete(GetPathStoragePath());
- using (var fs = File.Create(GetPathStoragePath()))
- {
- using (var bw = new BinaryWriter(fs))
- {
- bw.Write(FormatVersion);
- }
- }
+ using var fs = File.Create(GetPathStoragePath());
+ using var bw = new BinaryWriter(fs);
+ bw.Write(FormatVersion);
}
}
diff --git a/Everlook/Content/Shaders/Components/SolidWireframe/SolidWireframeGeometry.glsl b/Everlook/Content/Shaders/Components/SolidWireframe/SolidWireframeGeometry.glsl
index 1daa851..d08ee61 100644
--- a/Everlook/Content/Shaders/Components/SolidWireframe/SolidWireframeGeometry.glsl
+++ b/Everlook/Content/Shaders/Components/SolidWireframe/SolidWireframeGeometry.glsl
@@ -40,7 +40,7 @@ out GeometryOut
flat vec2 ABDir;
} gOut;
-uniform mat3 ViewportMatrix;
+uniform mat4 ViewportMatrix;
uniform bool IsWireframeEnabled;
void InitializeOutput()
@@ -124,13 +124,13 @@ int DetermineCase(float P0z, float P1z, float P2z)
vec2 ComputeLineDirection(int Q, int QPrim)
{
vec4 Qp = gl_in[Q].gl_Position;
- vec3 Qv = ProjectToScreen(ViewportMatrix, Qp);
+ vec3 Qv = ProjectToScreen(mat3(ViewportMatrix), Qp);
vec4 QPrimp = gl_in[QPrim].gl_Position;
return normalize
(
Qv -
- ProjectToScreen(ViewportMatrix, Qp + (QPrimp - Qp))
+ ProjectToScreen(mat3(ViewportMatrix), Qp + (QPrimp - Qp))
).xy;
}
@@ -149,8 +149,8 @@ void SetComplexCasePoints(int complexCase)
gOut.IsSimpleWireframeCase = false;
TriangleProjectionIndexes projectionIndices = ProjectionLookup[complexCase];
- gOut.A = ProjectToScreen(ViewportMatrix, gl_in[projectionIndices.A].gl_Position).xy;
- gOut.B = ProjectToScreen(ViewportMatrix, gl_in[projectionIndices.B].gl_Position).xy;
+ gOut.A = ProjectToScreen(mat3(ViewportMatrix), gl_in[projectionIndices.A].gl_Position).xy;
+ gOut.B = ProjectToScreen(mat3(ViewportMatrix), gl_in[projectionIndices.B].gl_Position).xy;
gOut.ADir = ComputeLineDirection(projectionIndices.A, projectionIndices.APrim);
gOut.BDir = ComputeLineDirection(projectionIndices.B, projectionIndices.BPrim);
@@ -181,7 +181,7 @@ void ComputeEdgeDistanceData()
vec2 P[3];
for (int i = 0; i < 3; ++i)
{
- P[i] = ProjectToScreen(ViewportMatrix, gl_in[i].gl_Position).xy;
+ P[i] = ProjectToScreen(mat3(ViewportMatrix), gl_in[i].gl_Position).xy;
}
EdgeDistances = ComputeVertexHeights(P);
diff --git a/Everlook/Database/Access/WMOAreaTableAccess.cs b/Everlook/Database/Access/WMOAreaTableAccess.cs
index fc64765..2e3cd6b 100644
--- a/Everlook/Database/Access/WMOAreaTableAccess.cs
+++ b/Everlook/Database/Access/WMOAreaTableAccess.cs
@@ -53,7 +53,7 @@ ForeignKey groupID
throw new ArgumentException("The given foreign key is not valid for searching by WMO group ID.");
}
- return database.FirstOrDefault(x => x.WMOGroupID == groupID.Key);
+ return database.First(x => x?.WMOGroupID == groupID.Key) ?? throw new InvalidOperationException();
}
///
@@ -72,7 +72,7 @@ public static WMOAreaTableRecord GetWMOArea(this DBC databas
throw new ArgumentException("The given foreign key is not valid for searching by WMO ID.");
}
- return database.FirstOrDefault(x => x.WMOID == wmoID.Key);
+ return database.First(x => x?.WMOID == wmoID.Key) ?? throw new InvalidOperationException();
}
}
}
diff --git a/Everlook/Database/ClientDatabaseProvider.cs b/Everlook/Database/ClientDatabaseProvider.cs
index e230b3d..5bb1195 100644
--- a/Everlook/Database/ClientDatabaseProvider.cs
+++ b/Everlook/Database/ClientDatabaseProvider.cs
@@ -22,7 +22,6 @@
using System;
using System.Collections.Generic;
-using System.IO;
using Warcraft.Core;
using Warcraft.DBC;
using Warcraft.DBC.Definitions;
@@ -98,7 +97,7 @@ public ClientDatabaseProvider(WarcraftVersion version, IPackage contentSource)
public T GetRecordByID(int id) where T : DBCRecord, new()
{
var database = GetDatabase();
- return database.GetRecordByID(id);
+ return database.GetRecordByID(id) ?? throw new InvalidOperationException();
}
///
@@ -142,9 +141,16 @@ private void LoadDatabase(DatabaseName databaseName)
var specificDBCType = genericDBCType.MakeGenericType(GetRecordTypeFromDatabaseName(databaseName));
var databasePath = GetDatabasePackagePath(databaseName);
- var databaseData = _contentSource.ExtractFile(databasePath);
+ if (!_contentSource.TryExtractFile(databasePath, out var databaseData))
+ {
+ throw new InvalidOperationException();
+ }
+
+ if (!(Activator.CreateInstance(specificDBCType, _version, databaseData) is IDBC database))
+ {
+ throw new InvalidOperationException("Something caused the database instantiation to fail.");
+ }
- var database = (IDBC)Activator.CreateInstance(specificDBCType, _version, databaseData);
_databases.Add(databaseName, database);
}
diff --git a/Everlook/Database/TypeTranslatorHelpers.cs b/Everlook/Database/TypeTranslatorHelpers.cs
index c1edc03..042b81b 100644
--- a/Everlook/Database/TypeTranslatorHelpers.cs
+++ b/Everlook/Database/TypeTranslatorHelpers.cs
@@ -37,7 +37,13 @@ public static class TypeTranslatorHelpers
/// The type mapping to the database name.
public static Type GetRecordTypeFromDatabaseName(DatabaseName databaseName)
{
- return Type.GetType($"Warcraft.DBC.Definitions.{databaseName}Record, libwarcraft");
+ var type = Type.GetType($"Warcraft.DBC.Definitions.{databaseName}Record, libwarcraft");
+ if (type is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return type;
}
///
diff --git a/Everlook/Everlook.csproj b/Everlook/Everlook.csproj
index ca1baf7..a91e09c 100644
--- a/Everlook/Everlook.csproj
+++ b/Everlook/Everlook.csproj
@@ -1,14 +1,11 @@
- WinExe
- net461
+ Exe
+ netcoreapp3.1
false
true
- x86
$(DefineConstants);GTK3;
- true
- ..\stylecop.ruleset
true
@@ -19,6 +16,14 @@
2.0.0
An open-source World of Warcraft model viewer.
+
+
+
+
+ PreserveNewest
+
+
+
false
@@ -44,9 +49,6 @@
-
- PreserveNewest
-
PreserveNewest
@@ -54,20 +56,23 @@
+
-
+
-
+
-
-
+
+
+
+
+
+
-
+
-
-
-
+
@@ -77,7 +82,9 @@
+
+
diff --git a/Everlook/Exceptions/Shader/ShaderCompilationException.cs b/Everlook/Exceptions/Shader/ShaderCompilationException.cs
index da7fac2..68af3d3 100644
--- a/Everlook/Exceptions/Shader/ShaderCompilationException.cs
+++ b/Everlook/Exceptions/Shader/ShaderCompilationException.cs
@@ -21,7 +21,7 @@
//
using System;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Exceptions.Shader
{
diff --git a/Everlook/Explorer/FileReference.cs b/Everlook/Explorer/FileReference.cs
index d3e10cc..72a9f06 100644
--- a/Everlook/Explorer/FileReference.cs
+++ b/Everlook/Explorer/FileReference.cs
@@ -21,8 +21,8 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
-using System.Threading.Tasks;
using Everlook.Utility;
using FileTree.Tree.Nodes;
using FileTree.Tree.Serialized;
@@ -52,19 +52,31 @@ public class FileReference : GLib.Object, IEquatable
/// Gets the name of the package where the file is stored.
///
/// The name of the package.
- public string PackageName { get; } = string.Empty;
+ public string PackageName { get; }
///
/// Gets the file path of the file inside the package. This string uses the backslash character ('\') as its
/// directory separator.
///
/// The file path.
- public string FilePath { get; } = string.Empty;
+ public string FilePath { get; }
///
/// Gets the directory that the file resides in.
///
- public string FileDirectory => Path.GetDirectoryName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar));
+ public string FileDirectory
+ {
+ get
+ {
+ var directory = Path.GetDirectoryName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar));
+ if (directory is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return directory;
+ }
+ }
///
/// Gets the file info of this reference.
@@ -74,12 +86,12 @@ public MPQFileInfo? ReferenceInfo
{
get
{
- if (this.IsFile)
+ if (!this.IsFile)
{
- return this.Context.Assets.GetReferenceInfo(this);
+ return null;
}
- return null;
+ return this.Context.Assets.TryGetReferenceInfo(this, out var result) ? result : null;
}
}
@@ -115,9 +127,22 @@ public MPQFileInfo? ReferenceInfo
///
/// Gets the name of the file or directory.
///
- public string Filename => this.IsDirectory ?
- Path.GetDirectoryName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar)) :
- Path.GetFileName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar));
+ public string Filename
+ {
+ get
+ {
+ var filename = this.IsDirectory
+ ? Path.GetDirectoryName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar))
+ : Path.GetFileName(this.FilePath.Replace('\\', Path.DirectorySeparatorChar));
+
+ if (filename is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return filename;
+ }
+ }
///
/// Initializes a new instance of the class.
@@ -135,21 +160,13 @@ public FileReference(IGameContext gameContext, SerializedNode node, string packa
}
///
- /// Asynchronously extracts this instance from the package group it is associated with.
+ /// Attempts to extract this instance from the package group it is associated with.
///
- /// A task wrapping the raw data of the file pointed to by the reference.
- public Task ExtractAsync()
+ /// The extracted data.
+ /// true if the data was successfully extracted; otherwise, false.
+ public bool TryExtract([NotNullWhen(true)] out byte[]? data)
{
- return Task.Factory.StartNew(Extract);
- }
-
- ///
- /// Extracts this instance from the package group it is associated with.
- ///
- /// The raw data of the file pointed to by the reference.
- public byte[]? Extract()
- {
- return this.Context.Assets.ExtractVersionedReference(this);
+ return this.Context.Assets.TryExtractVersionedReference(this, out data);
}
///
@@ -162,23 +179,22 @@ public WarcraftFileType GetReferencedFileType()
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var other = obj as FileReference;
- return other != null && Equals(other);
+ return obj is FileReference other && Equals(other);
}
///
public bool Equals(FileReference other)
{
- if (other != null)
+ if (other is null)
{
- return
- this.Context.Equals(other.Context) &&
- this.PackageName == other.PackageName &&
- this.FilePath == other.FilePath;
+ return false;
}
- return false;
+
+ return this.Context.Equals(other.Context) &&
+ this.PackageName == other.PackageName &&
+ this.FilePath == other.FilePath;
}
///
diff --git a/Everlook/Explorer/FileTreeModel.cs b/Everlook/Explorer/FileTreeModel.cs
index 5a90056..267cf8c 100644
--- a/Everlook/Explorer/FileTreeModel.cs
+++ b/Everlook/Explorer/FileTreeModel.cs
@@ -36,7 +36,7 @@
namespace Everlook.Explorer
{
///
- /// GTK TreeModel which serves an .
+ /// GTK TreeModel which serves tree nodes.
///
public class FileTreeModel : Object, ITreeModelImplementor
{
@@ -127,11 +127,6 @@ public string GetNodeFilePath(SerializedNode node)
/// A set of all the child references of the given reference.
public IEnumerable EnumerateFilesOfReference(FileReference fileReference)
{
- if (fileReference == null)
- {
- yield break;
- }
-
if (fileReference.IsFile)
{
yield return fileReference;
@@ -184,7 +179,7 @@ public FileReference GetReferenceByIter(IGameContext gameContext, TreeIter iter)
}
var node = _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
throw new InvalidDataException("The iter did not contain a valid node offset.");
}
@@ -312,7 +307,7 @@ public TreePath GetPath(TreeIter iter)
var result = new TreePath();
var node = _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
return result;
}
@@ -345,7 +340,7 @@ public void GetValue(TreeIter iter, int column, ref Value value)
}
var node = iter.Equals(TreeIter.Zero) ? _tree.Root : _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
return;
}
@@ -374,13 +369,13 @@ public bool IterNext(ref TreeIter iter)
var currentIndex = parentNode.ChildOffsets.IndexOf(currentOffset);
var nextIndex = currentIndex + 1;
- if (nextIndex < (int)parentNode.ChildCount)
+ if (nextIndex >= (int)parentNode.ChildCount)
{
- iter.UserData = new IntPtr((long)parentNode.ChildOffsets[nextIndex]);
- return true;
+ return false;
}
- return false;
+ iter.UserData = new IntPtr((long)parentNode.ChildOffsets[nextIndex]);
+ return true;
}
///
@@ -404,13 +399,13 @@ public bool IterPrevious(ref TreeIter iter)
var currentIndex = parentNode.ChildOffsets.IndexOf(currentOffset);
var previousIndex = currentIndex - 1;
- if (previousIndex >= 0 && previousIndex < (int)parentNode.ChildCount)
+ if (previousIndex < 0 || previousIndex >= (int)parentNode.ChildCount)
{
- iter.UserData = new IntPtr((long)parentNode.ChildOffsets[previousIndex]);
- return true;
+ return false;
}
- return false;
+ iter.UserData = new IntPtr((long)parentNode.ChildOffsets[previousIndex]);
+ return true;
}
///
@@ -431,7 +426,7 @@ public bool IterChildren(out TreeIter iter, TreeIter parent)
iter = TreeIter.Zero;
var node = parent.Equals(TreeIter.Zero) ? _tree.Root : _tree.GetNode((ulong)parent.UserData);
- if (node == null)
+ if (node is null)
{
throw new ArgumentException("The given iter was not valid.", nameof(parent));
}
@@ -461,7 +456,7 @@ public bool IterHasChild(TreeIter iter)
}
var node = iter.Equals(TreeIter.Zero) ? _tree.Root : _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
throw new ArgumentException("The given iter was not valid.", nameof(iter));
}
@@ -489,7 +484,7 @@ public int IterNChildren(TreeIter iter)
}
var node = _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
throw new ArgumentException("The given iter was not valid.", nameof(iter));
}
@@ -522,7 +517,7 @@ public bool IterNthChild(out TreeIter iter, TreeIter parent, int n)
var node = iter.Equals(TreeIter.Zero) ? _tree.Root : _tree.GetNode((ulong)iter.UserData);
- if (node == null)
+ if (node is null)
{
throw new ArgumentException("The given iter was not valid.", nameof(parent));
}
@@ -555,13 +550,13 @@ public bool IterParent(out TreeIter iter, TreeIter child)
iter = TreeIter.Zero;
var childNode = _tree.GetNode((ulong)child.UserData);
- if (childNode == null)
+ if (childNode is null)
{
throw new ArgumentException("The given iter was not valid.", nameof(child));
}
var parentNode = _tree.GetNode((ulong)childNode.ParentOffset);
- if (parentNode == null)
+ if (parentNode is null)
{
return false;
}
diff --git a/Everlook/Explorer/GameLoader.cs b/Everlook/Explorer/GameLoader.cs
index d0c76e1..3e7b058 100644
--- a/Everlook/Explorer/GameLoader.cs
+++ b/Everlook/Explorer/GameLoader.cs
@@ -85,7 +85,7 @@ private static Task LoadDictionaryAsync(CancellationToken ct
/// A cancellation token.
/// An object for progress reporting.
/// A tuple with a package group and a node tree for the requested game.
- public async Task<(PackageGroup? packageGroup, SerializedTree? nodeTree)> LoadGameAsync
+ public async Task<(PackageGroup? PackageGroup, SerializedTree? NodeTree)> LoadGameAsync
(
string gameAlias,
string gamePath,
@@ -156,7 +156,7 @@ private static Task LoadDictionaryAsync(CancellationToken ct
double totalSteps = packagePaths.Count * 2;
// Load packages
- var packages = new List<(string packageName, IPackage package)>();
+ var packages = new List<(string PackageName, IPackage Package)>();
foreach (var packagePath in packagePaths)
{
ct.ThrowIfCancellationRequested();
@@ -182,7 +182,7 @@ private static Task LoadDictionaryAsync(CancellationToken ct
}
// Load dictionary if neccesary
- if (_dictionary == null)
+ if (_dictionary is null)
{
progress?.Report(new GameLoadingProgress
{
@@ -219,15 +219,15 @@ private static Task LoadDictionaryAsync(CancellationToken ct
CompletionPercentage = steps / totalSteps,
State = GameLoadingState.BuildingNodeTree,
Alias = gameAlias,
- CurrentPackage = packageInfo.packageName,
+ CurrentPackage = packageInfo.PackageName,
NodesCreationProgress = p
}
);
}
);
- await Task.Run(() => builder.AddPackage(packageInfo.packageName, packageInfo.package, createNodesProgress, ct), ct);
- packageGroup.AddPackage((PackageInteractionHandler)packageInfo.package);
+ await Task.Run(() => builder.AddPackage(packageInfo.PackageName, packageInfo.Package, createNodesProgress, ct), ct);
+ packageGroup.AddPackage((PackageInteractionHandler)packageInfo.Package);
++completedSteps;
}
@@ -257,12 +257,10 @@ private static Task LoadDictionaryAsync(CancellationToken ct
var treeClosureCopy = tree;
tree = await Task.Run(() => optimizer.OptimizeTree(treeClosureCopy, optimizeTreeProgress, ct), ct);
- using (var fs = File.OpenWrite(packageTreeFilePath))
+ await using (var fs = File.OpenWrite(packageTreeFilePath))
{
- using (var serializer = new TreeSerializer(fs))
- {
- await serializer.SerializeAsync(tree, ct);
- }
+ using var serializer = new TreeSerializer(fs);
+ await serializer.SerializeAsync(tree, ct);
}
nodeTree = new SerializedTree(File.OpenRead(packageTreeFilePath));
@@ -309,13 +307,11 @@ private static string GeneratePathSetHash(IEnumerable packagePaths)
sb.Append(packageSize);
}
- using (var md5 = MD5.Create())
- {
- var input = Encoding.UTF8.GetBytes(sb.ToString());
- var hash = md5.ComputeHash(input);
+ using var md5 = MD5.Create();
+ var input = Encoding.UTF8.GetBytes(sb.ToString());
+ var hash = md5.ComputeHash(input);
- return BitConverter.ToString(hash);
- }
+ return BitConverter.ToString(hash);
}
}
}
diff --git a/Everlook/Explorer/GamePage.cs b/Everlook/Explorer/GamePage.cs
index d38c974..debc7da 100644
--- a/Everlook/Explorer/GamePage.cs
+++ b/Everlook/Explorer/GamePage.cs
@@ -337,7 +337,7 @@ private void RenderNodeIcon(TreeViewColumn column, CellRenderer cell, ITreeModel
var cellIcon = cell as CellRendererPixbuf;
var node = (SerializedNode)model.GetValue(iter, 0);
- if (node == null || cellIcon == null)
+ if (node is null || cellIcon is null)
{
return;
}
@@ -381,7 +381,7 @@ private void RenderNodeName(TreeViewColumn column, CellRenderer cell, ITreeModel
var cellText = cell as CellRendererText;
var node = (SerializedNode)model.GetValue(iter, 0);
- if (node == null || cellText == null)
+ if (node is null || cellText is null)
{
return;
}
@@ -405,10 +405,10 @@ private void RenderNodeName(TreeViewColumn column, CellRenderer cell, ITreeModel
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnQueueForExportRequested(object sender, EventArgs eventArgs)
+ private void OnQueueForExportRequested(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -421,10 +421,10 @@ private void OnQueueForExportRequested(object sender, EventArgs eventArgs)
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnExportItemRequested(object sender, EventArgs eventArgs)
+ private void OnExportItemRequested(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -439,10 +439,10 @@ private void OnExportItemRequested(object sender, EventArgs eventArgs)
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnOpenItem(object sender, EventArgs eventArgs)
+ private void OnOpenItem(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -465,10 +465,10 @@ private void OnOpenItem(object sender, EventArgs eventArgs)
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnCopyPath(object sender, EventArgs eventArgs)
+ private void OnCopyPath(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -483,10 +483,10 @@ private void OnCopyPath(object sender, EventArgs eventArgs)
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnSaveItem(object sender, EventArgs eventArgs)
+ private void OnSaveItem(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -525,7 +525,7 @@ private void OnButtonPressed(object o, ButtonPressEventArgs args)
var filterPath = _treeSorter.ConvertPathToChildPath(sorterPath);
var modelPath = _treeFilter.ConvertPathToChildPath(filterPath);
- if (modelPath == null)
+ if (modelPath is null)
{
_saveItem.Sensitive = false;
_exportItem.Sensitive = false;
@@ -554,9 +554,7 @@ private void OnButtonPressed(object o, ButtonPressEventArgs args)
}
_treeContextMenu.ShowAll();
-
- //this.TreeContextMenu.Popup(); // only available in GTK >= 3.22
- _treeContextMenu.PopupForDevice(args.Event.Device, null, null, null, null, args.Event.Button, args.Event.Time);
+ _treeContextMenu.PopupAtPointer(args.Event);
}
///
@@ -565,10 +563,10 @@ private void OnButtonPressed(object o, ButtonPressEventArgs args)
///
/// The sending object.
/// Arguments describing the row that was activated.
- private void OnSelectionChanged(object sender, EventArgs eventArgs)
+ private void OnSelectionChanged(object? sender, EventArgs eventArgs)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -587,7 +585,7 @@ private void OnSelectionChanged(object sender, EventArgs eventArgs)
private void OnRowActivated(object o, RowActivatedArgs args)
{
var fileReference = GetSelectedReference();
- if (fileReference == null)
+ if (fileReference is null)
{
return;
}
@@ -655,8 +653,7 @@ private static void OpenReference(FileReference fileReference)
case WarcraftFileType.Font:
case WarcraftFileType.Script:
{
- var fileData = fileReference.Extract();
- if (fileData != null)
+ if (fileReference.TryExtract(out var fileData))
{
// create a temporary file and write the data to it.
var tempPath = Path.Combine(Path.GetTempPath(), fileReference.Filename);
diff --git a/Everlook/Export/Model/AssimpConverter.cs b/Everlook/Export/Model/AssimpConverter.cs
index 5948493..9b92ee2 100644
--- a/Everlook/Export/Model/AssimpConverter.cs
+++ b/Everlook/Export/Model/AssimpConverter.cs
@@ -21,9 +21,12 @@
//
using System;
+using System.Collections.Generic;
using System.Linq;
using Assimp;
using Warcraft.MDX;
+using Warcraft.MDX.Data;
+using Warcraft.MDX.Geometry.Skin;
namespace Everlook.Export.Model
{
@@ -50,12 +53,32 @@ public static Scene FromMDX(MDX model)
var defaultMaterial = new Material();
scene.Materials.Add(defaultMaterial);
+ if (model.Skins is null)
+ {
+ return scene;
+ }
+
foreach (var skin in model.Skins)
{
var skinNode = new Node($"LOD_{model.Skins.ToList().IndexOf(skin)}", modelNode);
modelNode.Children.Add(skinNode);
- var skinVerts = skin.VertexIndices.Select(i => model.Vertices[i]).ToArray();
+ if (skin.VertexIndices is null)
+ {
+ continue;
+ }
+
+ if (model.Vertices is null)
+ {
+ continue;
+ }
+
+ var skinVerts = skin.VertexIndices.Select(i => model.Vertices?[i]).ToArray();
+
+ if (skin.Sections is null)
+ {
+ continue;
+ }
foreach (var section in skin.Sections)
{
@@ -64,13 +87,16 @@ public static Scene FromMDX(MDX model)
mesh.MaterialIndex = scene.Materials.IndexOf(defaultMaterial);
- var modelBones = model.Bones.Skip(section.StartBoneIndex).Take(section.BoneCount);
- foreach (var modelBone in modelBones)
+ if (!(model.Bones is null))
{
- var bone = new Bone();
+ var modelBones = model.Bones.Skip(section.StartBoneIndex).Take(section.BoneCount);
+ foreach (var modelBone in modelBones)
+ {
+ var bone = new Bone();
- // TODO: Calculate offset matrices
- mesh.Bones.Add(bone);
+ // TODO: Calculate offset matrices
+ mesh.Bones.Add(bone);
+ }
}
var batchNode = new Node($"Section_{skin.Sections.ToList().IndexOf(section)}", skinNode);
@@ -93,24 +119,36 @@ public static Scene FromMDX(MDX model)
var localIndex = skinVertexIndexes[i];
var vertex = skinVerts[localIndex];
+ if (vertex is null)
+ {
+ continue;
+ }
+
mesh.Vertices.Add(new Vector3D(vertex.Position.X, vertex.Position.Y, vertex.Position.Z));
mesh.Normals.Add(new Vector3D(vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z));
mesh.TextureCoordinateChannels[0].Add(new Vector3D(vertex.UV1.X, vertex.UV1.Y, 0.0f));
mesh.TextureCoordinateChannels[1].Add(new Vector3D(vertex.UV2.X, vertex.UV2.Y, 0.0f));
- if (mesh.HasBones)
+ if (!mesh.HasBones)
{
- for (var boneAttributeIndex = 0; boneAttributeIndex < 4; ++boneAttributeIndex)
- {
- var bone = mesh.Bones[vertex.BoneIndices[boneAttributeIndex]];
+ continue;
+ }
- var weight = vertex.BoneWeights[boneAttributeIndex];
- bone.VertexWeights.Add(new VertexWeight(i, weight));
- }
+ for (var boneAttributeIndex = 0; boneAttributeIndex < 4; ++boneAttributeIndex)
+ {
+ var bone = mesh.Bones[vertex.BoneIndices[boneAttributeIndex]];
+
+ var weight = vertex.BoneWeights[boneAttributeIndex];
+ bone.VertexWeights.Add(new VertexWeight(i, weight));
}
}
+ if (skin.Triangles is null)
+ {
+ continue;
+ }
+
var triangleIndexes = new Span
(
skin.Triangles.ToArray(),
diff --git a/Everlook/Native/IGTKGLExt.cs b/Everlook/Native/IGTKGLExt.cs
new file mode 100644
index 0000000..d3447a0
--- /dev/null
+++ b/Everlook/Native/IGTKGLExt.cs
@@ -0,0 +1,42 @@
+//
+// IGTKGLExt.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2017 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using AdvancedDLSupport;
+
+// ReSharper disable ExplicitCallerInfoArgument
+namespace Everlook.Native
+{
+ ///
+ /// Represents the native interface to the GTK GL Extensions library.
+ ///
+ public interface IGTKGLExt
+ {
+ ///
+ /// Gets a function pointer to the named symbol via GDK.
+ ///
+ /// The name of the symbol.
+ /// A pointer to the symbol, or IntPtr.Zero.
+ [NativeSymbol("gdk_gl_get_proc_address")]
+ IntPtr GetProcAddress(string functionName);
+ }
+}
diff --git a/Everlook/OpenTK.dll.config b/Everlook/OpenTK.dll.config
deleted file mode 100644
index 873737e..0000000
--- a/Everlook/OpenTK.dll.config
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Everlook/Package/PackageGroup.cs b/Everlook/Package/PackageGroup.cs
index ae65c73..3727b13 100644
--- a/Everlook/Package/PackageGroup.cs
+++ b/Everlook/Package/PackageGroup.cs
@@ -193,11 +193,6 @@ public void LoadPackagesFromPath(string path)
/// Thrown if the package is null.
public void AddPackage(PackageInteractionHandler package)
{
- if (package == null)
- {
- throw new ArgumentNullException(nameof(package));
- }
-
if (_packages.Contains(package))
{
return;
@@ -207,77 +202,67 @@ public void AddPackage(PackageInteractionHandler package)
}
///
- /// Gets the reference info for the specified reference. This method gets the most recent info for the file from
- /// overriding packages.
+ /// Attempts to get the reference info for the specified reference. This method gets the most recent info for
+ /// the file from overriding packages.
///
/// The reference info.
/// Reference reference.
- public MPQFileInfo GetReferenceInfo(FileReference fileReference)
+ /// The file information.
+ public bool TryGetReferenceInfo(FileReference fileReference, [NotNullWhen(true)] out MPQFileInfo? fileInfo)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
- return GetFileInfo(fileReference.FilePath);
+ return TryGetFileInfo(fileReference.FilePath, out fileInfo);
}
///
- /// Gets the file info for the specified reference in its specific package. If the file does not exist in
- /// the package referenced in , this method returned will return null.
+ /// Attempts to get the file info for the specified reference in its specific package. If the file does not
+ /// exist in the package referenced in , this method will return false.
///
/// The reference info.
/// Reference reference.
- public MPQFileInfo? GetVersionedReferenceInfo(FileReference fileReference)
+ /// The file info.
+ public bool TryGetVersionedReferenceInfo
+ (
+ FileReference fileReference,
+ [NotNullWhen(true)] out MPQFileInfo? fileInfo
+ )
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
var package = GetPackageByName(fileReference.PackageName);
- return package.GetReferenceInfo(fileReference);
+ return package.TryGetReferenceInfo(fileReference, out fileInfo);
}
///
- /// Extracts a file from a specific package in the package group. If the file does not exist in
+ /// Attempts to extract a file from a specific package in the package group. If the file does not exist in
/// the package referenced in , this method returned will return null.
///
/// The unversioned file or null.
/// Reference reference.
- public byte[]? ExtractVersionedReference(FileReference fileReference)
+ /// The data.
+ public bool TryExtractVersionedReference(FileReference fileReference, [NotNullWhen(true)] out byte[]? data)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
+ data = null;
if (fileReference.IsVirtual)
{
- return ExtractReference(fileReference);
+ return TryExtractReference(fileReference, out data);
}
var package = GetPackageByName(fileReference.PackageName);
- return package?.ExtractReference(fileReference);
+ return package.TryExtractReference(fileReference, out data);
}
///
- /// Extracts a file from the package group. This method returns the most recently overridden version
+ /// Attempts to extract a file from the package group. This method returns the most recently overridden version
/// of the specified file with no regard for the origin package. The returned file may originate from the
/// package referenced in the , or it may originate from a patch package.
///
- /// If the file does not exist in any package, this method will return null.
+ /// If the file does not exist in any package, this method will return false.
///
/// The file or null.
/// Reference reference.
- public byte[] ExtractReference(FileReference fileReference)
+ /// The data.
+ public bool TryExtractReference(FileReference fileReference, [NotNullWhen(true)] out byte[]? data)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
- return ExtractFile(fileReference.FilePath);
+ return TryExtractFile(fileReference.FilePath, out data);
}
///
@@ -287,7 +272,7 @@ public byte[] ExtractReference(FileReference fileReference)
/// Reference reference.
public bool ContainsReference(FileReference fileReference)
{
- if (fileReference == null)
+ if (fileReference is null)
{
throw new ArgumentNullException(nameof(fileReference));
}
@@ -323,7 +308,7 @@ private PackageInteractionHandler GetPackageByName(string packageName)
}
///
- public bool TryExtractFile(string filePath, out byte[]? data)
+ public bool TryExtractFile(string filePath, [NotNullWhen(true)] out byte[]? data)
{
data = null;
@@ -338,20 +323,6 @@ public bool TryExtractFile(string filePath, out byte[]? data)
return false;
}
- ///
- public byte[] ExtractFile(string filePath)
- {
- for (var i = _packages.Count - 1; i >= 0; --i)
- {
- if (_packages[i].TryExtractFile(filePath, out var data))
- {
- return data;
- }
- }
-
- throw new FileNotFoundException("The specified file was not found in this package group.", filePath);
- }
-
///
public bool HasFileList()
{
@@ -359,9 +330,9 @@ public bool HasFileList()
}
///
- public IEnumerable? GetFileList()
+ public IEnumerable GetFileList()
{
- return null;
+ return new List();
}
///
@@ -387,8 +358,7 @@ public bool TryGetFileInfo(string filePath, [NotNullWhen(true)] out MPQFileInfo?
{
if (_packages[i].ContainsFile(filePath))
{
- fileInfo = _packages[i].GetFileInfo(filePath);
- return true;
+ return _packages[i].TryGetFileInfo(filePath, out fileInfo);
}
}
@@ -396,21 +366,9 @@ public bool TryGetFileInfo(string filePath, [NotNullWhen(true)] out MPQFileInfo?
}
///
- public MPQFileInfo GetFileInfo(string filePath)
- {
- if (!TryGetFileInfo(filePath, out var fileInfo))
- {
- throw new FileNotFoundException("The specified file was not found in this package group.", filePath);
- }
-
- return fileInfo;
- }
-
- ///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var other = obj as PackageGroup;
- if (other != null)
+ if (obj is PackageGroup other)
{
return this.GroupName.Equals(other.GroupName) &&
_packages.Equals(other._packages);
diff --git a/Everlook/Package/PackageInteractionHandler.cs b/Everlook/Package/PackageInteractionHandler.cs
index 3db4bdb..d86ad39 100644
--- a/Everlook/Package/PackageInteractionHandler.cs
+++ b/Everlook/Package/PackageInteractionHandler.cs
@@ -26,8 +26,6 @@
using System.IO;
using System.Threading.Tasks;
using Everlook.Explorer;
-using log4net;
-using Warcraft.Core;
using Warcraft.MPQ;
using Warcraft.MPQ.FileInfo;
@@ -39,11 +37,6 @@ namespace Everlook.Package
///
public sealed class PackageInteractionHandler : IDisposable, IPackage
{
- ///
- /// Logger instance for this class.
- ///
- private static readonly ILog Log = LogManager.GetLogger(typeof(PackageInteractionHandler));
-
///
/// Gets the package path.
///
@@ -58,7 +51,19 @@ public string? PackagePath
/// Gets the name of the package.
///
/// The name of the package.
- public string PackageName => Path.GetFileNameWithoutExtension(this.PackagePath);
+ public string PackageName
+ {
+ get
+ {
+ var filename = Path.GetFileNameWithoutExtension(this.PackagePath);
+ if (filename is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return filename;
+ }
+ }
private MPQ? _package;
@@ -135,46 +140,30 @@ public bool ContainsFile(FileReference fileReference)
}
///
- /// Extracts the specified reference from its associated package. This method only operates on the file path.
+ /// Attempts to extract a file from the package group. This method returns the most recently overridden version
+ /// of the specified file with no regard for the origin package. The returned file may originate from the
+ /// package referenced in the , or it may originate from a patch package.
+ ///
+ /// If the file does not exist in any package, this method will return false.
///
+ /// The file or null.
/// Reference reference.
- /// The raw data of the file pointed to by the reference.
- public byte[]? ExtractReference(FileReference fileReference)
+ /// The data.
+ public bool TryExtractReference(FileReference fileReference, [NotNullWhen(true)] out byte[]? data)
{
- if (!fileReference.IsFile)
- {
- throw new ArgumentException("The specified reference can't be extracted.", nameof(fileReference));
- }
-
- try
- {
- return ExtractFile(fileReference.FilePath);
- }
- catch (InvalidFileSectorTableException fex)
- {
- Log.Warn
- (
- $"Failed to extract the file \"{fileReference.FilePath}\" due to an invalid sector table " +
- $"(\"{fex.Message}\")."
- );
- throw;
- }
+ return TryExtractFile(fileReference.FilePath, out data);
}
///
- /// Gets a set of information about the specified package file, such as stored size, disk size
- /// and storage flags.
+ /// Attempts to get the reference info for the specified reference. This method gets the most recent info for
+ /// the file from overriding packages.
///
/// The reference info.
/// Reference reference.
- public MPQFileInfo? GetReferenceInfo(FileReference fileReference)
+ /// The file information.
+ public bool TryGetReferenceInfo(FileReference fileReference, [NotNullWhen(true)] out MPQFileInfo? fileInfo)
{
- if (!fileReference.IsFile)
- {
- throw new ArgumentException("The specified reference is not a file.", nameof(fileReference));
- }
-
- return GetFileInfo(fileReference.FilePath);
+ return TryGetFileInfo(fileReference.FilePath, out fileInfo);
}
///
@@ -190,12 +179,6 @@ public bool TryExtractFile(string filePath, [NotNullWhen(true)] out byte[]? data
return _package.TryExtractFile(filePath, out data);
}
- ///
- public byte[]? ExtractFile(string filePath)
- {
- return _package?.ExtractFile(filePath);
- }
-
///
public bool HasFileList()
{
@@ -241,12 +224,6 @@ public bool TryGetFileInfo(string filePath, [NotNullWhen(true)] out MPQFileInfo?
return _package.TryGetFileInfo(filePath, out fileInfo);
}
- ///
- public MPQFileInfo? GetFileInfo(string filePath)
- {
- return _package?.GetFileInfo(filePath);
- }
-
///
public void Dispose()
{
diff --git a/Everlook/Program.cs b/Everlook/Program.cs
index c42806d..37a6c95 100644
--- a/Everlook/Program.cs
+++ b/Everlook/Program.cs
@@ -21,181 +21,112 @@
//
using System;
-using System.Globalization;
using System.IO;
+using System.Reflection;
using System.Runtime.InteropServices;
+using System.Xml;
using Everlook.Explorer;
+using Everlook.Silk;
using Everlook.UI;
using Everlook.Utility;
using FileTree.Tree.Serialized;
using GLib;
using log4net;
-using OpenTK;
+using log4net.Config;
+using log4net.Repository.Hierarchy;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Silk.NET.Core.Loader;
+using Silk.NET.Core.Platform;
+
using Application = Gtk.Application;
+using Task = System.Threading.Tasks.Task;
namespace Everlook
{
///
/// The main entry class, containing the entry point and some top-level diagnostics.
///
- internal static class Program
+ internal class Program
{
///
- /// Logger instance for this class.
+ /// Holds the logging instance for this class.
///
- private static readonly ILog Log = LogManager.GetLogger(typeof(Program));
+ private static ILogger? _log;
///
/// The entry point.
///
- public static void Main()
+ /// The command-line arguments.
+ /// A representing the asynchronous operation.
+ [STAThread]
+ public static async Task Main(string[] args)
{
- // Bind any unhandled exceptions in the main thread so that they are logged.
- AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
-
- // Set correct working directory for compatibility with double-clicking
- Directory.SetCurrentDirectory(DirectoryHelpers.GetLocalDir());
+ ExceptionManager.UnhandledException += OnUnhandledGLibException;
+ IconManager.LoadEmbeddedIcons();
+ Application.Init();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Environment.SetEnvironmentVariable("GSETTINGS_SCHEMA_DIR", "share\\glib-2.0\\schemas\\");
}
- log4net.Config.XmlConfigurator.Configure();
-
- Log.Info("----------------");
- Log.Info("Initializing Everlook...");
-
- Log.Info("Initializing OpenTK...");
-
- // OpenGL
- var toolkitOptions = new ToolkitOptions
+ const string configurationName = "Everlook.log4net.config";
+ var logConfig = new XmlDocument();
+ await using (var configStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(configurationName))
{
- Backend = PlatformBackend.PreferNative,
- EnableHighResolution = true
- };
-
- using (Toolkit.Init(toolkitOptions))
- {
- Log.Info($"OpenTK initialized using the {GetOpenTKBackend()} backend.");
+ if (configStream is null)
+ {
+ throw new InvalidOperationException("The log4net configuration stream could not be found.");
+ }
- Log.Info("Initializing GTK...");
+ logConfig.Load(configStream);
+ }
- // Bind any unhandled exceptions in the GTK UI so that they are logged.
- ExceptionManager.UnhandledException += OnGLibUnhandledException;
+ var repo = LogManager.CreateRepository(Assembly.GetEntryAssembly(), typeof(Hierarchy));
+ XmlConfigurator.Configure(repo, logConfig["log4net"]);
- Log.Info("Registering treeview types with the native backend...");
- var nodeType = (GType)typeof(SerializedNode);
- GType.Register(nodeType, typeof(SerializedNode));
+ SilkManager.Register(new GDKGLSymbolLoader());
- var referenceType = (GType)typeof(FileReference);
- GType.Register(referenceType, typeof(FileReference));
+ var nodeType = (GType)typeof(SerializedNode);
+ GType.Register(nodeType, typeof(SerializedNode));
- // GTK
- IconManager.LoadEmbeddedIcons();
- Application.Init();
- var win = MainWindow.Create();
- win.Show();
- Application.Run();
- }
- }
+ var referenceType = (GType)typeof(FileReference);
+ GType.Register(referenceType, typeof(FileReference));
- ///
- /// Gets the backend used by OpenTK.
- ///
- /// The name of the backend.
- private static string GetOpenTKBackend()
- {
- if (OpenTK.Configuration.RunningOnSdl2)
- {
- return "SDL2";
- }
+ var host = CreateHostBuilder(args).Build();
- if (OpenTK.Configuration.RunningOnX11)
- {
- return "X11";
- }
+ _log = host.Services.GetRequiredService>();
+ var app = host.Services.GetRequiredService();
+ app.Start();
- return "native";
+ Application.Run();
}
- ///
- /// Passes any unhandled exceptions from the GTK UI to the generic handler.
- ///
- /// The event object containing the information about the exception.
- private static void OnGLibUnhandledException(UnhandledExceptionArgs args)
+ private static void OnUnhandledGLibException(UnhandledExceptionArgs args)
{
- OnUnhandledException(null, args);
+ _log.LogError((Exception)args.ExceptionObject, "Unhandled GLib exception.");
}
- ///
- /// Event handler for all unhandled exceptions that may be encountered during runtime. While there should never
- /// be any unhandled exceptions in an ideal program, unexpected issues can and will arise. This handler logs
- /// the exception and all relevant information to a logfile and prints it to the console for debugging purposes.
- ///
- /// The sending object.
- ///
- /// The event object containing the information about the exception.
- ///
- private static void OnUnhandledException(object? sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
- {
- // Force english exception output
- System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
- System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
-
- Log.Fatal("----------------");
- Log.Fatal("FATAL UNHANDLED EXCEPTION!");
- Log.Fatal("Something has gone terribly, terribly wrong during runtime.");
- Log.Fatal("The following is what information could be gathered by the program before crashing.");
- Log.Fatal("Please report this to or via GitHub. Include the full log and a " +
- "description of what you were doing when it happened.");
-
- var unhandledException = (Exception)unhandledExceptionEventArgs.ExceptionObject;
- switch (unhandledException)
+ private static IHostBuilder CreateHostBuilder(string[] args) => new HostBuilder()
+ .ConfigureAppConfiguration((hostingContext, config) =>
{
- case null:
- {
- return;
- }
- case DllNotFoundException _:
- {
- Log.Fatal
- (
- "This exception is typical of instances where the GTK runtime has not been properly copied " +
- "to the working directory or is not available on your system.\n" +
- "If you're on Windows, make sure that the bundled GTK libraries are present.\n" +
- "If you're on macOS, try installing GTK through Homebrew.\n" +
- "If you're on Linux, check with your package maintainer that all dependencies are properly " +
- "listed."
- );
- break;
- }
- case GraphicsException _:
- {
- Log.Fatal
- (
- "Some type of graphics error occurred. On macOS, this is usally indicative of an OpenGL " +
- "context which doesn't meet Everlook's requirements. Please note that Everlook requires at " +
- "least OpenGL 3.3.\n" +
- "If you're running via XQuartz, please note that XQuartz does not provide contexts above " +
- "OpenGL 2.1."
- );
- break;
- }
- }
-
- Log.Fatal($"Exception type: {unhandledException!.GetType().FullName}");
- Log.Fatal($"Exception Message: {unhandledException.Message}");
- Log.Fatal($"Exception Stacktrace: {unhandledException.StackTrace}");
-
- if (unhandledException.InnerException == null)
+ config.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "config"));
+ config.AddJsonFile("appsettings.json");
+ })
+ .ConfigureServices((hostingContext, services) =>
{
- return;
- }
+ services.AddSingleton(new Application("net.Everlook.Everlook", ApplicationFlags.None));
- Log.Fatal($"Inner exception type: {unhandledException.InnerException.GetType().FullName}");
- Log.Fatal($"Inner exception Message: {unhandledException.InnerException.Message}");
- Log.Fatal($"Inner exception Stacktrace: {unhandledException.InnerException.StackTrace}");
- }
+ services.AddTransient(MainWindow.Create);
+ services.AddSingleton();
+ })
+ .ConfigureLogging(l =>
+ {
+ l.ClearProviders();
+ l.AddLog4Net();
+ });
}
}
diff --git a/Everlook/Silk/GDKGLSymbolLoader.cs b/Everlook/Silk/GDKGLSymbolLoader.cs
new file mode 100644
index 0000000..d31930f
--- /dev/null
+++ b/Everlook/Silk/GDKGLSymbolLoader.cs
@@ -0,0 +1,71 @@
+//
+// GDKGLSymbolLoader.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2017 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+using System.Runtime.InteropServices;
+using AdvancedDLSupport;
+using Everlook.Native;
+using Silk.NET.Core.Loader;
+
+namespace Everlook.Silk
+{
+ ///
+ /// Handles loading OpenGL symbols via GDK.
+ ///
+ public class GDKGLSymbolLoader : GLSymbolLoader
+ {
+ private readonly IGTKGLExt _gtkglExt;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public GDKGLSymbolLoader()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ _gtkglExt = NativeLibraryBuilder.Default.ActivateInterface("libgtkglext-x11-1.0");
+ }
+ else
+ {
+ _gtkglExt = NativeLibraryBuilder.Default.ActivateInterface("gtkglext-1.0");
+ }
+ }
+
+ ///
+ protected override IntPtr CoreLoadFunctionPointer(IntPtr handle, string functionName)
+ {
+ var glFunction = _gtkglExt.GetProcAddress(functionName);
+ if (glFunction != IntPtr.Zero)
+ {
+ return glFunction;
+ }
+
+ var systemFunction = this.UnderlyingLoader.LoadFunctionPointer(handle, functionName);
+ if (systemFunction != IntPtr.Zero)
+ {
+ return systemFunction;
+ }
+
+ throw new SymbolLoadingException();
+ }
+ }
+}
diff --git a/Everlook/Startup.cs b/Everlook/Startup.cs
new file mode 100644
index 0000000..0d83acf
--- /dev/null
+++ b/Everlook/Startup.cs
@@ -0,0 +1,64 @@
+//
+// Startup.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2017 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using Everlook.UI;
+using Gtk;
+
+namespace Everlook
+{
+ ///
+ /// Represents startup procedures for the application.
+ ///
+ public class Startup
+ {
+ private readonly Application _app;
+ private readonly MainWindow _mainWindow;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application information.
+ /// The main application window.
+ public Startup(Application app, MainWindow mainWindow)
+ {
+ _app = app;
+ _mainWindow = mainWindow;
+ }
+
+ ///
+ /// Starts the application.
+ ///
+ public void Start()
+ {
+ _app.Register(GLib.Cancellable.Current);
+ _app.AddWindow(_mainWindow);
+
+ _mainWindow.Show();
+ _mainWindow.DeleteEvent += DeletedEvent;
+ }
+
+ private void DeletedEvent(object o, DeleteEventArgs args)
+ {
+ Application.Quit();
+ }
+ }
+}
diff --git a/Everlook/UI/EverlookDirectoryExportDialog.cs b/Everlook/UI/EverlookDirectoryExportDialog.cs
index 373df6f..477600b 100644
--- a/Everlook/UI/EverlookDirectoryExportDialog.cs
+++ b/Everlook/UI/EverlookDirectoryExportDialog.cs
@@ -50,15 +50,13 @@ public partial class EverlookDirectoryExportDialog : Dialog
/// An initialized instance of the EverlookDirectoryExportDialog class.
public static EverlookDirectoryExportDialog Create(FileReference inExportTarget)
{
- using (var builder = new Builder(null, "Everlook.interfaces.EverlookDirectoryExport.glade", null))
- {
- return new EverlookDirectoryExportDialog
- (
- builder,
- builder.GetObject("EverlookDirectoryExportDialog").Handle,
- inExportTarget
- );
- }
+ using var builder = new Builder(null, "Everlook.interfaces.EverlookDirectoryExport.glade", null);
+ return new EverlookDirectoryExportDialog
+ (
+ builder,
+ builder.GetObject("EverlookDirectoryExportDialog").Handle,
+ inExportTarget
+ );
}
///
@@ -138,7 +136,7 @@ public void RunExport()
Directory.CreateDirectory(Directory.GetParent(exportPath).FullName);
byte[] fileData = referenceToExport.Extract();
- if (fileData != null)
+ if (!(fileData is null))
{
File.WriteAllBytes(exportPath, fileData);
}
@@ -155,15 +153,15 @@ public void RunExport()
/// Sender.
/// E.
[GLib.ConnectBefore]
- private void OnItemListingButtonPressed(object sender, ButtonPressEventArgs e)
+ private void OnItemListingButtonPressed(object? sender, ButtonPressEventArgs e)
{
- if (e.Event.Type == EventType.ButtonPress && e.Event.Button == 3)
+ if (e.Event.Type != EventType.ButtonPress || e.Event.Button != 3)
{
- _exportPopupMenu.ShowAll();
-
- _exportPopupMenu.PopupForDevice(e.Event.Device, null, null, null, null, e.Event.Button, e.Event.Time);
- //this.ExportPopupMenu.Popup();
+ return;
}
+
+ _exportPopupMenu.ShowAll();
+ _exportPopupMenu.PopupAtPointer(e.Event);
}
///
@@ -171,7 +169,7 @@ private void OnItemListingButtonPressed(object sender, ButtonPressEventArgs e)
///
/// Sender.
/// E.
- private void OnSelectAllItemActivated(object sender, EventArgs e)
+ private void OnSelectAllItemActivated(object? sender, EventArgs e)
{
_itemExportListStore.Foreach
(
@@ -188,7 +186,7 @@ private void OnSelectAllItemActivated(object sender, EventArgs e)
///
/// Sender.
/// E.
- private void OnSelectNoneItemActivated(object sender, EventArgs e)
+ private void OnSelectNoneItemActivated(object? sender, EventArgs e)
{
_itemExportListStore.Foreach
(
@@ -205,7 +203,7 @@ private void OnSelectNoneItemActivated(object sender, EventArgs e)
///
/// Sender.
/// E.
- private void OnExportItemToggleClicked(object sender, ToggledArgs e)
+ private void OnExportItemToggleClicked(object? sender, ToggledArgs e)
{
TreeIter iter;
_itemExportListStore.GetIterFromString(out iter, e.Path);
@@ -220,7 +218,7 @@ private void OnExportItemToggleClicked(object sender, ToggledArgs e)
///
/// Sender.
/// E.
- private void OnOkButtonClicked(object sender, EventArgs e)
+ private void OnOkButtonClicked(object? sender, EventArgs e)
{
RunExport();
}
diff --git a/Everlook/UI/EverlookGameLoadingDialog.cs b/Everlook/UI/EverlookGameLoadingDialog.cs
index efa8e6a..c9c20bc 100644
--- a/Everlook/UI/EverlookGameLoadingDialog.cs
+++ b/Everlook/UI/EverlookGameLoadingDialog.cs
@@ -72,10 +72,8 @@ public partial class EverlookGameLoadingDialog : Dialog
/// An initialized instance of the EverlookGameLoadingDialog class.
public static EverlookGameLoadingDialog Create(Window parent)
{
- using (var builder = new Builder(null, "Everlook.interfaces.EverlookGameLoadingDialog.glade", null))
- {
- return new EverlookGameLoadingDialog(builder, builder.GetObject("_gameLoadingDialog").Handle, parent);
- }
+ using var builder = new Builder(null, "Everlook.interfaces.EverlookGameLoadingDialog.glade", null);
+ return new EverlookGameLoadingDialog(builder, builder.GetObject("_gameLoadingDialog").Handle, parent);
}
private EverlookGameLoadingDialog(Builder builder, IntPtr handle, Window parent)
@@ -161,18 +159,16 @@ private EverlookGameLoadingDialog(Builder builder, IntPtr handle, Window parent)
using (var shaderStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Everlook.Content.jokes.txt"))
{
- if (shaderStream == null)
+ if (shaderStream is null)
{
return;
}
- using (var sr = new StreamReader(shaderStream))
+ using var sr = new StreamReader(shaderStream);
+ while (sr.BaseStream.Length > sr.BaseStream.Position)
{
- while (sr.BaseStream.Length > sr.BaseStream.Position)
- {
- // Add italics to all jokes. Jokes are in Pango markup format
- _jokes.Add($"{sr.ReadLine()}");
- }
+ // Add italics to all jokes. Jokes are in Pango markup format
+ _jokes.Add($"{sr.ReadLine()}");
}
}
@@ -261,10 +257,10 @@ private void SetStatusMessage(string statusMessage)
$"{_currentLoadingProgress.OperationCount}) {statusMessage}";
}
- ///
- public override void Destroy()
+ ///
+ protected override void Dispose(bool disposing)
{
- base.Destroy();
+ base.Dispose(disposing);
GLib.Timeout.Remove(_jokeTimeoutID);
GLib.Timeout.Remove(_secondaryProgressPulserTimeoutID);
diff --git a/Everlook/UI/EverlookImageExportDialog.cs b/Everlook/UI/EverlookImageExportDialog.cs
index 9b97e0a..9fbf68f 100644
--- a/Everlook/UI/EverlookImageExportDialog.cs
+++ b/Everlook/UI/EverlookImageExportDialog.cs
@@ -64,15 +64,13 @@ public partial class EverlookImageExportDialog : Dialog
/// An initialized instance of the EverlookImageExportDialog class.
public static EverlookImageExportDialog Create(FileReference inExportTarget)
{
- using (var builder = new Builder(null, "Everlook.interfaces.EverlookImageExport.glade", null))
- {
- return new EverlookImageExportDialog
- (
- builder,
- builder.GetObject("EverlookImageExportDialog").Handle,
- inExportTarget
- );
- }
+ using var builder = new Builder(null, "Everlook.interfaces.EverlookImageExport.glade", null);
+ return new EverlookImageExportDialog
+ (
+ builder,
+ builder.GetObject("EverlookImageExportDialog").Handle,
+ inExportTarget
+ );
}
///
@@ -110,7 +108,11 @@ private void LoadInformation()
this.Title = $"Export Image | {imageFilename}";
- var file = _exportTarget.Extract();
+ if (!_exportTarget.TryExtract(out var file))
+ {
+ throw new ArgumentException("The file data could not be extracted.", nameof(_exportTarget));
+ }
+
_image = new BLP(file);
_exportFormatComboBox.Active = (int)_config.DefaultImageExportFormat;
@@ -170,14 +172,12 @@ public void RunExport()
var fullExportPath = $"{exportPath}_{i}.{formatExtension}";
- using (var fs = File.OpenWrite(fullExportPath))
- {
- _image.GetMipMap((uint)i).Save
- (
- fs,
- GetImageEncoderFromFormat((ImageFormat)_exportFormatComboBox.Active)
- );
- }
+ using var fs = File.OpenWrite(fullExportPath);
+ _image.GetMipMap((uint)i).Save
+ (
+ fs,
+ GetImageEncoderFromFormat((ImageFormat)_exportFormatComboBox.Active)
+ );
}
++i;
@@ -234,15 +234,16 @@ private static string GetFileExtensionFromImageFormat(ImageFormat format)
/// Sender.
/// E.
[GLib.ConnectBefore]
- protected void OnMipListingButtonPressed(object sender, ButtonPressEventArgs e)
+ protected void OnMipListingButtonPressed(object? sender, ButtonPressEventArgs e)
{
- if (e.Event.Type == EventType.ButtonPress && e.Event.Button == 3)
+ if (e.Event.Type != EventType.ButtonPress || e.Event.Button != 3)
{
- _exportPopupMenu.ShowAll();
-
- _exportPopupMenu.PopupForDevice(e.Event.Device, null, null, null, null, e.Event.Button, e.Event.Time);
- //this.ExportPopupMenu.Popup();
+ return;
}
+
+ _exportPopupMenu.ShowAll();
+
+ _exportPopupMenu.PopupAtPointer(e.Event);
}
///
@@ -250,7 +251,7 @@ protected void OnMipListingButtonPressed(object sender, ButtonPressEventArgs e)
///
/// Sender.
/// E.
- protected void OnSelectAllItemActivated(object sender, EventArgs e)
+ protected void OnSelectAllItemActivated(object? sender, EventArgs e)
{
_mipLevelListStore.Foreach
(
@@ -267,7 +268,7 @@ protected void OnSelectAllItemActivated(object sender, EventArgs e)
///
/// Sender.
/// E.
- protected void OnSelectNoneItemActivated(object sender, EventArgs e)
+ protected void OnSelectNoneItemActivated(object? sender, EventArgs e)
{
_mipLevelListStore.Foreach
(
@@ -284,7 +285,7 @@ protected void OnSelectNoneItemActivated(object sender, EventArgs e)
///
/// Sender.
/// E.
- protected void OnExportMipToggleClicked(object sender, ToggledArgs e)
+ protected void OnExportMipToggleClicked(object? sender, ToggledArgs e)
{
TreeIter iter;
_mipLevelListStore.GetIterFromString(out iter, e.Path);
@@ -299,7 +300,7 @@ protected void OnExportMipToggleClicked(object sender, ToggledArgs e)
///
/// Sender.
/// E.
- protected void OnOkButtonClicked(object sender, EventArgs e)
+ protected void OnOkButtonClicked(object? sender, EventArgs e)
{
RunExport();
}
diff --git a/Everlook/UI/EverlookPreferences.cs b/Everlook/UI/EverlookPreferences.cs
index 27a723a..9a7123c 100644
--- a/Everlook/UI/EverlookPreferences.cs
+++ b/Everlook/UI/EverlookPreferences.cs
@@ -60,10 +60,8 @@ public sealed partial class EverlookPreferences : Dialog
/// An initialized instance of the EverlookPreferences class.
public static EverlookPreferences Create()
{
- using (var builder = new Builder(null, "Everlook.interfaces.EverlookPreferences.glade", null))
- {
- return new EverlookPreferences(builder, builder.GetObject("_preferencesDialog").Handle);
- }
+ using var builder = new Builder(null, "Everlook.interfaces.EverlookPreferences.glade", null);
+ return new EverlookPreferences(builder, builder.GetObject("_preferencesDialog").Handle);
}
///
@@ -99,7 +97,7 @@ private EverlookPreferences(Builder builder, IntPtr handle)
/// The sending object.
/// The event arguments.
[ConnectBefore]
- private void OnShowUnknownFilesToggled(object sender, EventArgs e)
+ private void OnShowUnknownFilesToggled(object? sender, EventArgs e)
{
// Refilter if the option has changed
if (_showUnknownFilesCheckButton.Active != _config.ShowUnknownFilesWhenFiltering)
@@ -117,7 +115,7 @@ private void OnShowUnknownFilesToggled(object sender, EventArgs e)
/// The sending object.
/// The event arguments.
[ConnectBefore]
- private void OnAllowStatsToggled(object sender, EventArgs e)
+ private void OnAllowStatsToggled(object? sender, EventArgs e)
{
var suboptionSensitivity = _allowStatsCheckButton.Active;
@@ -165,7 +163,7 @@ private void OnKeyPressedGamePathTreeView(object o, KeyPressEventArgs args)
///
/// The sending object.
/// The event arguments.
- private void OnAliasEntryChanged(object sender, EventArgs eventArgs)
+ private void OnAliasEntryChanged(object? sender, EventArgs eventArgs)
{
_newGamePathDialog.SetResponseSensitive(ResponseType.Ok, !string.IsNullOrEmpty(_aliasEntry.Text));
}
@@ -175,7 +173,7 @@ private void OnAliasEntryChanged(object sender, EventArgs eventArgs)
///
/// The sending object.
/// The event arguments.
- private void OnAddPathButtonClicked(object sender, EventArgs eventArgs)
+ private void OnAddPathButtonClicked(object? sender, EventArgs eventArgs)
{
var defaultLocation = new Uri(Environment.GetFolderPath(Environment.SpecialFolder.Desktop));
_pathChooser.SetCurrentFolderUri(defaultLocation.ToString());
@@ -217,7 +215,7 @@ private void OnAddPathButtonClicked(object sender, EventArgs eventArgs)
///
/// Sender.
/// E.
- private void OnRemovePathButtonClicked(object sender, EventArgs e)
+ private void OnRemovePathButtonClicked(object? sender, EventArgs e)
{
TreeIter selectedIter;
_gamePathSelectionTreeView.Selection.GetSelected(out selectedIter);
diff --git a/Everlook/UI/Helpers/CellRenderers.cs b/Everlook/UI/Helpers/CellRenderers.cs
index 4f350bc..657eac6 100644
--- a/Everlook/UI/Helpers/CellRenderers.cs
+++ b/Everlook/UI/Helpers/CellRenderers.cs
@@ -52,7 +52,7 @@ TreeIter iter
)
{
var cellText = cell as CellRendererText;
- if (cellText == null)
+ if (cellText is null)
{
return;
}
@@ -97,7 +97,7 @@ TreeIter iter
var cellText = cell as CellRendererText;
var reference = (FileReference)model.GetValue(iter, 0);
- if (reference == null || cellText == null)
+ if (reference is null || cellText is null)
{
return;
}
@@ -123,7 +123,7 @@ TreeIter iter
var cellIcon = cell as CellRendererPixbuf;
var reference = (FileReference)model.GetValue(iter, 0);
- if (reference == null || cellIcon == null)
+ if (reference is null || cellIcon is null)
{
return;
}
diff --git a/Everlook/UI/MainWindow.cs b/Everlook/UI/MainWindow.cs
index 4dd85a5..8f6c83a 100644
--- a/Everlook/UI/MainWindow.cs
+++ b/Everlook/UI/MainWindow.cs
@@ -22,11 +22,11 @@
using System;
using System.Collections.Generic;
+using System.ComponentModel.Design;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
-using System.Threading.Tasks;
using Everlook.Audio;
using Everlook.Configuration;
using Everlook.Explorer;
@@ -42,14 +42,13 @@
using Gdk;
using GLib;
using Gtk;
-using log4net;
-using OpenTK.Graphics;
-using OpenTK.Input;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Silk.NET.OpenGL;
using Warcraft.Core;
using static Everlook.Utility.DataLoadingDelegates;
-using Application = Gtk.Application;
using EventArgs = System.EventArgs;
using IOPath = System.IO.Path;
using Task = System.Threading.Tasks.Task;
@@ -64,9 +63,9 @@ namespace Everlook.UI
public sealed partial class MainWindow : Gtk.Window
{
///
- /// Logger instance for this class.
+ /// Holds the logging instance for this class.
///
- private static readonly ILog Log = LogManager.GetLogger(typeof(MainWindow));
+ private readonly ILogger _log;
///
/// Static reference to the configuration handler.
@@ -76,12 +75,12 @@ public sealed partial class MainWindow : Gtk.Window
///
/// Background viewport renderer. Handles all rendering in the viewport.
///
- private readonly ViewportRenderer _renderingEngine;
+ private ViewportRenderer? _renderingEngine;
///
- /// Task scheduler for the UI thread. This allows task-based code to have very simple UI callbacks.
+ /// Holds the available services.
///
- private readonly TaskScheduler _uiTaskScheduler;
+ private IServiceProvider? _services;
///
/// Whether or not the program is shutting down. This is used to remove callbacks and events.
@@ -101,13 +100,17 @@ public sealed partial class MainWindow : Gtk.Window
///
/// Creates an instance of the class, loading the glade XML UI as needed.
///
+ /// The application services.
/// An initialized instance of the MainWindow class.
- public static MainWindow Create()
+ public static MainWindow Create(IServiceProvider provider)
{
- using (var builder = new Builder(null, "Everlook.interfaces.Everlook.glade", null))
- {
- return new MainWindow(builder, builder.GetObject("_mainWindow").Handle);
- }
+ using var builder = new Builder(null, "Everlook.interfaces.Everlook.glade", null);
+ return ActivatorUtilities.CreateInstance
+ (
+ provider,
+ builder,
+ builder.GetObject("_mainWindow").Handle
+ );
}
///
@@ -115,29 +118,28 @@ public static MainWindow Create()
///
/// Builder.
/// Handle.
- private MainWindow(Builder builder, IntPtr handle)
+ /// The application services.
+ /// The logging instance.
+ public MainWindow
+ (
+ Builder builder,
+ IntPtr handle,
+ IServiceProvider services,
+ ILogger log
+ )
: base(handle)
{
+ _log = log;
+
builder.Autoconnect(this);
+
this.DeleteEvent += OnDeleteEvent;
this.Shown += OnMainWindowShown;
this.WindowStateEvent += OnWindowStateChanged;
- _uiTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
_fileLoadingCancellationSource = new CancellationTokenSource();
- var graphicsMode = new GraphicsMode
- (
- new ColorFormat(24),
- 24,
- 0,
- 4,
- 0,
- 2,
- false
- );
-
- _viewportWidget = new ViewportArea(graphicsMode, 3, 3, GraphicsContextFlags.Default)
+ _viewportWidget = new ViewportArea(3, 3)
{
AutoRender = true,
CanFocus = true
@@ -149,10 +151,22 @@ private MainWindow(Builder builder, IntPtr handle)
EventMask.EnterNotifyMask |
EventMask.LeaveNotifyMask |
EventMask.KeyPressMask |
- EventMask.KeyReleaseMask;
+ EventMask.KeyReleaseMask |
+ EventMask.PointerMotionMask;
_viewportWidget.Initialized += (sender, args) =>
{
+ var wrappedServices = new ServiceContainer(services);
+ wrappedServices.AddService(typeof(GL), _viewportWidget.GetAPI());
+ wrappedServices.AddService
+ (
+ typeof(RenderCache),
+ new RenderCache(wrappedServices.GetRequiredService())
+ );
+
+ _services = wrappedServices;
+
+ _renderingEngine = ActivatorUtilities.CreateInstance(_services, _viewportWidget);
_renderingEngine.Initialize();
};
@@ -163,6 +177,11 @@ private MainWindow(Builder builder, IntPtr handle)
return;
}
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
if (!_renderingEngine.IsInitialized)
{
return;
@@ -178,7 +197,6 @@ private MainWindow(Builder builder, IntPtr handle)
_viewportWidget.EnterNotifyEvent += OnViewportMouseEnter;
_viewportWidget.LeaveNotifyEvent += OnViewportMouseLeave;
- _renderingEngine = new ViewportRenderer(_viewportWidget);
_viewportAlignment.Add(_viewportWidget);
_viewportAlignment.ShowAll();
@@ -238,6 +256,11 @@ private void BindModelControlEvents()
{
_renderBoundsCheckButton.Toggled += (sender, args) =>
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
switch (_renderingEngine.RenderTarget)
{
case RenderableWorldModel wmo:
@@ -255,6 +278,11 @@ private void BindModelControlEvents()
_renderWireframeCheckButton.Toggled += (sender, args) =>
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
switch (_renderingEngine.RenderTarget)
{
case RenderableWorldModel wmo:
@@ -272,6 +300,11 @@ private void BindModelControlEvents()
_renderDoodadsCheckButton.Toggled += (sender, args) =>
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
switch (_renderingEngine.RenderTarget)
{
case RenderableWorldModel wmo:
@@ -286,6 +319,11 @@ private void BindModelControlEvents()
_modelVariationComboBox.Changed += (sender, args) =>
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
switch (_renderingEngine.RenderTarget)
{
case RenderableWorldModel wmo:
@@ -301,7 +339,7 @@ private void BindModelControlEvents()
_modelVariationComboBox.GetActiveIter(out var activeIter);
var variationObject = _modelVariationListStore.GetValue(activeIter, 1);
- if (variationObject != null)
+ if (!(variationObject is null))
{
var variationID = (int)variationObject;
@@ -320,8 +358,7 @@ private void BindImageControlEvents()
{
_renderAlphaCheckButton.Toggled += (sender, args) =>
{
- var image = _renderingEngine.RenderTarget as RenderableImage;
- if (image == null)
+ if (!(_renderingEngine?.RenderTarget is RenderableImage image))
{
return;
}
@@ -331,8 +368,7 @@ private void BindImageControlEvents()
_renderRedCheckButton.Toggled += (sender, args) =>
{
- var image = _renderingEngine.RenderTarget as RenderableImage;
- if (image == null)
+ if (!(_renderingEngine?.RenderTarget is RenderableImage image))
{
return;
}
@@ -342,8 +378,7 @@ private void BindImageControlEvents()
_renderGreenCheckButton.Toggled += (sender, args) =>
{
- var image = _renderingEngine.RenderTarget as RenderableImage;
- if (image == null)
+ if (!(_renderingEngine?.RenderTarget is RenderableImage image))
{
return;
}
@@ -353,8 +388,7 @@ private void BindImageControlEvents()
_renderBlueCheckButton.Toggled += (sender, args) =>
{
- var image = _renderingEngine.RenderTarget as RenderableImage;
- if (image == null)
+ if (!(_renderingEngine?.RenderTarget is RenderableImage image))
{
return;
}
@@ -369,7 +403,7 @@ private void BindImageControlEvents()
/// The sending object.
/// The event arguments.
[ConnectBefore]
- private void OnRunExportQueueButtonClicked(object sender, EventArgs e)
+ private void OnRunExportQueueButtonClicked(object? sender, EventArgs e)
{
throw new NotImplementedException();
}
@@ -380,7 +414,7 @@ private void OnRunExportQueueButtonClicked(object sender, EventArgs e)
/// The sending object.
/// The event arguments.
[ConnectBefore]
- private void OnClearExportQueueButtonClicked(object sender, EventArgs e)
+ private void OnClearExportQueueButtonClicked(object? sender, EventArgs e)
{
_exportQueueListStore.Clear();
}
@@ -391,7 +425,7 @@ private void OnClearExportQueueButtonClicked(object sender, EventArgs e)
/// The sending object.
/// The event arguments.
[ConnectBefore]
- private void OnCancelCurrentActionClicked(object sender, EventArgs e)
+ private void OnCancelCurrentActionClicked(object? sender, EventArgs e)
{
_fileLoadingCancellationSource.Cancel();
}
@@ -433,6 +467,11 @@ private void OnViewportMouseLeave(object o, LeaveNotifyEventArgs args)
[ConnectBefore]
private void OnViewportMouseEnter(object o, EnterNotifyEventArgs args)
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
if (_renderingEngine.RenderTarget?.Projection == ProjectionType.Orthographic)
{
this.Window.Cursor = new Cursor(CursorType.Hand2);
@@ -444,7 +483,7 @@ private void OnViewportMouseEnter(object o, EnterNotifyEventArgs args)
///
/// The sending object.
/// The event arguments.
- private async void OnFilterChanged(object sender, EventArgs e)
+ private async void OnFilterChanged(object? sender, EventArgs e)
{
await RefilterTrees();
}
@@ -505,10 +544,9 @@ private async Task RefilterTrees()
///
/// The sending object.
/// The event arguments.
- private async void OnMainWindowShown(object sender, EventArgs eventArgs)
+ private async void OnMainWindowShown(object? sender, EventArgs eventArgs)
{
await LoadGames();
- //OnDeleteEvent(sender, null); // DEBUG
}
///
@@ -520,7 +558,7 @@ private async Task LoadGames()
sw.Start();
var loader = new GameLoader();
- var dialog = EverlookGameLoadingDialog.Create(this);
+ using var dialog = EverlookGameLoadingDialog.Create(this);
dialog.ShowAll();
var loadingProgress = default(OverallLoadingProgress);
@@ -535,7 +573,7 @@ private async Task LoadGames()
if (!Directory.Exists(gameTarget.Path))
{
- Log.Warn($"Could not find game folder for {gameTarget.Alias}. Has the directory moved?");
+ _log.LogWarning($"Could not find game folder for {gameTarget.Alias}. Has the directory moved?");
continue;
}
@@ -558,15 +596,15 @@ private async Task LoadGames()
}
catch (OperationCanceledException)
{
- Log.Info("Cancelled game loading operation.");
+ _log.LogInformation("Cancelled game loading operation.");
break;
}
}
- dialog.Destroy();
+ dialog.Hide();
sw.Stop();
- Log.Debug($"Game loading took {sw.Elapsed.TotalMilliseconds}ms ({sw.Elapsed.TotalSeconds}s)");
+ _log.LogDebug($"Game loading took {sw.Elapsed.TotalMilliseconds}ms ({sw.Elapsed.TotalSeconds}s)");
}
private void AddGamePage(string alias, WarcraftVersion version, PackageGroup group, SerializedTree nodeTree)
@@ -620,8 +658,7 @@ private void EnableControlPage(ControlPage pageToEnable)
{
case ControlPage.Image:
{
- var image = _renderingEngine.RenderTarget as RenderableImage;
- if (image == null)
+ if (!(_renderingEngine?.RenderTarget is RenderableImage image))
{
return;
}
@@ -647,44 +684,53 @@ private void EnableControlPage(ControlPage pageToEnable)
_modelVariationComboBox.Sensitive = true;
- if (_renderingEngine.RenderTarget is RenderableWorldModel wmo)
+ if (_renderingEngine is null)
{
- wmo.ShouldRenderBounds = _renderBoundsCheckButton.Active;
- wmo.ShouldRenderWireframe = _renderWireframeCheckButton.Active;
- wmo.ShouldRenderDoodads = _renderDoodadsCheckButton.Active;
-
- var doodadSetNames = wmo.GetDoodadSetNames().ToList();
- _modelVariationListStore.Clear();
- for (var i = 0; i < doodadSetNames.Count; ++i)
- {
- _modelVariationListStore.AppendValues(doodadSetNames[i], i);
- }
-
- _modelVariationComboBox.Active = 0;
- _modelVariationComboBox.Sensitive = _renderDoodadsCheckButton.Active &&
- doodadSetNames.Count > 1;
- _renderDoodadsCheckButton.Sensitive = true;
+ return;
}
- if (_renderingEngine.RenderTarget is RenderableGameModel mdx)
+ switch (_renderingEngine.RenderTarget)
{
- mdx.ShouldRenderBounds = _renderBoundsCheckButton.Active;
- mdx.ShouldRenderWireframe = _renderWireframeCheckButton.Active;
-
- var skinVariations = mdx.GetSkinVariations().ToList();
- _modelVariationListStore.Clear();
- foreach (var variation in skinVariations)
+ case RenderableWorldModel wmo:
{
- var firstTextureName = variation.TextureVariation1.Value;
- if (!string.IsNullOrEmpty(firstTextureName))
+ wmo.ShouldRenderBounds = _renderBoundsCheckButton.Active;
+ wmo.ShouldRenderWireframe = _renderWireframeCheckButton.Active;
+ wmo.ShouldRenderDoodads = _renderDoodadsCheckButton.Active;
+
+ var doodadSetNames = wmo.GetDoodadSetNames().ToList();
+ _modelVariationListStore.Clear();
+ for (var i = 0; i < doodadSetNames.Count; ++i)
{
- _modelVariationListStore.AppendValues(variation.TextureVariation1.Value, variation.ID);
+ _modelVariationListStore.AppendValues(doodadSetNames[i], i);
}
+
+ _modelVariationComboBox.Active = 0;
+ _modelVariationComboBox.Sensitive = _renderDoodadsCheckButton.Active &&
+ doodadSetNames.Count > 1;
+ _renderDoodadsCheckButton.Sensitive = true;
+ break;
}
+ case RenderableGameModel mdx:
+ {
+ mdx.ShouldRenderBounds = _renderBoundsCheckButton.Active;
+ mdx.ShouldRenderWireframe = _renderWireframeCheckButton.Active;
- _modelVariationComboBox.Active = 0;
- _modelVariationComboBox.Sensitive = skinVariations.Count > 1;
- _renderDoodadsCheckButton.Sensitive = false;
+ var skinVariations = mdx.GetSkinVariations().ToList();
+ _modelVariationListStore.Clear();
+ foreach (var variation in skinVariations)
+ {
+ var firstTextureName = variation.TextureVariation1.Value;
+ if (!string.IsNullOrEmpty(firstTextureName))
+ {
+ _modelVariationListStore.AppendValues(variation.TextureVariation1.Value, variation.ID);
+ }
+ }
+
+ _modelVariationComboBox.Active = 0;
+ _modelVariationComboBox.Sensitive = skinVariations.Count > 1;
+ _renderDoodadsCheckButton.Sensitive = false;
+ break;
+ }
}
break;
@@ -769,6 +815,11 @@ private Task ReloadGames()
///
private void ReloadViewportBackground()
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
_viewportWidget.MakeCurrent();
_renderingEngine.SetClearColour(_config.ViewportBackgroundColour);
@@ -796,12 +847,17 @@ private async Task DisplayRenderableFile
CancellationToken ct
)
{
- if (fileReference == null)
+ if (fileReference is null)
{
throw new ArgumentNullException(nameof(fileReference));
}
- Log.Info($"Loading \"{fileReference.FilePath}\".");
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
+ _log.LogInformation($"Loading \"{fileReference.FilePath}\".");
_statusSpinner.Active = true;
@@ -823,11 +879,17 @@ CancellationToken ct
var renderable = await Task.Run
(
- () => createRenderable(item, fileReference),
+ () => createRenderable
+ (
+ _services.GetRequiredService(),
+ _services.GetRequiredService(),
+ item,
+ fileReference
+ ),
ct
);
- if (renderable != null)
+ if (!(renderable is null))
{
ct.ThrowIfCancellationRequested();
@@ -848,7 +910,7 @@ CancellationToken ct
}
catch (OperationCanceledException)
{
- Log.Info($"Cancelled loading of {fileReference.Filename}");
+ _log.LogInformation($"Cancelled loading of {fileReference.Filename}");
}
finally
{
@@ -865,6 +927,11 @@ CancellationToken ct
[ConnectBefore]
private void OnViewportButtonPressed(object o, ButtonPressEventArgs args)
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
if (_renderingEngine.IsMovementDisabled())
{
return;
@@ -903,8 +970,11 @@ private void OnViewportButtonPressed(object o, ButtonPressEventArgs args)
_viewportWidget.GrabFocus();
- _renderingEngine.InitialMouseX = Mouse.GetCursorState().X;
- _renderingEngine.InitialMouseY = Mouse.GetCursorState().Y;
+ _renderingEngine.InitialMouseX = args.Event.X;
+ _renderingEngine.InitialMouseY = args.Event.Y;
+
+ _renderingEngine.CurrentMouseX = args.Event.X;
+ _renderingEngine.CurrentMouseY = args.Event.Y;
_renderingEngine.WantsToMove = true;
}
@@ -917,6 +987,11 @@ private void OnViewportButtonPressed(object o, ButtonPressEventArgs args)
[ConnectBefore]
private void OnViewportButtonReleased(object o, ButtonReleaseEventArgs args)
{
+ if (_renderingEngine is null)
+ {
+ return;
+ }
+
if (args.Event.Type != EventType.ButtonRelease)
{
return;
@@ -978,14 +1053,13 @@ private static Task OnExportItemRequested(GamePage page, FileReference fileRefer
}
case WarcraftFileType.BinaryImage:
{
- using (var exportDialog = EverlookImageExportDialog.Create(fileReference))
+ using var exportDialog = EverlookImageExportDialog.Create(fileReference);
+ if (exportDialog.Run() == (int)ResponseType.Ok)
{
- if (exportDialog.Run() == (int)ResponseType.Ok)
- {
- exportDialog.RunExport();
- }
- exportDialog.Destroy();
+ exportDialog.RunExport();
}
+
+ exportDialog.Hide();
break;
}
}
@@ -1011,7 +1085,7 @@ private Task OnEnqueueItemRequested(GamePage page, FileReference fileReference)
///
/// Sender.
/// E.
- private void OnAboutButtonClicked(object sender, EventArgs e)
+ private void OnAboutButtonClicked(object? sender, EventArgs e)
{
_aboutDialog.Run();
_aboutDialog.Hide();
@@ -1022,30 +1096,28 @@ private void OnAboutButtonClicked(object sender, EventArgs e)
///
/// Sender.
/// E.
- private async void OnPreferencesButtonClicked(object sender, EventArgs e)
+ private async void OnPreferencesButtonClicked(object? sender, EventArgs e)
{
- using (var preferencesDialog = EverlookPreferences.Create())
+ using var preferencesDialog = EverlookPreferences.Create();
+ preferencesDialog.TransientFor = this;
+ if (preferencesDialog.Run() == (int)ResponseType.Ok)
{
- preferencesDialog.TransientFor = this;
- if (preferencesDialog.Run() == (int)ResponseType.Ok)
- {
- preferencesDialog.SavePreferences();
- }
+ preferencesDialog.SavePreferences();
+ }
- preferencesDialog.Destroy();
+ preferencesDialog.Hide();
- // Commit the changes
- ReloadViewportBackground();
+ // Commit the changes
+ ReloadViewportBackground();
- if (preferencesDialog.DidGameListChange)
- {
- await ReloadGames();
- }
+ if (preferencesDialog.DidGameListChange)
+ {
+ await ReloadGames();
+ }
- if (preferencesDialog.ShouldRefilterTree)
- {
- await RefilterTrees();
- }
+ if (preferencesDialog.ShouldRefilterTree)
+ {
+ await RefilterTrees();
}
}
@@ -1083,8 +1155,7 @@ private async Task OnSaveRequested(GamePage page, IEnumerable fil
Directory.CreateDirectory(Directory.GetParent(exportpath).FullName);
}
- var file = await fileReference.ExtractAsync();
- if (file != null)
+ if (fileReference.TryExtract(out var file))
{
try
{
@@ -1093,26 +1164,28 @@ private async Task OnSaveRequested(GamePage page, IEnumerable fil
File.Delete(exportpath);
}
- using
+ await using var fs = new FileStream
(
- var fs = new FileStream(exportpath, FileMode.CreateNew, FileAccess.Write, FileShare.None)
- )
- {
- await fs.WriteAsync(file, 0, file.Length);
- }
+ exportpath,
+ FileMode.CreateNew,
+ FileAccess.Write,
+ FileShare.None
+ );
+
+ await fs.WriteAsync(file, 0, file.Length);
}
catch (UnauthorizedAccessException unex)
{
- Log.Warn($"Failed to save \"{fileReference.Filename}\": {unex}");
+ _log.LogWarning($"Failed to save \"{fileReference.Filename}\": {unex}");
}
catch (IOException iex)
{
- Log.Warn($"Failed to save \"{fileReference.Filename}\": {iex}");
+ _log.LogWarning($"Failed to save \"{fileReference.Filename}\": {iex}");
}
}
else
{
- Log.Warn
+ _log.LogWarning
(
$"Failed to save \"{fileReference.Filename}\": Could not extract any data from the archives."
);
@@ -1249,7 +1322,7 @@ await DisplayRenderableFile
/// Sender.
/// E.
[ConnectBefore]
- private void OnExportQueueButtonPressed(object sender, ButtonPressEventArgs e)
+ private void OnExportQueueButtonPressed(object? sender, ButtonPressEventArgs e)
{
if (e.Event.Type != EventType.ButtonPress || e.Event.Button != 3)
{
@@ -1259,7 +1332,7 @@ private void OnExportQueueButtonPressed(object sender, ButtonPressEventArgs e)
_exportQueueTreeView.GetPathAtPos((int)e.Event.X, (int)e.Event.Y, out var path);
- if (path == null)
+ if (path is null)
{
return;
}
@@ -1278,8 +1351,7 @@ private void OnExportQueueButtonPressed(object sender, ButtonPressEventArgs e)
}
_queueContextMenu.ShowAll();
- _queueContextMenu.PopupForDevice(e.Event.Device, null, null, null, null, e.Event.Button, e.Event.Time);
- //this.QueueContextMenu.Popup();
+ _queueContextMenu.PopupAtPointer(e.Event);
}
///
@@ -1287,7 +1359,7 @@ private void OnExportQueueButtonPressed(object sender, ButtonPressEventArgs e)
///
/// Sender.
/// E.
- private void OnQueueRemoveContextItemActivated(object sender, EventArgs e)
+ private void OnQueueRemoveContextItemActivated(object? sender, EventArgs e)
{
_exportQueueTreeView.Selection.GetSelected(out var selectedIter);
_exportQueueListStore.Remove(ref selectedIter);
@@ -1299,22 +1371,14 @@ private void OnQueueRemoveContextItemActivated(object sender, EventArgs e)
///
/// Sender.
/// The alpha component.
- private void OnDeleteEvent(object sender, DeleteEventArgs a)
+ private void OnDeleteEvent(object? sender, DeleteEventArgs a)
{
_isShuttingDown = true;
_fileLoadingCancellationSource?.Cancel();
-
- _viewportWidget.MakeCurrent();
-
- _renderingEngine.SetRenderTarget(null);
- _renderingEngine.Dispose();
-
- RenderCache.Instance?.Dispose();
-
+ _renderingEngine?.Dispose();
_viewportWidget.Dispose();
- Application.Quit();
a.RetVal = true;
}
}
diff --git a/Everlook/UI/Widgets/ViewportArea.cs b/Everlook/UI/Widgets/ViewportArea.cs
index 3fe4680..1477045 100644
--- a/Everlook/UI/Widgets/ViewportArea.cs
+++ b/Everlook/UI/Widgets/ViewportArea.cs
@@ -22,11 +22,9 @@
using System;
using System.ComponentModel;
-using System.Threading;
using Gdk;
using Gtk;
-using OpenTK;
-using OpenTK.Graphics;
+using Silk.NET.OpenGL;
namespace Everlook.UI.Widgets
{
@@ -34,14 +32,12 @@ namespace Everlook.UI.Widgets
/// The is a GTK widget for which an OpenGL context can be used to draw arbitrary
/// graphics.
///
- [CLSCompliant(false)]
[ToolboxItem(true)]
public class ViewportArea : GLArea
{
- private static int _graphicsContextCount;
- private static bool _isSharedContextInitialized;
+ private readonly bool _isDebugEnabled;
+ private readonly bool _isForwardCompatible;
- private IGraphicsContext? _tkGraphicsContext;
private bool _isInitialized;
///
@@ -55,69 +51,56 @@ public class ViewportArea : GLArea
public double DeltaTime { get; private set; }
///
- /// Gets the context flags used in the creation of this widget.
+ /// Called when this has finished initializing.
///
- public GraphicsContextFlags ContextFlags { get; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ViewportArea()
- : this(GraphicsMode.Default)
- {
- }
-
- ///
- /// Initializes a new instance of the class. The given is
- /// used to hint the area about context creation.
- ///
- ///
- /// The which the widget should be constructed with.
- ///
- public ViewportArea(GraphicsMode graphicsMode)
- : this(graphicsMode, 1, 0, GraphicsContextFlags.Default)
- {
- }
+ public event EventHandler? Initialized;
///
/// Initializes a new instance of the class.
///
- ///
- /// The which the widget should be constructed with.
- ///
- /// The major OpenGL version to attempt to initialize.
- /// The minor OpenGL version to attempt to initialize.
- ///
- /// Any flags which should be used during initialization of the .
- ///
+ /// The major version of OpenGL to request.
+ /// The minor version of OpenGL to request.
+ /// Whether the OpenGL context should be debuggable.
+ /// Whether the OpenGL context should be forward compatible.
+ /// Whether the viewport area should have a depth buffer.
+ /// Whether the viewport area should have a stencil buffer.
+ /// Whether the viewport area should have an alpha channel.
public ViewportArea
(
- GraphicsMode graphicsMode,
int glVersionMajor,
int glVersionMinor,
- GraphicsContextFlags contextFlags
+ bool isDebugEnabled = false,
+ bool isForwardCompatible = false,
+ bool withDepthBuffer = true,
+ bool withStencilBuffer = true,
+ bool withAlpha = true
)
{
- this.ContextFlags = contextFlags;
+ _isDebugEnabled = isDebugEnabled;
+ _isForwardCompatible = isForwardCompatible;
AddTickCallback(UpdateFrameTime);
SetRequiredVersion(glVersionMajor, glVersionMinor);
- if (graphicsMode.Depth > 0)
- {
- this.HasDepthBuffer = true;
- }
+ this.HasDepthBuffer = withDepthBuffer;
+ this.HasStencilBuffer = withStencilBuffer;
+ this.HasAlpha = withAlpha;
+ }
- if (graphicsMode.Stencil > 0)
+ ///
+ /// Gets an instance of the OpenGL API.
+ ///
+ /// The API instance.
+ /// Thrown if the viewport area has not been initialized.
+ public GL GetAPI()
+ {
+ if (_isInitialized)
{
- this.HasStencilBuffer = true;
+ return GL.GetApi();
}
- if (graphicsMode.ColorFormat.Alpha > 0)
- {
- this.HasAlpha = true;
- }
+ throw new InvalidOperationException();
}
///
@@ -152,21 +135,17 @@ protected override GLContext OnCreateContext()
GetRequiredVersion(out var major, out var minor);
gdkGLContext.SetRequiredVersion(major, minor);
-
- gdkGLContext.DebugEnabled = this.ContextFlags.HasFlag(GraphicsContextFlags.Debug);
- gdkGLContext.ForwardCompatible = this.ContextFlags.HasFlag(GraphicsContextFlags.ForwardCompatible);
+ gdkGLContext.DebugEnabled = _isDebugEnabled;
+ gdkGLContext.ForwardCompatible = _isForwardCompatible;
gdkGLContext.Realize();
return gdkGLContext;
}
- ///
- public override void Destroy()
+ ///
+ protected override void OnDestroyed()
{
- GC.SuppressFinalize(this);
Dispose(true);
-
- base.Destroy();
}
///
@@ -180,53 +159,6 @@ protected override void Dispose(bool disposing)
}
MakeCurrent();
- OnShuttingDown();
- if (!GraphicsContext.ShareContexts || (Interlocked.Decrement(ref _graphicsContextCount) != 0))
- {
- return;
- }
-
- OnGraphicsContextShuttingDown();
- _isSharedContextInitialized = false;
- }
-
- ///
- /// Called when the first is created in the case where
- /// GraphicsContext.ShareContexts == true;
- ///
- public static event EventHandler? GraphicsContextInitialized;
-
- ///
- /// Called when the first is being destroyed in the case where
- /// GraphicsContext.ShareContext == true;
- ///
- public static event EventHandler? GraphicsContextShuttingDown;
-
- ///
- /// Called when this has finished initializing and has a valid
- /// .
- ///
- public event EventHandler? Initialized;
-
- ///
- /// Called when this is being disposed.
- ///
- public event EventHandler? ShuttingDown;
-
- ///
- /// Invokes the event.
- ///
- private static void OnGraphicsContextInitialized()
- {
- GraphicsContextInitialized?.Invoke(null, EventArgs.Empty);
- }
-
- ///
- /// Invokes the event.
- ///
- private static void OnGraphicsContextShuttingDown()
- {
- GraphicsContextShuttingDown?.Invoke(null, EventArgs.Empty);
}
///
@@ -237,14 +169,6 @@ protected virtual void OnInitialized()
this.Initialized?.Invoke(this, EventArgs.Empty);
}
- ///
- /// Invokes the event.
- ///
- protected virtual void OnShuttingDown()
- {
- this.ShuttingDown?.Invoke(this, EventArgs.Empty);
- }
-
///
protected override bool OnDrawn(Cairo.Context cr)
{
@@ -258,8 +182,7 @@ protected override bool OnDrawn(Cairo.Context cr)
}
///
- /// Initializes the with its given values and creates a
- /// .
+ /// Initializes the with its given values.
///
private void Initialize()
{
@@ -268,31 +191,6 @@ private void Initialize()
// Make the GDK GL context current
MakeCurrent();
- // Create a dummy context that will grab the GdkGLContext that is current on the thread
- _tkGraphicsContext = new GraphicsContext(ContextHandle.Zero, null);
-
- if (this.ContextFlags.HasFlag(GraphicsContextFlags.Debug))
- {
- _tkGraphicsContext.ErrorChecking = true;
- }
-
- if (GraphicsContext.ShareContexts)
- {
- Interlocked.Increment(ref _graphicsContextCount);
-
- if (!_isSharedContextInitialized)
- {
- _isSharedContextInitialized = true;
- ((IGraphicsContextInternal)_tkGraphicsContext).LoadAll();
- OnGraphicsContextInitialized();
- }
- }
- else
- {
- ((IGraphicsContextInternal)_tkGraphicsContext).LoadAll();
- OnGraphicsContextInitialized();
- }
-
OnInitialized();
}
}
diff --git a/Everlook/Utility/DataLoadingDelegates.cs b/Everlook/Utility/DataLoadingDelegates.cs
index 2fe815f..bca3891 100644
--- a/Everlook/Utility/DataLoadingDelegates.cs
+++ b/Everlook/Utility/DataLoadingDelegates.cs
@@ -21,7 +21,9 @@
//
using Everlook.Explorer;
+using Everlook.Viewport.Rendering;
using Everlook.Viewport.Rendering.Interfaces;
+using Silk.NET.OpenGL;
namespace Everlook.Utility
{
@@ -41,12 +43,20 @@ public static class DataLoadingDelegates
///
/// A delegate which will create an from the specified item.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The item to encapsulate in a renderable version of it.
/// The file reference associated with the object.
///
/// A type which can be encapsulated in another type implementing .
///
/// A renderable object.
- public delegate IRenderable CreateRenderable(T renderableItem, FileReference fileReference);
+ public delegate IRenderable CreateRenderable
+ (
+ GL gl,
+ RenderCache renderCache,
+ T renderableItem,
+ FileReference fileReference
+ );
}
}
diff --git a/Everlook/Utility/DataLoadingRoutines.cs b/Everlook/Utility/DataLoadingRoutines.cs
index 3fdc8c8..635ecad 100644
--- a/Everlook/Utility/DataLoadingRoutines.cs
+++ b/Everlook/Utility/DataLoadingRoutines.cs
@@ -28,6 +28,7 @@
using Everlook.Viewport.Rendering;
using Everlook.Viewport.Rendering.Interfaces;
using log4net;
+using Silk.NET.OpenGL;
using Warcraft.BLP;
using Warcraft.Core;
using Warcraft.Core.Extensions;
@@ -57,15 +58,14 @@ public static class DataLoadingRoutines
/// A WMO object.
public static WMO LoadWorldModel(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
WMO worldModel;
try
{
- var fileData = fileReference.Extract();
+ if (!fileReference.TryExtract(out var fileData))
+ {
+ throw new FileNotFoundException();
+ }
+
worldModel = new WMO(fileData);
var modelPathWithoutExtension = $"{fileReference.FileDirectory.Replace('/', '\\')}\\" +
@@ -77,7 +77,11 @@ public static WMO LoadWorldModel(FileReference fileReference)
try
{
- var modelGroupData = fileReference.Context.Assets.ExtractFile(modelGroupPath);
+ if (!fileReference.Context.Assets.TryExtractFile(modelGroupPath, out var modelGroupData))
+ {
+ throw new FileNotFoundException();
+ }
+
worldModel.AddModelGroup(new ModelGroup(modelGroupData));
}
catch (FileNotFoundException fex)
@@ -107,7 +111,7 @@ public static WMO LoadWorldModel(FileReference fileReference)
/// A WMO object, containing just the specified model group.
public static WMO LoadWorldModelGroup(FileReference fileReference)
{
- if (fileReference == null)
+ if (fileReference is null)
{
throw new ArgumentNullException(nameof(fileReference));
}
@@ -115,14 +119,22 @@ public static WMO LoadWorldModelGroup(FileReference fileReference)
// Get the file name of the root object
var modelRootPath = fileReference.FilePath.Remove(fileReference.FilePath.Length - 8, 4);
- WMO worldModel;
// Extract it and load just this model group
+ WMO worldModel;
try
{
- var rootData = fileReference.Context.Assets.ExtractFile(modelRootPath);
+ if (!fileReference.Context.Assets.TryExtractFile(modelRootPath, out var rootData))
+ {
+ throw new FileNotFoundException();
+ }
+
worldModel = new WMO(rootData);
- var modelGroupData = fileReference.Extract();
+ if (!fileReference.TryExtract(out var modelGroupData))
+ {
+ throw new FileNotFoundException();
+ }
+
worldModel.AddModelGroup(new ModelGroup(modelGroupData));
}
catch (FileNotFoundException fex)
@@ -148,13 +160,21 @@ public static WMO LoadWorldModelGroup(FileReference fileReference)
/// NOTE: This method *must* be called in the UI thread after the OpenGL context has been made current.
/// The constructors commonly make extensive use of OpenGL methods.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The model object.
/// The reference it was constructed from.
/// An encapsulated renderable OpenGL object.
- public static IRenderable CreateRenderableWorldModel(WMO worldModel, FileReference fileReference)
+ public static IRenderable CreateRenderableWorldModel
+ (
+ GL gl,
+ RenderCache renderCache,
+ WMO worldModel,
+ FileReference fileReference
+ )
{
var warcraftContext = fileReference.Context as WarcraftGameContext;
- if (warcraftContext == null)
+ if (warcraftContext is null)
{
// TODO: This is bad practice. Refactor
throw new ArgumentException
@@ -163,7 +183,7 @@ public static IRenderable CreateRenderableWorldModel(WMO worldModel, FileReferen
);
}
- var renderableWorldModel = new RenderableWorldModel(worldModel, warcraftContext);
+ var renderableWorldModel = new RenderableWorldModel(gl, renderCache, worldModel, warcraftContext);
renderableWorldModel.LoadDoodads();
return renderableWorldModel;
@@ -176,15 +196,13 @@ public static IRenderable CreateRenderableWorldModel(WMO worldModel, FileReferen
/// A BLP object containing the image data pointed to by the reference.
public static BLP LoadBinaryImage(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
BLP image;
try
{
- var fileData = fileReference.Extract();
+ if (!fileReference.TryExtract(out var fileData))
+ {
+ throw new FileNotFoundException();
+ }
try
{
@@ -192,9 +210,12 @@ public static BLP LoadBinaryImage(FileReference fileReference)
}
catch (FileLoadException fex)
{
- Log.Warn(
+ Log.Warn
+ (
$"FileLoadException when loading BLP image: {fex.Message}\n" +
- $"Please report this on GitHub or via email.");
+ $"Please report this on GitHub or via email."
+ );
+
throw;
}
}
@@ -213,12 +234,20 @@ public static BLP LoadBinaryImage(FileReference fileReference)
/// NOTE: This method *must* be called in the UI thread after the OpenGL context has been made current.
/// The constructors commonly make extensive use of OpenGL methods.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The image object.
/// The reference it was constructed from.
/// An encapsulated renderable OpenGL object.
- public static IRenderable CreateRenderableBinaryImage(BLP binaryImage, FileReference fileReference)
+ public static IRenderable CreateRenderableBinaryImage
+ (
+ GL gl,
+ RenderCache renderCache,
+ BLP binaryImage,
+ FileReference fileReference
+ )
{
- var renderableImage = new RenderableBLP(binaryImage, fileReference.FilePath);
+ var renderableImage = new RenderableBLP(gl, renderCache, binaryImage, fileReference.FilePath);
return renderableImage;
}
@@ -230,7 +259,7 @@ public static IRenderable CreateRenderableBinaryImage(BLP binaryImage, FileRefer
/// A bitmap containing the image data pointed to by the reference.
public static Bitmap LoadBitmapImage(FileReference fileReference)
{
- if (fileReference == null)
+ if (fileReference is null)
{
throw new ArgumentNullException(nameof(fileReference));
}
@@ -238,16 +267,21 @@ public static Bitmap LoadBitmapImage(FileReference fileReference)
Bitmap image;
try
{
- var fileData = fileReference.Extract();
- using (var ms = new MemoryStream(fileData))
+ if (!fileReference.TryExtract(out var fileData))
{
- image = new Bitmap(ms);
+ throw new FileNotFoundException();
}
+
+ using var ms = new MemoryStream(fileData);
+ image = new Bitmap(ms);
}
catch (FileNotFoundException fex)
{
- Log.Warn(
- $"Failed to load the image \"{fileReference.FilePath}\": {fex}");
+ Log.Warn
+ (
+ $"Failed to load the image \"{fileReference.FilePath}\": {fex}"
+ );
+
throw;
}
@@ -260,12 +294,20 @@ public static Bitmap LoadBitmapImage(FileReference fileReference)
/// NOTE: This method *must* be called in the UI thread after the OpenGL context has been made current.
/// The constructors commonly make extensive use of OpenGL methods.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The image object.
/// The reference it was constructed from.
/// An encapsulated renderable OpenGL object.
- public static IRenderable CreateRenderableBitmapImage(Bitmap bitmapImage, FileReference fileReference)
+ public static IRenderable CreateRenderableBitmapImage
+ (
+ GL gl,
+ RenderCache renderCache,
+ Bitmap bitmapImage,
+ FileReference fileReference
+ )
{
- var renderableImage = new RenderableBitmap(bitmapImage, fileReference.FilePath);
+ var renderableImage = new RenderableBitmap(gl, renderCache, bitmapImage, fileReference.FilePath);
return renderableImage;
}
@@ -277,15 +319,14 @@ public static IRenderable CreateRenderableBitmapImage(Bitmap bitmapImage, FileRe
/// An object containing the model data pointed to by the reference.
public static MDX LoadGameModel(FileReference fileReference)
{
- if (fileReference == null)
- {
- throw new ArgumentNullException(nameof(fileReference));
- }
-
MDX model;
try
{
- var fileData = fileReference.Extract();
+ if (!fileReference.TryExtract(out var fileData))
+ {
+ throw new FileNotFoundException();
+ }
+
model = new MDX(fileData);
if (model.Version >= WarcraftVersion.Wrath)
@@ -298,21 +339,21 @@ public static MDX LoadGameModel(FileReference fileReference)
for (var i = 0; i < model.SkinCount; ++i)
{
var modelSkinPath = $"{modelDirectory}\\{modelFilename}{i:D2}.skin";
- var skinData = fileReference.Context.Assets.ExtractFile(modelSkinPath);
+ if (!fileReference.Context.Assets.TryExtractFile(modelSkinPath, out var skinData))
+ {
+ continue;
+ }
- using (var ms = new MemoryStream(skinData))
+ using var ms = new MemoryStream(skinData);
+ using var br = new BinaryReader(ms);
+
+ var skinIdentifier = new string(br.ReadChars(4));
+ if (skinIdentifier != "SKIN")
{
- using (var br = new BinaryReader(ms))
- {
- var skinIdentifier = new string(br.ReadChars(4));
- if (skinIdentifier != "SKIN")
- {
- break;
- }
-
- skins.Add(br.ReadMDXSkin(model.Version));
- }
+ break;
}
+
+ skins.Add(br.ReadMDXSkin(model.Version));
}
model.SetSkins(skins);
@@ -342,13 +383,21 @@ public static MDX LoadGameModel(FileReference fileReference)
/// NOTE: This method *must* be called in the UI thread after the OpenGL context has been made current.
/// The constructors commonly make extensive use of OpenGL methods.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The model object.
/// The reference it was constructed from.
/// An encapsulated renderable OpenGL object.
- public static IRenderable CreateRenderableGameModel(MDX gameModel, FileReference fileReference)
+ public static IRenderable CreateRenderableGameModel
+ (
+ GL gl,
+ RenderCache renderCache,
+ MDX gameModel,
+ FileReference fileReference
+ )
{
var warcraftContext = fileReference.Context as WarcraftGameContext;
- if (warcraftContext == null)
+ if (warcraftContext is null)
{
// TODO: This is bad practice. Refactor
throw new ArgumentException
@@ -357,7 +406,14 @@ public static IRenderable CreateRenderableGameModel(MDX gameModel, FileReference
);
}
- var renderableModel = new RenderableGameModel(gameModel, warcraftContext, fileReference.FilePath);
+ var renderableModel = new RenderableGameModel
+ (
+ gl,
+ renderCache,
+ gameModel,
+ warcraftContext,
+ fileReference.FilePath
+ );
return renderableModel;
}
diff --git a/Everlook/Utility/DirectoryHelpers.cs b/Everlook/Utility/DirectoryHelpers.cs
index 93b4c87..faac1fe 100644
--- a/Everlook/Utility/DirectoryHelpers.cs
+++ b/Everlook/Utility/DirectoryHelpers.cs
@@ -39,7 +39,13 @@ public static string GetLocalDir()
{
var codeBaseURI = new UriBuilder(Assembly.GetExecutingAssembly().Location).Uri;
- return Path.GetDirectoryName(Uri.UnescapeDataString(codeBaseURI.AbsolutePath));
+ var directory = Path.GetDirectoryName(Uri.UnescapeDataString(codeBaseURI.AbsolutePath));
+ if (directory is null)
+ {
+ throw new InvalidOperationException();
+ }
+
+ return directory;
}
}
}
diff --git a/Everlook/Utility/ExtensionMethods.cs b/Everlook/Utility/ExtensionMethods.cs
index 277d5fc..b58e5bc 100644
--- a/Everlook/Utility/ExtensionMethods.cs
+++ b/Everlook/Utility/ExtensionMethods.cs
@@ -22,9 +22,9 @@
using System;
using System.Collections.Generic;
+using System.Numerics;
using Everlook.Explorer;
using Gdk;
-using OpenTK;
using Warcraft.Core.Structures;
namespace Everlook.Utility
@@ -40,11 +40,6 @@ public static class ExtensionMethods
/// The notebook to clear the pages from.
public static void ClearPages(this Gtk.Notebook notebook)
{
- if (notebook == null)
- {
- throw new ArgumentNullException(nameof(notebook));
- }
-
while (notebook.NPages > 0)
{
notebook.RemovePage(-1);
@@ -53,7 +48,7 @@ public static void ClearPages(this Gtk.Notebook notebook)
///
/// Converts any non-native path separators to the current native path separator,
- /// e.g backslashes to forwardslashes on *nix, and vice versa.
+ /// e.g backslashes to forward slashes on *nix, and vice versa.
///
/// The path.
/// Input path.
@@ -89,7 +84,7 @@ public static bool IsRunningOnUnix()
/// A pixel buffer containg the icon.
public static Pixbuf GetIcon(this FileReference fileReference)
{
- if (fileReference == null)
+ if (fileReference is null)
{
throw new ArgumentNullException(nameof(fileReference));
}
@@ -97,46 +92,6 @@ public static Pixbuf GetIcon(this FileReference fileReference)
return IconManager.GetIconForFiletype(fileReference.FilePath);
}
- ///
- /// Converts the current OpenGL vector to a Warcraft vector structure.
- ///
- /// An -type vector.
- /// A System.Numerics vector.
- public static System.Numerics.Vector3 ToSystemVector(this Vector3 vector3)
- {
- return new System.Numerics.Vector3(vector3.X, vector3.Y, vector3.Z);
- }
-
- ///
- /// Converts the current Warcraft vector to an OpenGL vector structure.
- ///
- /// A -type vector.
- /// An OpenTK vector.
- public static Vector3 ToOpenGLVector(this System.Numerics.Vector3 vector3)
- {
- return new Vector3(vector3.X, vector3.Y, vector3.Z);
- }
-
- ///
- /// Converts the current Warcraft vector to an OpenGL vector structure.
- ///
- /// A -type vector.
- /// An OpenTK vector.
- public static Vector2 ToOpenGLVector(this System.Numerics.Vector2 vector2)
- {
- return new Vector2(vector2.X, vector2.Y);
- }
-
- ///
- /// Converts the current Warcraft quaternion to an OpenGL quaternion structure.
- ///
- /// A -type vector.
- /// An OpenTK vector.
- public static Quaternion ToOpenGLQuaternion(this System.Numerics.Quaternion quaternion)
- {
- return new Quaternion(quaternion.X, quaternion.Y, quaternion.Z, quaternion.W);
- }
-
///
/// Gets the coordinates of all corners in the box.
///
@@ -150,15 +105,15 @@ public static IEnumerable GetCorners(this Box box)
var xDiff = top.X - bottom.X;
var yDiff = top.Y - bottom.Y;
- yield return top.ToOpenGLVector();
- yield return top.ToOpenGLVector() - new Vector3(xDiff, 0, 0);
- yield return top.ToOpenGLVector() - new Vector3(xDiff, yDiff, 0);
- yield return top.ToOpenGLVector() - new Vector3(0, yDiff, 0);
+ yield return top;
+ yield return top - new Vector3(xDiff, 0, 0);
+ yield return top - new Vector3(xDiff, yDiff, 0);
+ yield return top - new Vector3(0, yDiff, 0);
- yield return bottom.ToOpenGLVector();
- yield return bottom.ToOpenGLVector() + new Vector3(xDiff, 0, 0);
- yield return bottom.ToOpenGLVector() + new Vector3(xDiff, yDiff, 0);
- yield return bottom.ToOpenGLVector() + new Vector3(0, yDiff, 0);
+ yield return bottom;
+ yield return bottom + new Vector3(xDiff, 0, 0);
+ yield return bottom + new Vector3(xDiff, yDiff, 0);
+ yield return bottom + new Vector3(0, yDiff, 0);
}
}
}
diff --git a/Everlook/Utility/IconManager.cs b/Everlook/Utility/IconManager.cs
index ff665ed..58f4ca4 100644
--- a/Everlook/Utility/IconManager.cs
+++ b/Everlook/Utility/IconManager.cs
@@ -43,8 +43,53 @@ public static class IconManager
///
private static readonly ILog Log = LogManager.GetLogger(typeof(IconManager));
- private static readonly Dictionary<(string iconName, int iconSize), Pixbuf> IconCache =
- new Dictionary<(string iconName, int iconSize), Pixbuf>();
+ private static readonly Dictionary<(string IconName, int IconSize), Pixbuf> IconCache =
+ new Dictionary<(string IconName, int IconSize), Pixbuf>();
+
+ private static readonly Dictionary KnownIconTypes = new Dictionary
+ {
+ { WarcraftFileType.Directory, Stock.Directory },
+ { WarcraftFileType.MoPaQArchive, "package-x-generic" },
+ { WarcraftFileType.TerrainTable, "x-office-spreadsheet" },
+ { WarcraftFileType.DatabaseContainer, "x-office-spreadsheet" },
+ { WarcraftFileType.Hashmap, "x-office-spreadsheet" },
+ { WarcraftFileType.TerrainWater, "Blender-Wave-Icon" },
+ { WarcraftFileType.TerrainLiquid, "Blender-Wave-Icon" },
+ { WarcraftFileType.TerrainLevel, "text-x-generic-template" },
+ { WarcraftFileType.TerrainData, "Blender-Planet-Icon" },
+ { WarcraftFileType.GameObjectModel, "Blender-Armature-Icon" },
+ { WarcraftFileType.WorldObjectModel, "Blender-Object-Icon" },
+ { WarcraftFileType.WorldObjectModelGroup, "Blender-Object-Icon" },
+ { WarcraftFileType.WaveAudio, "audio-x-generic" },
+ { WarcraftFileType.MP3Audio, "audio-x-generic" },
+ { WarcraftFileType.VorbisAudio, "audio-x-generic" },
+ { WarcraftFileType.WMAAudio, "audio-x-generic" },
+ { WarcraftFileType.Subtitles, "gnome-subtitles" },
+ { WarcraftFileType.Text, "text-x-generic" },
+ { WarcraftFileType.AddonManifest, "text-x-generic" },
+ { WarcraftFileType.AddonManifestSignature, "text-x-generic" },
+ { WarcraftFileType.GIFImage, "image-gif" },
+ { WarcraftFileType.PNGImage, "image-png" },
+ { WarcraftFileType.JPGImage, "image-jpeg" },
+ { WarcraftFileType.IconImage, "image-x-ico" },
+ { WarcraftFileType.BitmapImage, "image-bmp" },
+ { WarcraftFileType.BinaryImage, "image-x-generic" },
+ { WarcraftFileType.TargaImage, "image-x-generic" },
+ { WarcraftFileType.PDF, "application-pdf" },
+ { WarcraftFileType.Web, "text-html" },
+ { WarcraftFileType.Assembly, "application-x-executable" },
+ { WarcraftFileType.Font, "font-x-generic" },
+ { WarcraftFileType.Animation, "Blender-JumpingToon-Icon" },
+ { WarcraftFileType.Physics, "Blender-Deform-Icon" },
+ { WarcraftFileType.Skeleton, "Blender-Skeleton-Icon" },
+ { WarcraftFileType.DataCache, "text-x-sql" },
+ { WarcraftFileType.INI, "utilities-terminal" },
+ { WarcraftFileType.ConfigurationFile, "utilities-terminal" },
+ { WarcraftFileType.Script, "utilities-terminal" },
+ { WarcraftFileType.Lighting, "Blender-Sun-Icon" },
+ { WarcraftFileType.Shader, "Blender-Shader-Icon" },
+ { WarcraftFileType.XML, "text-xml" }
+ };
///
/// Loads all embedded builtin icons into the application's icon theme.
@@ -80,7 +125,7 @@ public static void LoadEmbeddedIcons()
var iconName = manifestNameParts.ElementAt(manifestNameParts.Length - 2);
var iconBuffer = LoadEmbeddedImage(manifestIconName);
- if (iconBuffer != null)
+ if (!(iconBuffer is null))
{
IconTheme.AddBuiltinIcon(iconName, 16, iconBuffer);
}
@@ -96,27 +141,23 @@ public static void LoadEmbeddedIcons()
/// A pixel buffer containing the image.
private static Pixbuf? LoadEmbeddedImage(string resourceName, int width = 16, int height = 16)
{
- using (var vectorStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
+ using var vectorStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
+ if (vectorStream is null)
{
- if (vectorStream == null)
- {
- return null;
- }
+ return null;
+ }
- using (var ms = new MemoryStream())
- {
- vectorStream.CopyTo(ms);
+ using var ms = new MemoryStream();
+ vectorStream.CopyTo(ms);
- try
- {
- return new Pixbuf(ms.ToArray(), width, height);
- }
- catch (GException gex)
- {
- Log.Error($"Failed to load resource \"{resourceName}\" due to a GException: {gex}");
- return null;
- }
- }
+ try
+ {
+ return new Pixbuf(ms.ToArray(), width, height);
+ }
+ catch (GException gex)
+ {
+ Log.Error($"Failed to load resource \"{resourceName}\" due to a GException: {gex}");
+ return null;
}
}
@@ -134,8 +175,12 @@ public static Pixbuf GetIcon(string iconName)
}
catch (GException gex)
{
- Log.Warn($"Loading of icon \"{iconName}\" failed. Exception message: {gex.Message}\n" +
- $"A fallback icon will be used instead.");
+ Log.Warn
+ (
+ $"Loading of icon \"{iconName}\" failed. Exception message: {gex.Message}\n" +
+ $"A fallback icon will be used instead."
+ );
+
return LoadIconPixbuf("empty");
}
}
@@ -159,142 +204,12 @@ public static Pixbuf GetIconForFiletype(string file)
/// The file type.
public static Pixbuf GetIconForFiletype(WarcraftFileType fileType)
{
- switch (fileType)
+ if (KnownIconTypes.TryGetValue(fileType, out var result))
{
- case WarcraftFileType.Directory:
- {
- return GetIcon(Stock.Directory);
- }
- case WarcraftFileType.MoPaQArchive:
- {
- return GetIcon("package-x-generic");
- }
- case WarcraftFileType.TerrainTable:
- case WarcraftFileType.DatabaseContainer:
- case WarcraftFileType.Hashmap:
- {
- return GetIcon("x-office-spreadsheet");
- }
- case WarcraftFileType.TerrainWater:
- case WarcraftFileType.TerrainLiquid:
- {
- return GetIcon("Blender-Wave-Icon");
- }
- case WarcraftFileType.TerrainLevel:
- {
- return GetIcon("text-x-generic-template");
- }
- case WarcraftFileType.TerrainData:
- {
- return GetIcon("Blender-Planet-Icon");
- }
- case WarcraftFileType.GameObjectModel:
- {
- return GetIcon("Blender-Armature-Icon");
- }
- case WarcraftFileType.WorldObjectModel:
- case WarcraftFileType.WorldObjectModelGroup:
- {
- return GetIcon("Blender-Object-Icon");
- }
- case WarcraftFileType.WaveAudio:
- case WarcraftFileType.MP3Audio:
- case WarcraftFileType.VorbisAudio:
- case WarcraftFileType.WMAAudio:
- {
- return GetIcon("audio-x-generic");
- }
- case WarcraftFileType.Subtitles:
- {
- return GetIcon("gnome-subtitles");
- }
- case WarcraftFileType.Text:
- case WarcraftFileType.AddonManifest:
- case WarcraftFileType.AddonManifestSignature:
- {
- return GetIcon("text-x-generic");
- }
- case WarcraftFileType.GIFImage:
- {
- return GetIcon("image-gif");
- }
- case WarcraftFileType.PNGImage:
- {
- return GetIcon("image-png");
- }
- case WarcraftFileType.JPGImage:
- {
- return GetIcon("image-jpeg");
- }
- case WarcraftFileType.IconImage:
- {
- return GetIcon("image-x-ico");
- }
- case WarcraftFileType.BitmapImage:
- {
- return GetIcon("image-bmp");
- }
- case WarcraftFileType.BinaryImage:
- case WarcraftFileType.TargaImage:
- {
- return GetIcon("image-x-generic");
- }
- case WarcraftFileType.PDF:
- {
- return GetIcon("application-pdf");
- }
- case WarcraftFileType.Web:
- {
- return GetIcon("text-html");
- }
- case WarcraftFileType.Assembly:
- {
- return GetIcon("application-x-executable");
- }
- case WarcraftFileType.Font:
- {
- return GetIcon("font-x-generic");
- }
- case WarcraftFileType.Animation:
- {
- return GetIcon("Blender-JumpingToon-Icon");
- }
- case WarcraftFileType.Physics:
- {
- return GetIcon("Blender-Deform-Icon");
- }
- case WarcraftFileType.Skeleton:
- {
- return GetIcon("Blender-Skeleton-Icon");
- }
- case WarcraftFileType.DataCache:
- {
- return GetIcon("text-x-sql");
- }
- case WarcraftFileType.INI:
- case WarcraftFileType.ConfigurationFile:
- case WarcraftFileType.Script:
- {
- return GetIcon("utilities-terminal");
- }
- case WarcraftFileType.Lighting:
- {
- return GetIcon("Blender-Sun-Icon");
- }
- case WarcraftFileType.Shader:
- {
- return GetIcon("Blender-Shader-Icon");
- }
- case WarcraftFileType.XML:
- {
- return GetIcon("text-xml");
- }
- case WarcraftFileType.Unknown:
- default:
- {
- return GetIcon(Stock.File);
- }
+ return GetIcon(result);
}
+
+ return GetIcon(Stock.File);
}
///
diff --git a/Everlook/Utility/MathHelper.cs b/Everlook/Utility/MathHelper.cs
new file mode 100644
index 0000000..eecfffa
--- /dev/null
+++ b/Everlook/Utility/MathHelper.cs
@@ -0,0 +1,52 @@
+//
+// MathHelper.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2017 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using System;
+
+namespace Everlook.Utility
+{
+ ///
+ /// Various mathematical helper functions.
+ ///
+ public static class MathHelper
+ {
+ ///
+ /// Converts degrees to radians.
+ ///
+ /// The value in degrees.
+ /// The value in radians.
+ public static double DegreesToRadians(double degrees)
+ {
+ return degrees * (Math.PI / 180.0);
+ }
+
+ ///
+ /// Converts radians to degrees.
+ ///
+ /// The value in radians.
+ /// The value in degrees.
+ public static double RadiansToDegrees(double radians)
+ {
+ return radians / (Math.PI / 180.0);
+ }
+ }
+}
diff --git a/Everlook/Utility/ResourceManager.cs b/Everlook/Utility/ResourceManager.cs
index 7026572..c954427 100644
--- a/Everlook/Utility/ResourceManager.cs
+++ b/Everlook/Utility/ResourceManager.cs
@@ -41,15 +41,13 @@ public static class ResourceManager
string resourceString;
using (var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcePath))
{
- if (resourceStream == null)
+ if (resourceStream is null)
{
return null;
}
- using (var sr = new StreamReader(resourceStream))
- {
- resourceString = sr.ReadToEnd();
- }
+ using var sr = new StreamReader(resourceStream);
+ resourceString = sr.ReadToEnd();
}
return resourceString;
@@ -65,15 +63,13 @@ public static class ResourceManager
var executingAssembly = Assembly.GetExecutingAssembly();
const string fallbackTextureName = "Everlook.Content.Textures.FallbackTexture.png";
- using (var imageStream = executingAssembly.GetManifestResourceStream(fallbackTextureName))
+ using var imageStream = executingAssembly.GetManifestResourceStream(fallbackTextureName);
+ if (imageStream is null)
{
- if (imageStream == null)
- {
- return null;
- }
-
- return new Bitmap(imageStream);
+ return null;
}
+
+ return new Bitmap(imageStream);
}
}
}
diff --git a/Everlook/Utility/StringReferenceListComparer.cs b/Everlook/Utility/StringReferenceListComparer.cs
index 74d8283..643a9e2 100644
--- a/Everlook/Utility/StringReferenceListComparer.cs
+++ b/Everlook/Utility/StringReferenceListComparer.cs
@@ -34,16 +34,6 @@ public class StringReferenceListComparer : IEqualityComparer
public bool Equals(IReadOnlyList x, IReadOnlyList y)
{
- if (x == null && y == null)
- {
- return true;
- }
-
- if (x == null || y == null)
- {
- return false;
- }
-
if (x.Count != y.Count)
{
return false;
@@ -80,7 +70,7 @@ public int GetHashCode(IReadOnlyList obj)
foreach (var reference in obj)
{
- hash *= 23 + reference.Value.GetHashCode();
+ hash *= 23 + (reference.Value?.GetHashCode()).GetValueOrDefault();
hash *= 23 + reference.Offset.GetHashCode();
}
diff --git a/Everlook/Utility/WarcraftGameContext.cs b/Everlook/Utility/WarcraftGameContext.cs
index d2ec31d..c036631 100644
--- a/Everlook/Utility/WarcraftGameContext.cs
+++ b/Everlook/Utility/WarcraftGameContext.cs
@@ -56,16 +56,6 @@ public sealed class WarcraftGameContext : IGameContext
/// Thrown if the assets or the file tree are null.
public WarcraftGameContext(WarcraftVersion version, PackageGroup assets, FileTreeModel fileTree)
{
- if (assets == null)
- {
- throw new ArgumentNullException(nameof(assets));
- }
-
- if (fileTree == null)
- {
- throw new ArgumentNullException(nameof(fileTree));
- }
-
this.Version = version;
this.Assets = assets;
this.FileTree = fileTree;
@@ -81,14 +71,14 @@ public WarcraftGameContext(WarcraftVersion version, PackageGroup assets, FileTre
public FileReference GetReferenceForDoodad(DoodadInstance doodadInstance)
{
var doodadReference = GetReferenceForPath(doodadInstance.Name);
- if (doodadReference != null)
+ if (!(doodadReference is null))
{
return doodadReference;
}
// Doodads may have the *.mdx extension instead of *.m2. Try with that as well.
doodadReference = GetReferenceForPath(Path.ChangeExtension(doodadInstance.Name, "m2"));
- if (doodadReference == null)
+ if (doodadReference is null)
{
throw new ArgumentException
(
@@ -101,15 +91,15 @@ public FileReference GetReferenceForDoodad(DoodadInstance doodadInstance)
}
///
- public FileReference? GetReferenceForPath(string path)
+ public FileReference? GetReferenceForPath(string? path)
{
if (string.IsNullOrEmpty(path))
{
- throw new ArgumentNullException(nameof(path));
+ return null;
}
var treePath = this.FileTree.GetPath(path);
- if (treePath == null)
+ if (treePath is null)
{
return null;
}
diff --git a/Everlook/Viewport/Camera/CameraMovement.cs b/Everlook/Viewport/Camera/CameraMovement.cs
index 358c22f..6672006 100644
--- a/Everlook/Viewport/Camera/CameraMovement.cs
+++ b/Everlook/Viewport/Camera/CameraMovement.cs
@@ -21,9 +21,9 @@
//
using System;
+using System.Numerics;
using Everlook.Configuration;
-using OpenTK;
-using OpenTK.Input;
+using Everlook.Utility;
namespace Everlook.Viewport.Camera
{
@@ -55,8 +55,8 @@ public Vector3 Orientation
{
return new Vector3
(
- MathHelper.RadiansToDegrees(_camera.VerticalViewAngle),
- MathHelper.RadiansToDegrees(_camera.HorizontalViewAngle),
+ (float)MathHelper.RadiansToDegrees(_camera.VerticalViewAngle),
+ (float)MathHelper.RadiansToDegrees(_camera.HorizontalViewAngle),
0
);
}
@@ -87,6 +87,41 @@ public bool ConstrainVerticalView
set;
}
+ ///
+ /// Gets or sets a value indicating whether the user wants to move left.
+ ///
+ public bool WantsToMoveLeft { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move right.
+ ///
+ public bool WantsToMoveRight { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move forward.
+ ///
+ public bool WantsToMoveForward { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move backward.
+ ///
+ public bool WantsToMoveBackward { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move up.
+ ///
+ public bool WantsToMoveUp { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move down.
+ ///
+ public bool WantsToMoveDown { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the user wants to move faster.
+ ///
+ public bool WantsToSprint { get; set; }
+
///
/// Initializes a new instance of the class, bound to the input camera.
///
@@ -104,7 +139,7 @@ public CameraMovement(ViewportCamera inCamera)
/// The motion delta along the X axis of the mouse in the last frame.
/// The motion delta along the Y axis of the mouse in the last frame.
/// The time delta between this frame and the previous one.
- public void Calculate2DMovement(float deltaMouseX, float deltaMouseY, float deltaTime)
+ public void Calculate2DMovement(double deltaMouseX, double deltaMouseY, float deltaTime)
{
const float speedMultiplier = 6.0f;
if (deltaMouseX < 0)
@@ -133,7 +168,7 @@ public void Calculate2DMovement(float deltaMouseX, float deltaMouseY, float delt
/// The motion delta along the X axis of the mouse in the last frame.
/// The motion delta along the Y axis of the mouse in the last frame.
/// The time delta between this frame and the previous one.
- public void Calculate3DMovement(float deltaMouseX, float deltaMouseY, float deltaTime)
+ public void Calculate3DMovement(double deltaMouseX, double deltaMouseY, float deltaTime)
{
// Perform radial movement
RotateHorizontal
@@ -151,17 +186,17 @@ public void Calculate3DMovement(float deltaMouseX, float deltaMouseY, float delt
{
if (_camera.VerticalViewAngle > MathHelper.DegreesToRadians(90.0f))
{
- _camera.VerticalViewAngle = MathHelper.DegreesToRadians(90.0f);
+ _camera.VerticalViewAngle = MathHelper.DegreesToRadians(90.0);
}
- else if (_camera.VerticalViewAngle < MathHelper.DegreesToRadians(-90.0f))
+ else if (_camera.VerticalViewAngle < MathHelper.DegreesToRadians(-90.0))
{
- _camera.VerticalViewAngle = MathHelper.DegreesToRadians(-90.0f);
+ _camera.VerticalViewAngle = MathHelper.DegreesToRadians(-90.0);
}
}
var speedMultiplier = (float)(DefaultMovementSpeed * EverlookConfiguration.Instance.CameraSpeed);
- if (Keyboard.GetState().IsKeyDown(Key.ShiftLeft))
+ if (this.WantsToSprint)
{
speedMultiplier *= (float)EverlookConfiguration.Instance.SprintMultiplier;
}
@@ -169,32 +204,32 @@ public void Calculate3DMovement(float deltaMouseX, float deltaMouseY, float delt
var moveDistance = deltaTime * speedMultiplier;
// Perform axial movement
- if (Keyboard.GetState().IsKeyDown(Key.W))
+ if (this.WantsToMoveForward)
{
MoveForward(moveDistance);
}
- if (Keyboard.GetState().IsKeyDown(Key.S))
+ if (this.WantsToMoveBackward)
{
MoveBackward(moveDistance);
}
- if (Keyboard.GetState().IsKeyDown(Key.A))
+ if (this.WantsToMoveLeft)
{
MoveLeft(moveDistance);
}
- if (Keyboard.GetState().IsKeyDown(Key.D))
+ if (this.WantsToMoveRight)
{
MoveRight(moveDistance);
}
- if (Keyboard.GetState().IsKeyDown(Key.Q))
+ if (this.WantsToMoveUp)
{
MoveUp(moveDistance);
}
- if (Keyboard.GetState().IsKeyDown(Key.E))
+ if (this.WantsToMoveDown)
{
MoveDown(moveDistance);
}
@@ -204,7 +239,7 @@ public void Calculate3DMovement(float deltaMouseX, float deltaMouseY, float delt
/// Rotates the camera on the horizontal axis by the provided amount of degrees.
///
/// The number of degrees to rotate.
- public void RotateHorizontal(float degrees)
+ public void RotateHorizontal(double degrees)
{
_camera.HorizontalViewAngle += degrees;
}
@@ -213,7 +248,7 @@ public void RotateHorizontal(float degrees)
/// Rotates the camera on the vertical axis by the provided amount of degrees.
///
/// The number of degrees to rotate.
- public void RotateVertical(float degrees)
+ public void RotateVertical(double degrees)
{
_camera.VerticalViewAngle += degrees;
}
@@ -222,54 +257,54 @@ public void RotateVertical(float degrees)
/// Moves the camera up along its local Y axis by units.
///
/// The distance to move.
- public void MoveUp(float distance)
+ public void MoveUp(double distance)
{
- _camera.Position += _camera.UpVector * Math.Abs(distance);
+ _camera.Position += _camera.UpVector * (float)Math.Abs(distance);
}
///
/// Moves the camera down along its local Y axis by units.
///
/// The distance to move.
- public void MoveDown(float distance)
+ public void MoveDown(double distance)
{
- _camera.Position -= _camera.UpVector * Math.Abs(distance);
+ _camera.Position -= _camera.UpVector * (float)Math.Abs(distance);
}
///
/// Moves the camera forward along its local Z axis by units.
///
/// The distance to move.
- public void MoveForward(float distance)
+ public void MoveForward(double distance)
{
- _camera.Position += _camera.LookDirectionVector * Math.Abs(distance);
+ _camera.Position += _camera.LookDirectionVector * (float)Math.Abs(distance);
}
///
/// Moves the camera backwards along its local Z axis by units.
///
/// The distance to move.
- public void MoveBackward(float distance)
+ public void MoveBackward(double distance)
{
- _camera.Position -= _camera.LookDirectionVector * Math.Abs(distance);
+ _camera.Position -= _camera.LookDirectionVector * (float)Math.Abs(distance);
}
///
/// Moves the camera left along its local X axis by units.
///
/// The distance to move.
- public void MoveLeft(float distance)
+ public void MoveLeft(double distance)
{
- _camera.Position -= _camera.RightVector * Math.Abs(distance);
+ _camera.Position -= _camera.RightVector * (float)Math.Abs(distance);
}
///
/// Moves the camera right along its local X axis by units.
///
/// The distance to move.
- public void MoveRight(float distance)
+ public void MoveRight(double distance)
{
- _camera.Position += _camera.RightVector * Math.Abs(distance);
+ _camera.Position += _camera.RightVector * (float)Math.Abs(distance);
}
}
}
diff --git a/Everlook/Viewport/Camera/ViewportCamera.cs b/Everlook/Viewport/Camera/ViewportCamera.cs
index 2cd42ec..3d5cd0f 100644
--- a/Everlook/Viewport/Camera/ViewportCamera.cs
+++ b/Everlook/Viewport/Camera/ViewportCamera.cs
@@ -22,10 +22,10 @@
using System;
using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
using Everlook.Configuration;
+using Everlook.Utility;
using Everlook.Viewport.Rendering.Core;
-using OpenTK;
-using OpenTK.Graphics.ES10;
namespace Everlook.Viewport.Camera
{
@@ -66,12 +66,12 @@ public ProjectionType Projection
///
/// Gets or sets the width of the camera viewport in pixels.
///
- public int ViewportWidth { get; set; }
+ public uint ViewportWidth { get; set; }
///
/// Gets or sets the height of the camera viewport in pixels.
///
- public int ViewportHeight { get; set; }
+ public uint ViewportHeight { get; set; }
private Vector3 _positionInternal;
@@ -117,12 +117,12 @@ public Vector3 UpVector
private set;
}
- private float _horizontalViewAngleInternal;
+ private double _horizontalViewAngleInternal;
///
/// Gets or sets the current horizontal view angle of the observer.
///
- public float HorizontalViewAngle
+ public double HorizontalViewAngle
{
get => _horizontalViewAngleInternal;
set
@@ -132,13 +132,13 @@ public float HorizontalViewAngle
}
}
- private float _verticalViewAngleInternal;
+ private double _verticalViewAngleInternal;
///
/// Gets or sets the current vertical view angle of the observer. This angle is
/// limited to -90 and 90 (straight down and straight up, respectively).
///
- public float VerticalViewAngle
+ public double VerticalViewAngle
{
get => _verticalViewAngleInternal;
set
@@ -170,8 +170,8 @@ public void ResetPosition()
///
public void ResetRotation()
{
- this.HorizontalViewAngle = MathHelper.DegreesToRadians(180.0f);
- this.VerticalViewAngle = MathHelper.DegreesToRadians(0.0f);
+ this.HorizontalViewAngle = (float)MathHelper.DegreesToRadians(180.0);
+ this.VerticalViewAngle = (float)MathHelper.DegreesToRadians(0.0);
}
private void RecalculateInternals()
@@ -186,9 +186,9 @@ private void RecalculateInternals()
this.RightVector = new Vector3
(
- (float)Math.Sin(this.HorizontalViewAngle - MathHelper.PiOver2),
+ (float)Math.Sin(this.HorizontalViewAngle - (Math.PI / 2)),
0,
- (float)Math.Cos(this.HorizontalViewAngle - MathHelper.PiOver2)
+ (float)Math.Cos(this.HorizontalViewAngle - (Math.PI / 2))
);
this.UpVector = Vector3.Cross(this.RightVector, this.LookDirectionVector);
@@ -197,13 +197,13 @@ private void RecalculateInternals()
///
/// Gets the calculated projection matrix for this camera, using the values contained inside it.
///
- /// A projection matrix.
- public Matrix4 GetProjectionMatrix()
+ /// A projection matrix.
+ public Matrix4x4 GetProjectionMatrix()
{
- Matrix4 projectionMatrix;
+ Matrix4x4 projectionMatrix;
if (this.Projection == ProjectionType.Orthographic)
{
- projectionMatrix = Matrix4.CreateOrthographic
+ projectionMatrix = Matrix4x4.CreateOrthographic
(
this.ViewportWidth,
this.ViewportHeight,
@@ -214,9 +214,9 @@ public Matrix4 GetProjectionMatrix()
else
{
var aspectRatio = (float)this.ViewportWidth / this.ViewportHeight;
- projectionMatrix = Matrix4.CreatePerspectiveFieldOfView
+ projectionMatrix = Matrix4x4.CreatePerspectiveFieldOfView
(
- MathHelper.DegreesToRadians((float)EverlookConfiguration.Instance.CameraFOV),
+ (float)MathHelper.DegreesToRadians(EverlookConfiguration.Instance.CameraFOV),
aspectRatio,
DefaultNearClippingDistance,
DefaultFarClippingDistance
@@ -229,10 +229,10 @@ public Matrix4 GetProjectionMatrix()
///
/// Gets the view matrix of this camera (i.e, where it is looking).
///
- /// A view matrix.
- public Matrix4 GetViewMatrix()
+ /// A view matrix.
+ public Matrix4x4 GetViewMatrix()
{
- return Matrix4.LookAt
+ return Matrix4x4.CreateLookAt
(
this.Position,
this.Position + this.LookDirectionVector,
@@ -251,16 +251,17 @@ public Matrix4 GetViewMatrix()
Justification = "Used for matrix parameter alignment."
)
]
- public Matrix3 GetViewportMatrix()
+ public Matrix4x4 GetViewportMatrix()
{
var widthOver2 = this.ViewportWidth / 2.0f;
var heightOver2 = this.ViewportHeight / 2.0f;
- return new Matrix3
+ return new Matrix4x4
(
- widthOver2, 0, widthOver2,
- 0, heightOver2, heightOver2,
- 0, 0, 1
+ widthOver2, 0, widthOver2, 0,
+ 0, heightOver2, heightOver2, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
);
}
}
diff --git a/Everlook/Viewport/Rendering/Core/ActorInstanceSet.cs b/Everlook/Viewport/Rendering/Core/ActorInstanceSet.cs
index 9eee907..16c9afd 100644
--- a/Everlook/Viewport/Rendering/Core/ActorInstanceSet.cs
+++ b/Everlook/Viewport/Rendering/Core/ActorInstanceSet.cs
@@ -23,19 +23,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Numerics;
using System.Runtime.InteropServices;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Interfaces;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Core
{
///
- /// Represets a set of actor instances, differing by their transforms.
+ /// Represents a set of actor instances, differing by their transforms.
///
/// A renderable supporting instanced rendering.
- public class ActorInstanceSet : IRenderable, IBoundedModel
+ public class ActorInstanceSet : GraphicsObject, IRenderable, IBoundedModel
where T : class, IInstancedRenderable, IActor, IBoundedModel
{
///
@@ -64,15 +64,17 @@ public bool ShouldRenderBounds
///
public int Count => _instanceTransforms.Count;
- private Buffer? _instanceModelMatrices;
+ private Buffer? _instanceModelMatrices;
private List _instanceTransforms;
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
/// The target instanced renderable.
- public ActorInstanceSet(T target)
+ public ActorInstanceSet(GL gl, T target)
+ : base(gl)
{
this.Target = target;
_instanceTransforms = new List();
@@ -92,34 +94,71 @@ public void SetInstances(IEnumerable instanceTransforms)
///
public void Initialize()
{
- _instanceModelMatrices = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw);
+ _instanceModelMatrices = new Buffer
+ (
+ this.GL,
+ BufferTargetARB.ArrayBuffer,
+ BufferUsageARB.StaticDraw);
_instanceModelMatrices.AttachAttributePointer
(
- new VertexAttributePointer(6, 4, VertexAttribPointerType.Float, Marshal.SizeOf(), 0)
+ new VertexAttributePointer
+ (
+ this.GL,
+ 6,
+ 4,
+ VertexAttribPointerType.Float,
+ (uint)Marshal.SizeOf(),
+ 0
+ )
);
_instanceModelMatrices.AttachAttributePointer
(
- new VertexAttributePointer(7, 4, VertexAttribPointerType.Float, Marshal.SizeOf(), 16)
+ new VertexAttributePointer
+ (
+ this.GL,
+ 7,
+ 4,
+ VertexAttribPointerType.Float,
+ (uint)Marshal.SizeOf(),
+ 16
+ )
);
_instanceModelMatrices.AttachAttributePointer
(
- new VertexAttributePointer(8, 4, VertexAttribPointerType.Float, Marshal.SizeOf(), 32)
+ new VertexAttributePointer
+ (
+ this.GL,
+ 8,
+ 4,
+ VertexAttribPointerType.Float,
+ (uint)Marshal.SizeOf(),
+ 32
+ )
);
_instanceModelMatrices.AttachAttributePointer
(
- new VertexAttributePointer(9, 4, VertexAttribPointerType.Float, Marshal.SizeOf(), 48)
+ new VertexAttributePointer
+ (
+ this.GL,
+ 9,
+ 4,
+ VertexAttribPointerType.Float,
+ (uint)Marshal.SizeOf(),
+ 48
+ )
);
_instanceModelMatrices.Bind();
_instanceModelMatrices.EnableAttributes();
- GL.VertexAttribDivisor(6, 1);
- GL.VertexAttribDivisor(7, 1);
- GL.VertexAttribDivisor(8, 1);
- GL.VertexAttribDivisor(9, 1);
+
+ this.GL.VertexAttribDivisor(6, 1);
+ this.GL.VertexAttribDivisor(7, 1);
+ this.GL.VertexAttribDivisor(8, 1);
+ this.GL.VertexAttribDivisor(9, 1);
_instanceModelMatrices.Data = _instanceTransforms.Select(t => t.GetModelMatrix()).ToArray();
@@ -127,7 +166,7 @@ public void Initialize()
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
if (!this.IsInitialized || _instanceModelMatrices is null)
{
diff --git a/Everlook/Viewport/Rendering/Core/BaseGrid.cs b/Everlook/Viewport/Rendering/Core/BaseGrid.cs
index 3ae30f1..57aa28a 100644
--- a/Everlook/Viewport/Rendering/Core/BaseGrid.cs
+++ b/Everlook/Viewport/Rendering/Core/BaseGrid.cs
@@ -22,12 +22,11 @@
using System;
using System.Collections.Generic;
+using System.Numerics;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Interfaces;
using Everlook.Viewport.Rendering.Shaders;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Core
{
@@ -35,7 +34,7 @@ namespace Everlook.Viewport.Rendering.Core
/// Represents a base grid in the viewport, centered at the world and spanning 100x100 world units, subdivided
/// into squares.
///
- public class BaseGrid : IActor, IRenderable
+ public class BaseGrid : GraphicsObject, IActor, IRenderable
{
///
/// The size of one side of the grid.
@@ -72,9 +71,12 @@ public class BaseGrid : IActor, IRenderable
///
/// Initializes a new instance of the class.
///
- public BaseGrid()
+ /// The OpenGL API.
+ /// The rendering cache.
+ public BaseGrid(GL gl, RenderCache renderCache)
+ : base(gl)
{
- _shader = (BaseGridShader)RenderCache.Instance.GetShader(EverlookShader.BaseGrid);
+ _shader = (BaseGridShader)renderCache.GetShader(EverlookShader.BaseGrid);
this.ActorTransform = new Transform();
this.IsInitialized = false;
@@ -119,7 +121,7 @@ public void Initialize()
vertexIndexes.AddRange(new ushort[] { 0, Quads * 2 });
vertexIndexes.AddRange(new ushort[] { 1, (Quads * 2) + 1 });
- _vertices = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw)
+ _vertices = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = vertices.ToArray()
};
@@ -127,17 +129,17 @@ public void Initialize()
// Attach the vertex pointer
_vertices.AttachAttributePointer
(
- new VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 0, 0)
+ new VertexAttributePointer(this.GL, 0, 3, VertexAttribPointerType.Float, 0, 0)
);
- _vertexIndexes = new Buffer(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw)
+ _vertexIndexes = new Buffer(this.GL, BufferTargetARB.ElementArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = vertexIndexes.ToArray()
};
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
ThrowIfDisposed();
@@ -146,9 +148,9 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
return;
}
- GL.Enable(EnableCap.Blend);
- GL.Enable(EnableCap.DepthTest);
- GL.Disable(EnableCap.CullFace);
+ this.GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.DepthTest);
+ this.GL.Disable(EnableCap.CullFace);
_vertices.Bind();
_vertices.EnableAttributes();
@@ -158,20 +160,23 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
_shader.Enable();
- GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero);
+ this.GL.BlendFunc(BlendingFactor.One, BlendingFactor.Zero);
// Set the default line colour (a light gray)
- _shader.SetLineColour(new Color4(64, 64, 64, 255));
+ _shader.SetLineColour(new Vector4(64, 64, 64, 255));
_shader.SetMVPMatrix(modelViewProjection);
- var lineCount = ((Quads * 2) + 2) * 2;
- GL.DrawElements
- (
- PrimitiveType.Lines,
- lineCount,
- DrawElementsType.UnsignedShort,
- IntPtr.Zero
- );
+ uint lineCount = ((Quads * 2) + 2) * 2;
+ unsafe
+ {
+ this.GL.DrawElements
+ (
+ PrimitiveType.Lines,
+ lineCount,
+ DrawElementsType.UnsignedShort,
+ (void*)0
+ );
+ }
_vertices.DisableAttributes();
}
@@ -184,7 +189,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(BaseGrid));
}
}
diff --git a/Everlook/Viewport/Rendering/Core/Buffer.cs b/Everlook/Viewport/Rendering/Core/Buffer.cs
index 7d842f2..d415d7a 100644
--- a/Everlook/Viewport/Rendering/Core/Buffer.cs
+++ b/Everlook/Viewport/Rendering/Core/Buffer.cs
@@ -24,7 +24,7 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Everlook.Viewport.Rendering.Interfaces;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Core
{
@@ -32,18 +32,18 @@ namespace Everlook.Viewport.Rendering.Core
/// Represents a native OpenGL data buffer.
///
/// Any structure.
- public sealed class Buffer : IDisposable, IBuffer where T : struct
+ public sealed class Buffer : GraphicsObject, IDisposable, IBuffer where T : unmanaged
{
- private readonly int _nativeBufferID;
+ private readonly uint _nativeBufferID;
///
- public BufferTarget Target { get; }
+ public BufferTargetARB Target { get; }
///
- public BufferUsageHint Usage { get; }
+ public BufferUsageARB Usage { get; }
///
- public int Length { get; private set; }
+ public ulong Length { get; private set; }
///
/// Gets the attribute pointers of the buffer.
@@ -59,8 +59,20 @@ public T[] Data
{
Bind();
- var bufferData = new T[this.Length / Marshal.SizeOf()];
- GL.GetBufferSubData(this.Target, IntPtr.Zero, this.Length, bufferData);
+ var bufferData = new T[this.Length / (ulong)Marshal.SizeOf()];
+ unsafe
+ {
+ fixed (void* ptr = bufferData)
+ {
+ this.GL.GetBufferSubData
+ (
+ this.Target,
+ IntPtr.Zero,
+ new UIntPtr(this.Length),
+ ptr
+ );
+ }
+ }
return bufferData;
}
@@ -69,33 +81,37 @@ public T[] Data
{
Bind();
- this.Length = value.Length * Marshal.SizeOf();
- GL.BufferData(this.Target, this.Length, value, this.Usage);
+ this.Length = (ulong)value.Length * (ulong)Marshal.SizeOf();
+
+ unsafe
+ {
+ fixed (void* ptr = value)
+ {
+ this.GL.BufferData(this.Target, new UIntPtr(this.Length), ptr, this.Usage);
+ }
+ }
}
}
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
/// The intended use of the buffer.
/// A hint as to how the buffer's data might be read or written.
- public Buffer(BufferTarget target, BufferUsageHint usage)
+ public Buffer(GL gl, BufferTargetARB target, BufferUsageARB usage)
+ : base(gl)
{
this.Target = target;
this.Usage = usage;
this.Attributes = new List();
- _nativeBufferID = GL.GenBuffer();
+ _nativeBufferID = this.GL.GenBuffer();
}
///
public void AttachAttributePointer(VertexAttributePointer attributePointer)
{
- if (attributePointer == null)
- {
- throw new ArgumentNullException(nameof(attributePointer));
- }
-
Bind();
this.Attributes.Add(attributePointer);
}
@@ -103,11 +119,6 @@ public void AttachAttributePointer(VertexAttributePointer attributePointer)
///
public void AttachAttributePointers(IEnumerable attributePointers)
{
- if (attributePointers == null)
- {
- throw new ArgumentNullException(nameof(attributePointers));
- }
-
Bind();
foreach (var attributePointer in attributePointers)
{
@@ -136,13 +147,13 @@ public void DisableAttributes()
///
public void Bind()
{
- GL.BindBuffer(this.Target, _nativeBufferID);
+ this.GL.BindBuffer(this.Target, _nativeBufferID);
}
///
public void Dispose()
{
- GL.DeleteBuffer(_nativeBufferID);
+ this.GL.DeleteBuffer(_nativeBufferID);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Core/DynamicInterpolator.cs b/Everlook/Viewport/Rendering/Core/DynamicInterpolator.cs
index 6dce840..0fd3880 100644
--- a/Everlook/Viewport/Rendering/Core/DynamicInterpolator.cs
+++ b/Everlook/Viewport/Rendering/Core/DynamicInterpolator.cs
@@ -23,7 +23,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using OpenTK;
+using System.Numerics;
using Warcraft.Core.Interpolation;
using Warcraft.Core.Structures;
@@ -56,16 +56,13 @@ public class DynamicInterpolator
// Two-component vector types
{ typeof(Vector2), v => new []{ (float)v.X, (float)v.Y } },
- { typeof(System.Numerics.Vector2), v => new []{ (float)v.X, (float)v.Y } },
// Three-component vector types
{ typeof(Vector3), v => new []{ (float)v.X, (float)v.Y, (float)v.Z } },
- { typeof(System.Numerics.Vector3), v => new []{ (float)v.X, (float)v.Y, (float)v.Z } },
{ typeof(RGB), v => new []{ (float)v.R, (float)v.G, (float)v.B } },
// Four-component vector types
{ typeof(Quaternion), v => new []{ (float)v.X, (float)v.Y, (float)v.Z, (float)v.W } },
- { typeof(System.Numerics.Quaternion), v => new []{ (float)v.X, (float)v.Y, (float)v.Z, (float)v.W } },
};
private static readonly Dictionary> TypeCoalescers =
@@ -86,16 +83,13 @@ public class DynamicInterpolator
// Two-component vector types
{ typeof(Vector2), v => new Vector2(v[0], v[1]) },
- { typeof(System.Numerics.Vector2), v => new System.Numerics.Vector2(v[0], v[1]) },
// Three-component vector types
{ typeof(Vector3), v => new Vector3(v[0], v[1], v[2]) },
- { typeof(System.Numerics.Vector3), v => new System.Numerics.Vector3(v[0], v[1], v[2]) },
{ typeof(RGB), v => new RGB(v[0], v[1], v[2]) },
// Four-component vector types
{ typeof(Quaternion), v => new Quaternion(v[0], v[1], v[2], v[3]) },
- { typeof(System.Numerics.Quaternion), v => new System.Numerics.Quaternion(v[0], v[1], v[2], v[3]) },
};
///
diff --git a/Everlook/Viewport/Rendering/Core/GraphicsObject.cs b/Everlook/Viewport/Rendering/Core/GraphicsObject.cs
new file mode 100644
index 0000000..03195dd
--- /dev/null
+++ b/Everlook/Viewport/Rendering/Core/GraphicsObject.cs
@@ -0,0 +1,48 @@
+//
+// GraphicsObject.cs
+//
+// Author:
+// Jarl Gullberg
+//
+// Copyright (c) 2017 Jarl Gullberg
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+
+using JetBrains.Annotations;
+using Silk.NET.OpenGL;
+
+namespace Everlook.Viewport.Rendering.Core
+{
+ ///
+ /// Represents the base class of any graphics-aware object.
+ ///
+ [PublicAPI]
+ public abstract class GraphicsObject
+ {
+ ///
+ /// Gets the OpenGL API available to this object.
+ ///
+ protected GL GL { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL API.
+ public GraphicsObject(GL gl)
+ {
+ this.GL = gl;
+ }
+ }
+}
diff --git a/Everlook/Viewport/Rendering/Core/Lights/AmbientLight.cs b/Everlook/Viewport/Rendering/Core/Lights/AmbientLight.cs
index bb1cf53..22ed522 100644
--- a/Everlook/Viewport/Rendering/Core/Lights/AmbientLight.cs
+++ b/Everlook/Viewport/Rendering/Core/Lights/AmbientLight.cs
@@ -20,7 +20,7 @@
// along with this program. If not, see .
//
-using OpenTK.Graphics;
+using System.Numerics;
namespace Everlook.Viewport.Rendering.Core.Lights
{
@@ -32,7 +32,7 @@ public class AmbientLight
///
/// Gets or sets the colour of the light.
///
- public Color4 LightColour { get; set; }
+ public Vector4 LightColour { get; set; }
///
/// Gets or sets the intensity, in lux, of the light.
diff --git a/Everlook/Viewport/Rendering/Core/Lights/DirectionalLight.cs b/Everlook/Viewport/Rendering/Core/Lights/DirectionalLight.cs
index a72775e..777777c 100644
--- a/Everlook/Viewport/Rendering/Core/Lights/DirectionalLight.cs
+++ b/Everlook/Viewport/Rendering/Core/Lights/DirectionalLight.cs
@@ -21,8 +21,7 @@
//
using System;
-using OpenTK;
-using OpenTK.Graphics;
+using System.Numerics;
namespace Everlook.Viewport.Rendering.Core.Lights
{
@@ -45,18 +44,25 @@ public class DirectionalLight
///
/// Gets the vector along which the light shines.
///
- public Vector3 LightVector => new Vector3
- (
- (float)Math.Cos(this.HorizontalAngle) * (float)Math.Cos(this.VerticalAngle),
- (float)Math.Sin(this.VerticalAngle),
- (float)Math.Sin(this.HorizontalAngle) * (float)Math.Cos(this.VerticalAngle)
- )
- .Normalized();
+ public Vector3 LightVector
+ {
+ get
+ {
+ var vec = new Vector3
+ (
+ (float)Math.Cos(this.HorizontalAngle) * (float)Math.Cos(this.VerticalAngle),
+ (float)Math.Sin(this.VerticalAngle),
+ (float)Math.Sin(this.HorizontalAngle) * (float)Math.Cos(this.VerticalAngle)
+ );
+
+ return vec / vec.Length();
+ }
+ }
///
/// Gets or sets the colour of the light.
///
- public Color4 LightColour { get; set; }
+ public Vector4 LightColour { get; set; }
///
/// Gets or sets the intensity, in lux, of the light.
diff --git a/Everlook/Viewport/Rendering/Core/Plane.cs b/Everlook/Viewport/Rendering/Core/Plane.cs
index 7d3533b..10c2a91 100644
--- a/Everlook/Viewport/Rendering/Core/Plane.cs
+++ b/Everlook/Viewport/Rendering/Core/Plane.cs
@@ -20,7 +20,7 @@
// along with this program. If not, see .
//
-using OpenTK;
+using System.Numerics;
namespace Everlook.Viewport.Rendering.Core
{
@@ -58,7 +58,7 @@ public Plane(Vector3 inNormal, Vector3 inPointOnPlane)
///
/// The point from which to measure the distance.
/// The distance between the point and the plane.
- public float Distance(Vector3 point)
+ public readonly float Distance(Vector3 point)
{
return Vector3.Dot(this.Normal, point - this.PointOnPlane);
}
diff --git a/Everlook/Viewport/Rendering/Core/RenderableActorReference.cs b/Everlook/Viewport/Rendering/Core/RenderableActorReference.cs
index 0f279f5..784fa3a 100644
--- a/Everlook/Viewport/Rendering/Core/RenderableActorReference.cs
+++ b/Everlook/Viewport/Rendering/Core/RenderableActorReference.cs
@@ -21,9 +21,9 @@
//
using System;
+using System.Numerics;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Interfaces;
-using OpenTK;
namespace Everlook.Viewport.Rendering.Core
{
@@ -65,16 +65,6 @@ public RenderableActorReference(T target)
/// The transform of the instance.
public RenderableActorReference(T target, Transform transform)
{
- if (target == null)
- {
- throw new ArgumentNullException(nameof(target));
- }
-
- if (transform == null)
- {
- throw new ArgumentNullException(nameof(transform));
- }
-
_target = target;
_defaultTransform = target.ActorTransform;
@@ -88,7 +78,7 @@ public void Initialize()
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
_target.ActorTransform = this.ActorTransform;
_target.Render(viewMatrix, projectionMatrix, camera);
diff --git a/Everlook/Viewport/Rendering/Core/ShaderProgram.cs b/Everlook/Viewport/Rendering/Core/ShaderProgram.cs
index 5d78f94..e060e14 100644
--- a/Everlook/Viewport/Rendering/Core/ShaderProgram.cs
+++ b/Everlook/Viewport/Rendering/Core/ShaderProgram.cs
@@ -21,13 +21,13 @@
//
using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
using Everlook.Exceptions.Shader;
using Everlook.Utility;
using Everlook.Viewport.Rendering.Shaders.GLSLExtended;
using log4net;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Core
{
@@ -35,7 +35,7 @@ namespace Everlook.Viewport.Rendering.Core
/// Wraps basic OpenGL functionality for a shader program. This class is made to be extended out into
/// more advanced shaders with specific functionality.
///
- public abstract class ShaderProgram : IDisposable
+ public abstract class ShaderProgram : GraphicsObject, IDisposable
{
private const string MVPIdentifier = "ModelViewProjection";
@@ -47,13 +47,16 @@ public abstract class ShaderProgram : IDisposable
///
/// Gets the native OpenGL ID of the shader program.
///
- protected int NativeShaderProgramID { get; private set; }
+ protected uint NativeShaderProgramID { get; private set; }
///
/// Initializes a new instance of the class, compiling and linking its associated
/// shader sources into a shader program on the GPU.
///
- protected ShaderProgram()
+ /// The OpenGL API.
+ [SuppressMessage("ReSharper", "VirtualMemberCallInConstructor", Justification = "Required.")]
+ protected ShaderProgram(GL gl)
+ : base(gl)
{
var vertexShaderSource = GetShaderSource(this.VertexShaderResourceName);
var fragmentShaderSource = GetShaderSource(this.FragmentShaderResourceName);
@@ -88,7 +91,7 @@ protected ShaderProgram()
/// Sets the Model-View-Projection matrix of this shader.
///
/// The ModelViewProjection matrix.
- public void SetMVPMatrix(Matrix4 mvpMatrix)
+ public void SetMVPMatrix(Matrix4x4 mvpMatrix)
{
SetMatrix(mvpMatrix, MVPIdentifier);
}
@@ -102,8 +105,8 @@ protected void SetBoolean(bool value, string uniformName)
{
Enable();
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.Uniform1(variableHandle, value ? 1 : 0);
+ var variableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
+ this.GL.Uniform1(variableHandle, value ? 1 : 0);
}
///
@@ -112,12 +115,15 @@ protected void SetBoolean(bool value, string uniformName)
/// The matrix.
/// The name of the uniform variable.
/// Whether or not the matrix should be transposed.
- protected void SetMatrix(Matrix4 matrix, string uniformName, bool shouldTranspose = false)
+ protected void SetMatrix(Matrix4x4 matrix, string uniformName, bool shouldTranspose = false)
{
Enable();
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.UniformMatrix4(variableHandle, shouldTranspose, ref matrix);
+ var variableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
+ unsafe
+ {
+ this.GL.UniformMatrix4(variableHandle, 1, shouldTranspose, &matrix.M11);
+ }
}
///
@@ -129,8 +135,8 @@ protected void SetInteger(int value, string uniformName)
{
Enable();
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.Uniform1(variableHandle, value);
+ var variableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
+ this.GL.Uniform1(variableHandle, value);
}
///
@@ -142,21 +148,8 @@ protected void SetVector4(Vector4 value, string uniformName)
{
Enable();
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.Uniform4(variableHandle, value);
- }
-
- ///
- /// Sets the uniform named by to .
- ///
- /// The value.
- /// The name of the uniform variable.
- protected void SetColor4(Color4 value, string uniformName)
- {
- Enable();
-
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.Uniform4(variableHandle, value);
+ var variableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
+ this.GL.Uniform4(variableHandle, value);
}
///
@@ -168,8 +161,8 @@ protected void SetFloat(float value, string uniformName)
{
Enable();
- var variableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
- GL.Uniform1(variableHandle, value);
+ var variableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniformName);
+ this.GL.Uniform1(variableHandle, value);
}
///
@@ -181,17 +174,12 @@ protected void SetFloat(float value, string uniformName)
/// The texture to bind.
public void BindTexture2D(TextureUnit textureUnit, TextureUniform uniform, Texture2D texture)
{
- if (texture == null)
- {
- throw new ArgumentNullException(nameof(texture));
- }
-
Enable();
- var textureVariableHandle = GL.GetUniformLocation(this.NativeShaderProgramID, uniform.ToString());
- GL.Uniform1(textureVariableHandle, (int)uniform);
+ var textureVariableHandle = this.GL.GetUniformLocation(this.NativeShaderProgramID, uniform.ToString());
+ this.GL.Uniform1(textureVariableHandle, (int)uniform);
- GL.ActiveTexture(textureUnit);
+ this.GL.ActiveTexture(textureUnit);
texture.Bind();
}
@@ -232,33 +220,33 @@ public void BindTexture2D(TextureUnit textureUnit, TextureUniform uniform, Textu
///
/// A native handle to a shader program.
/// Thrown if the linking fails.
- private static int LinkShader(int vertexShaderID, int fragmentShaderID, int geometryShaderID = -1)
+ private uint LinkShader(uint vertexShaderID, uint fragmentShaderID, uint geometryShaderID = 0)
{
Log.Info("Linking shader program...");
- var program = GL.CreateProgram();
+ var program = this.GL.CreateProgram();
- GL.AttachShader(program, vertexShaderID);
- GL.AttachShader(program, fragmentShaderID);
+ this.GL.AttachShader(program, vertexShaderID);
+ this.GL.AttachShader(program, fragmentShaderID);
- if (geometryShaderID > -1)
+ if (geometryShaderID > 0)
{
- GL.AttachShader(program, geometryShaderID);
+ this.GL.AttachShader(program, geometryShaderID);
}
- GL.LinkProgram(program);
+ this.GL.LinkProgram(program);
- GL.GetProgram(program, GetProgramParameterName.LinkStatus, out var result);
+ this.GL.GetProgram(program, ProgramPropertyARB.LinkStatus, out var result);
var linkingSucceeded = result > 0;
- GL.GetProgram(program, GetProgramParameterName.InfoLogLength, out var linkingLogLength);
- GL.GetProgramInfoLog(program, out var linkingLog);
+ this.GL.GetProgram(program, ProgramPropertyARB.InfoLogLength, out var linkingLogLength);
+ this.GL.GetProgramInfoLog(program, out var linkingLog);
// Clean up the shader source code and unlinked object files from graphics memory
- GL.DetachShader(program, vertexShaderID);
- GL.DetachShader(program, fragmentShaderID);
+ this.GL.DetachShader(program, vertexShaderID);
+ this.GL.DetachShader(program, fragmentShaderID);
- GL.DeleteShader(vertexShaderID);
- GL.DeleteShader(fragmentShaderID);
+ this.GL.DeleteShader(vertexShaderID);
+ this.GL.DeleteShader(fragmentShaderID);
if (!linkingSucceeded)
{
@@ -281,7 +269,7 @@ private static int LinkShader(int vertexShaderID, int fragmentShaderID, int geom
/// The source code of the shader.
/// A native handle to the shader object code.
/// Thrown if the compilation fails.
- private static int CompileShader(ShaderType shaderType, string shaderSource)
+ private uint CompileShader(ShaderType shaderType, string shaderSource)
{
if (string.IsNullOrEmpty(shaderSource))
{
@@ -292,21 +280,21 @@ private static int CompileShader(ShaderType shaderType, string shaderSource)
);
}
- var shader = GL.CreateShader(shaderType);
+ var shader = this.GL.CreateShader(shaderType);
Log.Info("Compiling shader...");
- GL.ShaderSource(shader, shaderSource);
- GL.CompileShader(shader);
+ this.GL.ShaderSource(shader, shaderSource);
+ this.GL.CompileShader(shader);
- GL.GetShader(shader, ShaderParameter.CompileStatus, out var result);
+ this.GL.GetShader(shader, ShaderParameterName.CompileStatus, out var result);
var compilationSucceeded = result > 0;
- GL.GetShader(shader, ShaderParameter.InfoLogLength, out var compilationLogLength);
- GL.GetShaderInfoLog(shader, out var compilationLog);
+ this.GL.GetShader(shader, ShaderParameterName.InfoLogLength, out var compilationLogLength);
+ this.GL.GetShaderInfoLog(shader, out var compilationLog);
if (!compilationSucceeded)
{
- GL.DeleteShader(shader);
+ this.GL.DeleteShader(shader);
throw new ShaderCompilationException(ShaderType.VertexShader, compilationLog);
}
@@ -345,14 +333,14 @@ private static int CompileShader(ShaderType shaderType, string shaderSource)
///
public void Enable()
{
- GL.UseProgram(this.NativeShaderProgramID);
+ this.GL.UseProgram(this.NativeShaderProgramID);
}
///
public void Dispose()
{
- GL.DeleteProgram(this.NativeShaderProgramID);
- this.NativeShaderProgramID = -1;
+ this.GL.DeleteProgram(this.NativeShaderProgramID);
+ this.NativeShaderProgramID = 0;
}
}
}
diff --git a/Everlook/Viewport/Rendering/Core/Texture2D.cs b/Everlook/Viewport/Rendering/Core/Texture2D.cs
index 0b507da..4b6d23f 100644
--- a/Everlook/Viewport/Rendering/Core/Texture2D.cs
+++ b/Everlook/Viewport/Rendering/Core/Texture2D.cs
@@ -23,18 +23,15 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
-using System.IO;
-
using log4net;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using Warcraft.BLP;
-using Warcraft.Core.Structures;
-using GLPixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
+
using Image = System.Drawing.Image;
+using PixelFormat = Silk.NET.OpenGL.PixelFormat;
using Rectangle = System.Drawing.Rectangle;
using SysPixelFormat = System.Drawing.Imaging.PixelFormat;
@@ -43,7 +40,7 @@ namespace Everlook.Viewport.Rendering.Core
///
/// Wraps functionality around an OpenGL texture.
///
- public sealed class Texture2D : IDisposable
+ public sealed class Texture2D : GraphicsObject, IDisposable
{
///
/// Logger instance for this class.
@@ -51,7 +48,7 @@ public sealed class Texture2D : IDisposable
private static readonly ILog Log = LogManager.GetLogger(typeof(Texture2D));
private readonly object _textureLock = new object();
- private int _nativeTextureID;
+ private uint _nativeTextureID;
///
/// Gets or sets the filter used when magnifying the texture.
@@ -63,7 +60,7 @@ public TextureMagFilter MagnificationFilter
}
///
- /// Gets or sets the filter used when miniturizing the texture.
+ /// Gets or sets the filter used when miniaturizing the texture.
///
public TextureMinFilter MiniaturizationFilter
{
@@ -100,9 +97,11 @@ public TextureWrapMode WrappingModeT
///
/// Initializes a new instance of the class.
///
- private Texture2D()
+ /// The OpenGL API.
+ private Texture2D(GL gl)
+ : base(gl)
{
- _nativeTextureID = GL.GenTexture();
+ _nativeTextureID = this.GL.GenTexture();
}
///
@@ -110,16 +109,12 @@ private Texture2D()
/// mipmaps for the bitmap.
///
/// The image data to create the texture from.
+ /// The OpenGL API.
/// Optional. The wrapping mode to use for the texture.
/// Thrown if the image data is null.
- public Texture2D(Bitmap imageData, TextureWrapMode wrapMode = TextureWrapMode.Repeat)
- : this()
+ public Texture2D(GL gl, Bitmap imageData, TextureWrapMode wrapMode = TextureWrapMode.Repeat)
+ : this(gl)
{
- if (imageData == null)
- {
- throw new ArgumentNullException(nameof(imageData));
- }
-
CreateFromBitmap(imageData);
this.MagnificationFilter = TextureMagFilter.Linear;
@@ -132,11 +127,12 @@ public Texture2D(Bitmap imageData, TextureWrapMode wrapMode = TextureWrapMode.Re
/// Mipmaps are loaded from the compressed texture.
///
/// The image data to create the texture from.
+ /// The OpenGL API.
/// Optional. The magnification filter to use for the texture.
/// Optional. The miniaturization filter to use for the texture.
/// Thrown if the image data is null.
- public Texture2D(BLP imageData, TextureMagFilter magFilter, TextureMinFilter minFilter)
- : this(imageData, TextureWrapMode.Repeat, TextureWrapMode.Repeat, magFilter, minFilter)
+ public Texture2D(GL gl, BLP imageData, TextureMagFilter magFilter, TextureMinFilter minFilter)
+ : this(gl, imageData, TextureWrapMode.Repeat, TextureWrapMode.Repeat, magFilter, minFilter)
{
}
@@ -146,10 +142,11 @@ public Texture2D(BLP imageData, TextureMagFilter magFilter, TextureMinFilter min
///
/// The image data to create the texture from.
/// The magnification filter to use for the texture.
+ /// The OpenGL API.
/// The miniaturization filter to use for the texture.
/// Thrown if the image data is null.
- public Texture2D(BLP imageData, TextureMinFilter minFilter, TextureMagFilter magFilter)
- : this(imageData, magFilter, minFilter)
+ public Texture2D(GL gl, BLP imageData, TextureMinFilter minFilter, TextureMagFilter magFilter)
+ : this(gl, imageData, magFilter, minFilter)
{
}
@@ -158,20 +155,24 @@ public Texture2D(BLP imageData, TextureMinFilter minFilter, TextureMagFilter mag
/// Mipmaps are loaded from the compressed texture.
///
/// The image data to create the texture from.
+ /// The OpenGL API.
/// The wrapping mode to use for the texture on the S axis.
/// The wrapping mode to use for the texture on the T axis.
/// The magnification filter to use for the texture.
/// The miniaturization filter to use for the texture.
/// Thrown if the image data is null.
- public Texture2D(
+ public Texture2D
+ (
+ GL gl,
BLP imageData,
TextureWrapMode wrapModeS = TextureWrapMode.Repeat,
TextureWrapMode wrapModeT = TextureWrapMode.Repeat,
TextureMagFilter magFilter = TextureMagFilter.Linear,
- TextureMinFilter minFilter = TextureMinFilter.LinearMipmapLinear)
- : this()
+ TextureMinFilter minFilter = TextureMinFilter.LinearMipmapLinear
+ )
+ : this(gl)
{
- if (imageData == null)
+ if (imageData is null)
{
throw new ArgumentNullException(nameof(imageData));
}
@@ -182,29 +183,25 @@ public Texture2D(
{
CreateFromDXT(imageData);
}
- catch (GraphicsErrorException gex)
+ catch (Exception ex)
{
Log.Warn
(
- $"GraphicsErrorException in CreateFromDXT (failed to create DXT texture): {gex.Message}\n" +
+ $"GraphicsErrorException in CreateFromDXT (failed to create DXT texture): {ex.Message}\n" +
"The texture will be loaded as a bitmap instead."
);
}
finally
{
// Load a fallback bitmap instead
- using (var mipZero = imageData.GetMipMap(0))
- {
- CreateFromImage(mipZero);
- }
+ using var mipZero = imageData.GetMipMap(0);
+ CreateFromImage(mipZero);
}
}
else
{
- using (var mipZero = imageData.GetMipMap(0))
- {
- CreateFromImage(mipZero);
- }
+ using var mipZero = imageData.GetMipMap(0);
+ CreateFromImage(mipZero);
}
this.MagnificationFilter = magFilter;
@@ -229,7 +226,7 @@ private void SetMagnificationFilter(TextureMagFilter magFilter)
lock (_textureLock)
{
Bind();
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)magFilter);
+ this.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)magFilter);
}
}
@@ -241,7 +238,7 @@ private void SetMiniaturizationFilter(TextureMinFilter minFilter)
lock (_textureLock)
{
Bind();
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)minFilter);
+ this.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)minFilter);
}
}
@@ -254,7 +251,7 @@ private TextureMagFilter GetMagnificationFilter()
lock (_textureLock)
{
Bind();
- GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureMagFilter, out int magFilter);
+ this.GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureMagFilter, out int magFilter);
return (TextureMagFilter)magFilter;
}
}
@@ -268,7 +265,7 @@ private TextureMinFilter GetMiniaturizationFilter()
lock (_textureLock)
{
Bind();
- GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureMinFilter, out int minFilter);
+ this.GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureMinFilter, out int minFilter);
return (TextureMinFilter)minFilter;
}
}
@@ -297,7 +294,7 @@ private void SetWrappingModeS(TextureWrapMode wrapModeS)
lock (_textureLock)
{
Bind();
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)wrapModeS);
+ this.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)wrapModeS);
}
}
@@ -310,7 +307,7 @@ private void SetWrappingModeT(TextureWrapMode wrapModeT)
lock (_textureLock)
{
Bind();
- GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)wrapModeT);
+ this.GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)wrapModeT);
}
}
@@ -323,7 +320,7 @@ private TextureWrapMode GetWrappingModeS()
lock (_textureLock)
{
Bind();
- GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureWrapS, out int wrapModeS);
+ this.GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureWrapS, out int wrapModeS);
return (TextureWrapMode)wrapModeS;
}
}
@@ -337,7 +334,7 @@ private TextureWrapMode GetWrappingModeT()
lock (_textureLock)
{
Bind();
- GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureWrapT, out int wrapModeT);
+ this.GL.GetTexParameter(TextureTarget.Texture2D, GetTextureParameter.TextureWrapT, out int wrapModeT);
return (TextureWrapMode)wrapModeT;
}
}
@@ -363,17 +360,17 @@ private void CreateFromDXT(BLP inTextureData)
{
case BLPPixelFormat.DXT1:
{
- compressionFormat = InternalFormat.CompressedRgbaS3tcDxt1Ext;
+ compressionFormat = InternalFormat.CompressedRgbaS3TCDxt1Ext;
break;
}
case BLPPixelFormat.DXT3:
{
- compressionFormat = InternalFormat.CompressedRgbaS3tcDxt3Ext;
+ compressionFormat = InternalFormat.CompressedRgbaS3TCDxt3Ext;
break;
}
case BLPPixelFormat.DXT5:
{
- compressionFormat = InternalFormat.CompressedRgbaS3tcDxt5Ext;
+ compressionFormat = InternalFormat.CompressedRgbaS3TCDxt5Ext;
break;
}
default:
@@ -387,17 +384,23 @@ private void CreateFromDXT(BLP inTextureData)
}
// Load the mipmap into the texture
- GL.CompressedTexImage2D
- (
- TextureTarget.Texture2D,
- (int)i,
- compressionFormat,
- (int)mipResolution.X,
- (int)mipResolution.Y,
- 0,
- compressedMipMap.Length,
- compressedMipMap
- );
+ unsafe
+ {
+ fixed (void* ptr = compressedMipMap)
+ {
+ this.GL.CompressedTexImage2D
+ (
+ TextureTarget.Texture2D,
+ (int)i,
+ compressionFormat,
+ mipResolution.X,
+ mipResolution.Y,
+ 0,
+ (uint)compressedMipMap.Length,
+ ptr
+ );
+ }
+ }
}
}
}
@@ -420,20 +423,23 @@ private void CreateFromBitmap(Bitmap inTextureData)
SysPixelFormat.Format32bppArgb
);
- GL.TexImage2D
- (
- TextureTarget.Texture2D,
- 0, // level
- PixelInternalFormat.Rgba,
- pixels.Width,
- pixels.Height,
- 0, // border
- GLPixelFormat.Bgra,
- PixelType.UnsignedByte,
- pixels.Scan0
- );
+ unsafe
+ {
+ this.GL.TexImage2D
+ (
+ TextureTarget.Texture2D,
+ 0, // level
+ (int)InternalFormat.Rgba,
+ (uint)pixels.Width,
+ (uint)pixels.Height,
+ 0, // border
+ PixelFormat.Bgra,
+ PixelType.UnsignedByte,
+ pixels.Scan0.ToPointer()
+ );
+ }
- GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+ this.GL.GenerateMipmap(TextureTarget.Texture2D);
inTextureData.UnlockBits(pixels);
}
@@ -450,22 +456,22 @@ private void CreateFromImage(Image inTextureData)
{
fixed (void* ptr = &inTextureData.GetPixelSpan().GetPinnableReference())
{
- GL.TexImage2D
+ this.GL.TexImage2D
(
TextureTarget.Texture2D,
0, // level
- PixelInternalFormat.Rgba,
- inTextureData.Width,
- inTextureData.Height,
+ (int)InternalFormat.Rgba,
+ (uint)inTextureData.Width,
+ (uint)inTextureData.Height,
0, // border
- GLPixelFormat.Rgba,
+ PixelFormat.Rgba,
PixelType.UnsignedByte,
- new IntPtr(ptr)
+ ptr
);
}
}
- GL.GenerateMipmap(GenerateMipmapTarget.Texture2D);
+ this.GL.GenerateMipmap(TextureTarget.Texture2D);
}
}
@@ -477,7 +483,7 @@ public void Bind()
{
lock (_textureLock)
{
- GL.BindTexture(TextureTarget.Texture2D, _nativeTextureID);
+ this.GL.BindTexture(TextureTarget.Texture2D, _nativeTextureID);
}
}
@@ -488,8 +494,8 @@ public void Dispose()
{
GC.SuppressFinalize(this);
- GL.DeleteTexture(_nativeTextureID);
- _nativeTextureID = -1;
+ this.GL.DeleteTexture(_nativeTextureID);
+ _nativeTextureID = 0;
}
}
}
diff --git a/Everlook/Viewport/Rendering/Core/Timeline.cs b/Everlook/Viewport/Rendering/Core/Timeline.cs
index acb45cf..7fc9246 100644
--- a/Everlook/Viewport/Rendering/Core/Timeline.cs
+++ b/Everlook/Viewport/Rendering/Core/Timeline.cs
@@ -24,7 +24,6 @@
using System.Collections.Generic;
using System.Linq;
using Everlook.Viewport.Rendering.Interfaces;
-using OpenTK;
using Warcraft.Core.Interpolation;
namespace Everlook.Viewport.Rendering.Core
@@ -214,7 +213,7 @@ protected float NormalizeTime(float time)
return time % this.Duration;
}
- return MathHelper.Clamp(time, 0, this.Duration);
+ return Math.Clamp(time, 0, this.Duration);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Core/Transform.cs b/Everlook/Viewport/Rendering/Core/Transform.cs
index 44c61a9..daf6e2c 100644
--- a/Everlook/Viewport/Rendering/Core/Transform.cs
+++ b/Everlook/Viewport/Rendering/Core/Transform.cs
@@ -20,7 +20,7 @@
// along with this program. If not, see .
//
-using OpenTK;
+using System.Numerics;
namespace Everlook.Viewport.Rendering.Core
{
@@ -94,14 +94,14 @@ public Transform(Vector3 translation, Quaternion orientation, Vector3 scale)
}
///
- /// Gets the object representing the model matrix of this transform.
+ /// Gets the object representing the model matrix of this transform.
///
/// A matrix containing model-space transformation data.
- public Matrix4 GetModelMatrix()
+ public Matrix4x4 GetModelMatrix()
{
- var modelScale = Matrix4.CreateScale(this.Scale);
- var modelOrientation = Matrix4.CreateFromQuaternion(this.Orientation);
- var modelTranslation = Matrix4.CreateTranslation(this.Translation);
+ var modelScale = Matrix4x4.CreateScale(this.Scale);
+ var modelOrientation = Matrix4x4.CreateFromQuaternion(this.Orientation);
+ var modelTranslation = Matrix4x4.CreateTranslation(this.Translation);
return modelScale * modelOrientation * modelTranslation;
}
diff --git a/Everlook/Viewport/Rendering/Core/VertexAttributePointer.cs b/Everlook/Viewport/Rendering/Core/VertexAttributePointer.cs
index 5a6d1ca..4653ca9 100644
--- a/Everlook/Viewport/Rendering/Core/VertexAttributePointer.cs
+++ b/Everlook/Viewport/Rendering/Core/VertexAttributePointer.cs
@@ -20,19 +20,19 @@
// along with this program. If not, see .
//
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Core
{
///
/// Represents a vertex attribute pointer.
///
- public class VertexAttributePointer
+ public class VertexAttributePointer : GraphicsObject
{
///
/// Gets the attribute array index that the pointer modifies.
///
- public int LayoutIndex { get; }
+ public uint LayoutIndex { get; }
///
/// Gets the number of components per attribute.
@@ -52,16 +52,17 @@ public class VertexAttributePointer
///
/// Gets the byte offset between consecutive vertex attributes.
///
- public int ByteStride { get; }
+ public uint ByteStride { get; }
///
/// Gets the offset to the first component of the first attribute in the array.
///
- public int FirstAttributeByteOffset { get; }
+ public uint FirstAttributeByteOffset { get; }
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
/// The attribute array layout index.
/// The number of components in the attribute.
/// The data type of each component in the attribute.
@@ -70,13 +71,15 @@ public class VertexAttributePointer
/// Whether or not the data should be normalized.
public VertexAttributePointer
(
- int layoutIndex,
+ GL gl,
+ uint layoutIndex,
int componentCount,
VertexAttribPointerType type,
- int byteStride,
- int firstAttributeByteOffset,
+ uint byteStride,
+ uint firstAttributeByteOffset,
bool isNormalized = false
)
+ : base(gl)
{
this.LayoutIndex = layoutIndex;
this.ComponentCount = componentCount;
@@ -93,16 +96,19 @@ public VertexAttributePointer
///
public void Enable()
{
- GL.EnableVertexAttribArray(this.LayoutIndex);
- GL.VertexAttribPointer
- (
- this.LayoutIndex,
- this.ComponentCount,
- this.Type,
- this.IsNormalized,
- this.ByteStride,
- this.FirstAttributeByteOffset
- );
+ this.GL.EnableVertexAttribArray(this.LayoutIndex);
+ unsafe
+ {
+ this.GL.VertexAttribPointer
+ (
+ this.LayoutIndex,
+ this.ComponentCount,
+ this.Type,
+ this.IsNormalized,
+ this.ByteStride,
+ (void*)this.FirstAttributeByteOffset
+ );
+ }
}
///
@@ -110,7 +116,7 @@ public void Enable()
///
public void Disable()
{
- GL.DisableVertexAttribArray(this.LayoutIndex);
+ this.GL.DisableVertexAttribArray(this.LayoutIndex);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Interfaces/IBuffer.cs b/Everlook/Viewport/Rendering/Interfaces/IBuffer.cs
index 526c55c..5684c17 100644
--- a/Everlook/Viewport/Rendering/Interfaces/IBuffer.cs
+++ b/Everlook/Viewport/Rendering/Interfaces/IBuffer.cs
@@ -23,7 +23,7 @@
using System;
using System.Collections.Generic;
using Everlook.Viewport.Rendering.Core;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Interfaces
{
@@ -35,17 +35,17 @@ public interface IBuffer
///
/// Gets the intended use of the buffer.
///
- BufferTarget Target { get; }
+ BufferTargetARB Target { get; }
///
/// Gets a hinting value as to how the buffer's data might be read or written.
///
- BufferUsageHint Usage { get; }
+ BufferUsageARB Usage { get; }
///
/// Gets the byte count of the data in the buffer.
///
- int Length { get; }
+ ulong Length { get; }
///
/// Attaches the specified attribute pointer to the buffer.
diff --git a/Everlook/Viewport/Rendering/Interfaces/IDefaultCameraPositionProvider.cs b/Everlook/Viewport/Rendering/Interfaces/IDefaultCameraPositionProvider.cs
index c603c45..e380e41 100644
--- a/Everlook/Viewport/Rendering/Interfaces/IDefaultCameraPositionProvider.cs
+++ b/Everlook/Viewport/Rendering/Interfaces/IDefaultCameraPositionProvider.cs
@@ -20,7 +20,7 @@
// along with this program. If not, see .
//
-using OpenTK;
+using System.Numerics;
namespace Everlook.Viewport.Rendering.Interfaces
{
diff --git a/Everlook/Viewport/Rendering/Interfaces/IInstancedRenderable.cs b/Everlook/Viewport/Rendering/Interfaces/IInstancedRenderable.cs
index a8b1e5c..6663ad3 100644
--- a/Everlook/Viewport/Rendering/Interfaces/IInstancedRenderable.cs
+++ b/Everlook/Viewport/Rendering/Interfaces/IInstancedRenderable.cs
@@ -20,8 +20,8 @@
// along with this program. If not, see .
//
+using System.Numerics;
using Everlook.Viewport.Camera;
-using OpenTK;
namespace Everlook.Viewport.Rendering.Interfaces
{
@@ -37,6 +37,6 @@ public interface IInstancedRenderable : IRenderable
/// The projection matrix.
/// The user camera.
/// The number of instances to render.
- void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera, int count);
+ void RenderInstances(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera, int count);
}
}
diff --git a/Everlook/Viewport/Rendering/Interfaces/IRenderable.cs b/Everlook/Viewport/Rendering/Interfaces/IRenderable.cs
index 1e56373..55187ff 100644
--- a/Everlook/Viewport/Rendering/Interfaces/IRenderable.cs
+++ b/Everlook/Viewport/Rendering/Interfaces/IRenderable.cs
@@ -21,9 +21,9 @@
//
using System;
+using System.Numerics;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Core;
-using OpenTK;
namespace Everlook.Viewport.Rendering.Interfaces
{
@@ -72,6 +72,6 @@ ProjectionType Projection
/// The view matrix.
/// The projection matrix.
/// The user camera.
- void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera);
+ void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera);
}
}
diff --git a/Everlook/Viewport/Rendering/RenderCache.cs b/Everlook/Viewport/Rendering/RenderCache.cs
index b320dd1..d7ce196 100644
--- a/Everlook/Viewport/Rendering/RenderCache.cs
+++ b/Everlook/Viewport/Rendering/RenderCache.cs
@@ -26,13 +26,13 @@
using Everlook.Utility;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Shaders;
+using JetBrains.Annotations;
using log4net;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using Warcraft.BLP;
using Warcraft.Core;
using Warcraft.MDX.Visual;
using Warcraft.MPQ;
-using GLPixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
using SysPixelFormat = System.Drawing.Imaging.PixelFormat;
namespace Everlook.Viewport.Rendering
@@ -43,7 +43,7 @@ namespace Everlook.Viewport.Rendering
///
/// Currently, these are textures and shader programs.
///
- public sealed class RenderCache : IDisposable
+ public sealed class RenderCache : GraphicsObject, IDisposable
{
///
/// Logger instance for this class.
@@ -75,17 +75,19 @@ public Texture2D FallbackTexture
{
ThrowIfDisposed();
- if (_fallbackTextureInternal == null)
+ if (!(_fallbackTextureInternal is null))
{
- var fallbackImage = ResourceManager.GetFallbackImage();
- if (fallbackImage is null)
- {
- throw new InvalidOperationException();
- }
+ return _fallbackTextureInternal;
+ }
- _fallbackTextureInternal = new Texture2D(fallbackImage);
+ var fallbackImage = ResourceManager.GetFallbackImage();
+ if (fallbackImage is null)
+ {
+ throw new InvalidOperationException();
}
+ _fallbackTextureInternal = new Texture2D(this.GL, fallbackImage);
+
return _fallbackTextureInternal;
}
}
@@ -93,16 +95,12 @@ public Texture2D FallbackTexture
private Texture2D? _fallbackTextureInternal;
///
- /// A singleton instance of the rendering cache.
+ /// Initializes a new instance of the class.
///
- public static readonly RenderCache Instance = new RenderCache();
-
- ///
- /// Finalizes an instance of the class.
- ///
- ~RenderCache()
+ /// The OpenGL API.
+ public RenderCache([NotNull] GL gl)
+ : base(gl)
{
- Dispose();
}
///
@@ -207,11 +205,11 @@ public Texture2D GetTexture(MDXTexture texture, IGameContext gameContext, string
var wrapS = texture.Flags.HasFlag(MDXTextureFlags.TextureWrapX)
? TextureWrapMode.Repeat
- : TextureWrapMode.Clamp;
+ : TextureWrapMode.ClampToBorder;
var wrapT = texture.Flags.HasFlag(MDXTextureFlags.TextureWrapY)
? TextureWrapMode.Repeat
- : TextureWrapMode.Clamp;
+ : TextureWrapMode.ClampToBorder;
return GetTexture(filename!, gameContext.Assets, wrapS, wrapT);
}
@@ -266,11 +264,9 @@ public Texture2D GetTexture
return this.FallbackTexture;
}
- using (var ms = new MemoryStream(data))
- {
- var texture = new Bitmap(ms);
- return CreateCachedTexture(texture, texturePath);
- }
+ using var ms = new MemoryStream(data);
+ var texture = new Bitmap(ms);
+ return CreateCachedTexture(texture, texturePath);
}
}
@@ -298,14 +294,14 @@ public Texture2D CreateCachedTexture
{
ThrowIfDisposed();
- var texture = new Texture2D(imageData, wrappingModeS, wrappingModeT);
+ var texture = new Texture2D(this.GL, imageData, wrappingModeS, wrappingModeT);
_textureCache.Add(texturePath.ConvertPathSeparatorsToCurrentNativeSeparator().ToUpperInvariant(), texture);
return texture;
}
///
- /// Creates a cached texture for the specifed texture, using the specified path
+ /// Creates a cached texture for the specified texture, using the specified path
/// as a lookup key. This method will create a new texture, and cache it.
///
/// A bitmap containing the image data.
@@ -317,7 +313,7 @@ public Texture2D CreateCachedTexture(Bitmap imageData, string texturePath)
{
ThrowIfDisposed();
- var texture = new Texture2D(imageData);
+ var texture = new Texture2D(this.GL, imageData);
_textureCache.Add(texturePath.ConvertPathSeparatorsToCurrentNativeSeparator().ToUpperInvariant(), texture);
return texture;
@@ -341,27 +337,27 @@ private ShaderProgram CreateCachedShader(EverlookShader shader)
{
case EverlookShader.Plain2D:
{
- shaderProgram = new Plain2DShader();
+ shaderProgram = new Plain2DShader(this.GL);
break;
}
case EverlookShader.WorldModel:
{
- shaderProgram = new WorldModelShader();
+ shaderProgram = new WorldModelShader(this.GL);
break;
}
case EverlookShader.BoundingBox:
{
- shaderProgram = new BoundingBoxShader();
+ shaderProgram = new BoundingBoxShader(this.GL);
break;
}
case EverlookShader.GameModel:
{
- shaderProgram = new GameModelShader();
+ shaderProgram = new GameModelShader(this.GL);
break;
}
case EverlookShader.BaseGrid:
{
- shaderProgram = new BaseGridShader();
+ shaderProgram = new BaseGridShader(this.GL);
break;
}
default:
@@ -386,7 +382,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(RenderCache));
}
}
diff --git a/Everlook/Viewport/Rendering/RenderableBLP.cs b/Everlook/Viewport/Rendering/RenderableBLP.cs
index 2fbaebc..fad6f46 100644
--- a/Everlook/Viewport/Rendering/RenderableBLP.cs
+++ b/Everlook/Viewport/Rendering/RenderableBLP.cs
@@ -22,6 +22,7 @@
using System;
using Everlook.Viewport.Rendering.Core;
+using Silk.NET.OpenGL;
using Warcraft.BLP;
using Warcraft.Core.Structures;
@@ -40,9 +41,12 @@ public sealed class RenderableBLP : RenderableImage
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// An image object with populated data.
/// The path under which this renderable texture is stored in the archives.
- public RenderableBLP(BLP inImage, string inTexturePath)
+ public RenderableBLP(GL gl, RenderCache renderCache, BLP inImage, string inTexturePath)
+ : base(gl, renderCache)
{
_image = inImage;
this.TexturePath = inTexturePath;
@@ -58,12 +62,12 @@ protected override Texture2D LoadTexture()
throw new InvalidOperationException();
}
- if (Cache.HasCachedTextureForPath(this.TexturePath))
+ if (this.RenderCache.HasCachedTextureForPath(this.TexturePath))
{
- return Cache.GetCachedTexture(this.TexturePath);
+ return this.RenderCache.GetCachedTexture(this.TexturePath);
}
- return Cache.CreateCachedTexture(_image, this.TexturePath);
+ return this.RenderCache.CreateCachedTexture(_image, this.TexturePath);
}
///
@@ -73,10 +77,9 @@ protected override Resolution GetResolution()
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var otherImage = obj as RenderableBLP;
- if (otherImage == null)
+ if (!(obj is RenderableBLP otherImage))
{
return false;
}
diff --git a/Everlook/Viewport/Rendering/RenderableBitmap.cs b/Everlook/Viewport/Rendering/RenderableBitmap.cs
index 75dcf60..7147374 100644
--- a/Everlook/Viewport/Rendering/RenderableBitmap.cs
+++ b/Everlook/Viewport/Rendering/RenderableBitmap.cs
@@ -23,6 +23,7 @@
using System;
using System.Drawing;
using Everlook.Viewport.Rendering.Core;
+using Silk.NET.OpenGL;
using Warcraft.Core.Structures;
namespace Everlook.Viewport.Rendering
@@ -44,9 +45,12 @@ private Bitmap Image
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// In image.
/// The path under which this renderable texture is stored in the archives.
- public RenderableBitmap(Bitmap inImage, string inTexturePath)
+ public RenderableBitmap(GL gl, RenderCache renderCache, Bitmap inImage, string inTexturePath)
+ : base(gl, renderCache)
{
this.Image = inImage;
this.TexturePath = inTexturePath;
@@ -62,12 +66,12 @@ protected override Texture2D LoadTexture()
throw new InvalidOperationException();
}
- if (Cache.HasCachedTextureForPath(this.TexturePath))
+ if (this.RenderCache.HasCachedTextureForPath(this.TexturePath))
{
- return Cache.GetCachedTexture(this.TexturePath);
+ return this.RenderCache.GetCachedTexture(this.TexturePath);
}
- return Cache.CreateCachedTexture(this.Image, this.TexturePath);
+ return this.RenderCache.CreateCachedTexture(this.Image, this.TexturePath);
}
///
@@ -85,10 +89,9 @@ public override void Dispose()
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var otherImage = obj as RenderableBitmap;
- if (otherImage == null)
+ if (!(obj is RenderableBitmap otherImage))
{
return false;
}
diff --git a/Everlook/Viewport/Rendering/RenderableBoundingBox.cs b/Everlook/Viewport/Rendering/RenderableBoundingBox.cs
index ea82b37..5e61dad 100644
--- a/Everlook/Viewport/Rendering/RenderableBoundingBox.cs
+++ b/Everlook/Viewport/Rendering/RenderableBoundingBox.cs
@@ -22,15 +22,14 @@
using System;
using System.Linq;
+using System.Numerics;
using Everlook.Exceptions.Shader;
using Everlook.Utility;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Interfaces;
using Everlook.Viewport.Rendering.Shaders;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using Warcraft.Core.Structures;
namespace Everlook.Viewport.Rendering
@@ -38,7 +37,7 @@ namespace Everlook.Viewport.Rendering
///
/// Wraps a as a renderable in-world actor.
///
- public sealed class RenderableBoundingBox : IInstancedRenderable, IActor
+ public sealed class RenderableBoundingBox : GraphicsObject, IInstancedRenderable, IActor
{
private readonly BoundingBoxShader _boxShader;
@@ -57,14 +56,14 @@ public sealed class RenderableBoundingBox : IInstancedRenderable, IActor
///
/// Gets or sets the colour of the bounding box's lines.
///
- public Color4 LineColour { get; set; }
+ public Vector4 LineColour { get; set; }
///
/// Gets or sets a value indicating whether this object has been disposed.
///
private bool IsDisposed { get; set; }
- private Box _boundingBoxData;
+ private readonly Box _boundingBoxData;
private Buffer? _vertexBuffer;
private Buffer? _vertexIndexesBuffer;
@@ -72,15 +71,18 @@ public sealed class RenderableBoundingBox : IInstancedRenderable, IActor
/// Initializes a new instance of the class. The bounds data is taken from
/// the given , and the world translation is set to .
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The BoundingBox to get data from.
/// The world transform of the box.
- public RenderableBoundingBox(Box boundingBox, Transform transform)
+ public RenderableBoundingBox(GL gl, RenderCache renderCache, Box boundingBox, Transform transform)
+ : base(gl)
{
_boundingBoxData = boundingBox;
- this.LineColour = Color4.LimeGreen;
+ this.LineColour = new Vector4(0.0f, 1.0f, 0.0f, 1.0f);
this.ActorTransform = transform;
- _boxShader = (BoundingBoxShader)RenderCache.Instance.GetShader(EverlookShader.BoundingBox);
+ _boxShader = (BoundingBoxShader)renderCache.GetShader(EverlookShader.BoundingBox);
this.IsInitialized = false;
}
@@ -95,17 +97,28 @@ public void Initialize()
return;
}
- if (_boxShader == null)
+ if (_boxShader is null)
{
throw new ShaderNullException(typeof(BoundingBoxShader));
}
- _vertexBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw)
+ _vertexBuffer = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = _boundingBoxData.GetCorners().ToArray()
};
- _vertexBuffer.AttachAttributePointer(new VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 0, 0));
+ _vertexBuffer.AttachAttributePointer
+ (
+ new VertexAttributePointer
+ (
+ this.GL,
+ 0,
+ 3,
+ VertexAttribPointerType.Float,
+ 0,
+ 0
+ )
+ );
byte[] boundingBoxIndexValues =
{
@@ -126,7 +139,12 @@ public void Initialize()
5, 3
};
- _vertexIndexesBuffer = new Buffer(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw)
+ _vertexIndexesBuffer = new Buffer
+ (
+ this.GL,
+ BufferTargetARB.ElementArrayBuffer,
+ BufferUsageARB.StaticDraw
+ )
{
Data = boundingBoxIndexValues
};
@@ -135,7 +153,7 @@ public void Initialize()
}
///
- public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera, int count)
+ public void RenderInstances(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera, int count)
{
ThrowIfDisposed();
@@ -144,8 +162,8 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
return;
}
- GL.Disable(EnableCap.CullFace);
- GL.Disable(EnableCap.DepthTest);
+ this.GL.Disable(EnableCap.CullFace);
+ this.GL.Disable(EnableCap.DepthTest);
// Send the vertices to the shader
_vertexBuffer.Bind();
@@ -163,20 +181,23 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
_boxShader.SetProjectionMatrix(projectionMatrix);
// Now draw the box
- GL.DrawElementsInstanced
- (
- PrimitiveType.LineLoop,
- 24,
- DrawElementsType.UnsignedByte,
- new IntPtr(0),
- count
- );
+ unsafe
+ {
+ this.GL.DrawElementsInstanced
+ (
+ PrimitiveType.LineLoop,
+ 24,
+ DrawElementsType.UnsignedByte,
+ (void*)0,
+ (uint)count
+ );
+ }
_vertexBuffer.DisableAttributes();
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
ThrowIfDisposed();
@@ -185,8 +206,8 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
return;
}
- GL.Disable(EnableCap.CullFace);
- GL.Disable(EnableCap.DepthTest);
+ this.GL.Disable(EnableCap.CullFace);
+ this.GL.Disable(EnableCap.DepthTest);
// Send the vertices to the shader
_vertexBuffer.Bind();
@@ -201,13 +222,16 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
_boxShader.SetLineColour(this.LineColour);
// Now draw the box
- GL.DrawElements
- (
- PrimitiveType.LineLoop,
- 24,
- DrawElementsType.UnsignedByte,
- new IntPtr(0)
- );
+ unsafe
+ {
+ this.GL.DrawElements
+ (
+ PrimitiveType.LineLoop,
+ 24,
+ DrawElementsType.UnsignedByte,
+ (void*)0
+ );
+ }
_vertexBuffer.DisableAttributes();
}
@@ -220,7 +244,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(RenderableBoundingBox));
}
}
diff --git a/Everlook/Viewport/Rendering/RenderableGameModel.cs b/Everlook/Viewport/Rendering/RenderableGameModel.cs
index 5d6b0e5..3e1d4a0 100644
--- a/Everlook/Viewport/Rendering/RenderableGameModel.cs
+++ b/Everlook/Viewport/Rendering/RenderableGameModel.cs
@@ -24,6 +24,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Numerics;
using Everlook.Configuration;
using Everlook.Exceptions.Shader;
using Everlook.Utility;
@@ -31,9 +32,7 @@
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Interfaces;
using Everlook.Viewport.Rendering.Shaders;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using Warcraft.Core;
using Warcraft.Core.Extensions;
using Warcraft.Core.Shading.MDX;
@@ -51,6 +50,7 @@ namespace Everlook.Viewport.Rendering
/// Represents a renderable Game Object Model.
///
public sealed class RenderableGameModel :
+ GraphicsObject,
IInstancedRenderable,
ITickingActor,
IDefaultCameraPositionProvider,
@@ -73,16 +73,17 @@ public Vector3 DefaultCameraPosition
return Vector3.Zero;
}
- return
+ var vec4 = Vector4.Transform
(
- this.ActorTransform.GetModelMatrix() *
new Vector4
(
- _model.BoundingBox.GetCenterCoordinates().ToOpenGLVector(),
+ _model.BoundingBox.GetCenterCoordinates(),
1.0f
- )
- )
- .Xyz;
+ ),
+ this.ActorTransform.GetModelMatrix()
+ );
+
+ return new Vector3(vec4.X, vec4.Y, vec4.Z);
}
}
@@ -100,13 +101,13 @@ public Vector3 DefaultCameraPosition
public Transform ActorTransform { get; set; }
///
- public int PolygonCount => (int)_model.Skins.Sum(s => s.Triangles.Count / 3);
+ public int PolygonCount => (int)_model.Skins!.Sum(s => s.Triangles!.Count / 3);
///
- public int VertexCount => (int)_model.Vertices.Count;
+ public int VertexCount => (int)_model.Vertices!.Count;
private readonly string? _modelPath;
- private readonly RenderCache _cache = RenderCache.Instance;
+ private readonly RenderCache _renderCache;
private readonly WarcraftGameContext _gameContext;
///
@@ -142,11 +143,13 @@ public Vector3 DefaultCameraPosition
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The model to render.
/// The game context.
/// The full path of the model in the package group.
- public RenderableGameModel(MDX inModel, WarcraftGameContext gameContext, string modelPath)
- : this(inModel, gameContext)
+ public RenderableGameModel(GL gl, RenderCache renderCache, MDX inModel, WarcraftGameContext gameContext, string modelPath)
+ : this(gl, renderCache, inModel, gameContext)
{
_modelPath = modelPath;
}
@@ -154,10 +157,14 @@ public RenderableGameModel(MDX inModel, WarcraftGameContext gameContext, string
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The model to render.
/// The game context.
- public RenderableGameModel(MDX inModel, WarcraftGameContext gameContext)
+ public RenderableGameModel(GL gl, RenderCache renderCache, MDX inModel, WarcraftGameContext gameContext)
+ : base(gl)
{
+ _renderCache = renderCache;
_model = inModel;
_gameContext = gameContext;
@@ -165,7 +172,7 @@ public RenderableGameModel(MDX inModel, WarcraftGameContext gameContext)
// Set a default display info for this model
var displayInfo = GetSkinVariations().FirstOrDefault();
- if (displayInfo != null)
+ if (!(displayInfo is null))
{
this.CurrentDisplayInfo = displayInfo;
}
@@ -183,84 +190,112 @@ public void Initialize()
return;
}
- _shader = _cache.GetShader(EverlookShader.GameModel) as GameModelShader;
+ _shader = _renderCache.GetShader(EverlookShader.GameModel) as GameModelShader;
- if (_shader == null)
+ if (_shader is null)
{
throw new ShaderNullException(typeof(GameModelShader));
}
- _vertexBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw)
+ _vertexBuffer = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw)
{
- Data = _model.Vertices.Select(v => v.PackForOpenGL()).SelectMany(b => b).ToArray()
+ Data = _model.Vertices!.Select(v => v.PackForOpenGL()).SelectMany(b => b).ToArray()
};
var attributePointers = new[]
{
// Position
- new VertexAttributePointer(0, 3, VertexAttribPointerType.Float, MDXVertex.GetSize(), 0),
+ new VertexAttributePointer(this.GL, 0, 3, VertexAttribPointerType.Float, (uint)MDXVertex.GetSize(), 0),
+
// Bone weights
- new VertexAttributePointer(1, 4, VertexAttribPointerType.UnsignedByte, MDXVertex.GetSize(), 12),
+ new VertexAttributePointer
+ (
+ this.GL,
+ 1,
+ 4,
+ VertexAttribPointerType.UnsignedByte,
+ (uint)MDXVertex.GetSize(),
+ 12
+ ),
+
// Bone indexes
- new VertexAttributePointer(2, 4, VertexAttribPointerType.UnsignedByte, MDXVertex.GetSize(), 16),
+ new VertexAttributePointer
+ (
+ this.GL,
+ 2,
+ 4,
+ VertexAttribPointerType.UnsignedByte,
+ (uint)MDXVertex.GetSize(),
+ 16
+ ),
+
// Normal
- new VertexAttributePointer(3, 3, VertexAttribPointerType.Float, MDXVertex.GetSize(), 20),
+ new VertexAttributePointer(this.GL, 3, 3, VertexAttribPointerType.Float, (uint)MDXVertex.GetSize(), 20),
+
// UV1
- new VertexAttributePointer(4, 2, VertexAttribPointerType.Float, MDXVertex.GetSize(), 32),
+ new VertexAttributePointer(this.GL, 4, 2, VertexAttribPointerType.Float, (uint)MDXVertex.GetSize(), 32),
+
// UV2
- new VertexAttributePointer(5, 2, VertexAttribPointerType.Float, MDXVertex.GetSize(), 40)
+ new VertexAttributePointer(this.GL, 5, 2, VertexAttribPointerType.Float, (uint)MDXVertex.GetSize(), 40)
};
_vertexBuffer.AttachAttributePointers(attributePointers);
- _boundingBox = new RenderableBoundingBox(_model.BoundingBox, this.ActorTransform);
+ _boundingBox = new RenderableBoundingBox(this.GL, _renderCache, _model.BoundingBox, this.ActorTransform);
_boundingBox.Initialize();
- foreach (var texture in _model.Textures)
+ foreach (var texture in _model.Textures!)
{
if (!_textureLookup.ContainsKey(texture.Filename))
{
_textureLookup.Add
(
texture.Filename,
- _cache.GetTexture(texture, _gameContext)
+ _renderCache.GetTexture(texture, _gameContext)
);
}
}
- foreach (var skin in _model.Skins)
+ foreach (var skin in _model.Skins!)
{
- var absoluteTriangleVertexIndexes = skin.Triangles.Select
+ var absoluteTriangleVertexIndexes = skin.Triangles!.Select
(
- relativeIndex => skin.VertexIndices[relativeIndex]
+ relativeIndex => skin.VertexIndices![relativeIndex]
).ToArray();
- var skinIndexBuffer = new Buffer(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw)
+ var skinIndexBuffer = new Buffer
+ (
+ this.GL,
+ BufferTargetARB.ElementArrayBuffer,
+ BufferUsageARB.StaticDraw
+ )
{
Data = absoluteTriangleVertexIndexes
};
_skinIndexArrayBuffers.Add(skin, skinIndexBuffer);
- if (_model.Version <= WarcraftVersion.Wrath)
+ if (_model.Version > WarcraftVersion.Wrath)
{
- // In models earlier than Cata, we need to calculate the shader selector value at runtime.
- foreach (var renderBatch in skin.RenderBatches)
- {
- var shaderSelector = MDXShaderHelper.GetRuntimeShaderID
- (
- renderBatch.ShaderID,
- renderBatch,
- _model
- );
+ continue;
+ }
- renderBatch.ShaderID = shaderSelector;
- }
+ // In models earlier than Cata, we need to calculate the shader selector value at runtime.
+ foreach (var renderBatch in skin.RenderBatches!)
+ {
+ var shaderSelector = MDXShaderHelper.GetRuntimeShaderID
+ (
+ renderBatch.ShaderID,
+ renderBatch,
+ _model
+ );
+
+ renderBatch.ShaderID = shaderSelector;
}
}
// Cache the default display info
- if (this.CurrentDisplayInfo != null)
+ if (!(this.CurrentDisplayInfo is null))
{
CacheDisplayInfo(this.CurrentDisplayInfo);
}
@@ -275,7 +310,7 @@ public void Tick(float deltaTime)
}
///
- public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera, int count)
+ public void RenderInstances(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera, int count)
{
ThrowIfDisposed();
@@ -292,7 +327,7 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
_vertexBuffer.Bind();
_vertexBuffer.EnableAttributes();
- GL.Enable(EnableCap.DepthTest);
+ this.GL.Enable(EnableCap.DepthTest);
var modelViewMatrix = this.ActorTransform.GetModelMatrix() * viewMatrix;
var modelViewProjection = modelViewMatrix * projectionMatrix;
@@ -311,19 +346,19 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
_shader.Wireframe.SetViewportMatrix(camera.GetViewportMatrix());
// Override blend setting
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
- foreach (var skin in _model.Skins)
+ foreach (var skin in _model.Skins!)
{
_skinIndexArrayBuffers[skin].Bind();
if (this.ShouldRenderWireframe)
{
// Override blend setting
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
- foreach (var renderBatch in skin.RenderBatches)
+ foreach (var renderBatch in skin.RenderBatches!)
{
if (renderBatch.ShaderID == 0xFFFFu)
{
@@ -332,15 +367,19 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
PrepareBatchForRender(renderBatch);
- var skinSection = skin.Sections[renderBatch.SkinSectionIndex];
- GL.DrawElementsInstanced
- (
- PrimitiveType.Triangles,
- skinSection.TriangleCount,
- DrawElementsType.UnsignedShort,
- new IntPtr(skinSection.StartTriangleIndex * 2),
- count
- );
+ var skinSection = skin.Sections![renderBatch.SkinSectionIndex];
+
+ unsafe
+ {
+ this.GL.DrawElementsInstanced
+ (
+ PrimitiveType.Triangles,
+ skinSection.TriangleCount,
+ DrawElementsType.UnsignedShort,
+ (void*)(skinSection.StartTriangleIndex * 2),
+ (uint)count
+ );
+ }
}
}
@@ -355,7 +394,7 @@ public void RenderInstances(Matrix4 viewMatrix, Matrix4 projectionMatrix, Viewpo
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
ThrowIfDisposed();
@@ -372,7 +411,7 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
_vertexBuffer.Bind();
_vertexBuffer.EnableAttributes();
- GL.Enable(EnableCap.DepthTest);
+ this.GL.Enable(EnableCap.DepthTest);
var modelViewMatrix = this.ActorTransform.GetModelMatrix() * viewMatrix;
var modelViewProjection = modelViewMatrix * projectionMatrix;
@@ -391,19 +430,19 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
_shader.Wireframe.SetViewportMatrix(camera.GetViewportMatrix());
// Override blend setting
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
- foreach (var skin in _model.Skins)
+ foreach (var skin in _model.Skins!)
{
_skinIndexArrayBuffers[skin].Bind();
if (this.ShouldRenderWireframe)
{
// Override blend setting
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
- foreach (var renderBatch in skin.RenderBatches)
+ foreach (var renderBatch in skin.RenderBatches!)
{
if (renderBatch.ShaderID == 0xFFFFu)
{
@@ -412,14 +451,17 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
PrepareBatchForRender(renderBatch);
- var skinSection = skin.Sections[renderBatch.SkinSectionIndex];
- GL.DrawElements
- (
- PrimitiveType.Triangles,
- skinSection.TriangleCount,
- DrawElementsType.UnsignedShort,
- new IntPtr(skinSection.StartTriangleIndex * 2)
- );
+ var skinSection = skin.Sections![renderBatch.SkinSectionIndex];
+ unsafe
+ {
+ this.GL.DrawElements
+ (
+ PrimitiveType.Triangles,
+ skinSection.TriangleCount,
+ DrawElementsType.UnsignedShort,
+ (void*)(skinSection.StartTriangleIndex * 2)
+ );
+ }
}
}
@@ -430,7 +472,7 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
}
// Release the attribute arrays
- _vertexBuffer.DisableAttributes();
+ _vertexBuffer?.DisableAttributes();
}
///
@@ -442,7 +484,7 @@ private void PrepareBatchForRender(MDXRenderBatch renderBatch)
{
var fragmentShader = MDXShaderHelper.GetFragmentShaderType(renderBatch.TextureCount, renderBatch.ShaderID);
var vertexShader = MDXShaderHelper.GetVertexShaderType(renderBatch.TextureCount, renderBatch.ShaderID);
- var batchMaterial = _model.Materials[renderBatch.MaterialIndex];
+ var batchMaterial = _model.Materials![renderBatch.MaterialIndex];
if (_shader is null)
{
@@ -453,10 +495,10 @@ private void PrepareBatchForRender(MDXRenderBatch renderBatch)
_shader.SetFragmentShaderType(fragmentShader);
_shader.SetMaterial(batchMaterial);
- var baseColour = Color4.White;
+ var baseColour = Vector4.One;
if (renderBatch.ColorIndex >= 0)
{
- var colorAnimation = _model.ColourAnimations[renderBatch.ColorIndex];
+ var colorAnimation = _model.ColourAnimations![renderBatch.ColorIndex];
// TODO: Sample based on animated values
RGB rgb;
@@ -464,47 +506,47 @@ private void PrepareBatchForRender(MDXRenderBatch renderBatch)
if (colorAnimation.ColourTrack.IsComposite)
{
- rgb = colorAnimation.ColourTrack.CompositeTimelineValues.First();
- alpha = colorAnimation.OpacityTrack.CompositeTimelineValues.First() / 0x7fff;
+ rgb = colorAnimation.ColourTrack.CompositeTimelineValues!.First();
+ alpha = (float)colorAnimation.OpacityTrack.CompositeTimelineValues!.First() / 0x7fff;
}
else
{
- rgb = colorAnimation.ColourTrack.Values.First().First();
- alpha = colorAnimation.OpacityTrack.Values.First().First() / 0x7fff;
+ rgb = colorAnimation.ColourTrack.Values!.First().First();
+ alpha = (float)colorAnimation.OpacityTrack.Values!.First().First() / 0x7fff;
}
- baseColour = new Color4
+ baseColour = new Vector4
(
- MathHelper.Clamp(rgb.R, 0.0f, 1.0f),
- MathHelper.Clamp(rgb.G, 0.0f, 1.0f),
- MathHelper.Clamp(rgb.B, 0.0f, 1.0f),
- MathHelper.Clamp(alpha, 0.0f, 1.0f)
+ Math.Clamp(rgb.R, 0.0f, 1.0f),
+ Math.Clamp(rgb.G, 0.0f, 1.0f),
+ Math.Clamp(rgb.B, 0.0f, 1.0f),
+ Math.Clamp(alpha, 0.0f, 1.0f)
);
}
if ((short)renderBatch.TransparencyLookupTableIndex >= 0)
{
- var transparencyAnimationIndex = _model.TransparencyLookupTable[renderBatch.TransparencyLookupTableIndex];
- var transparencyAnimation = _model.TransparencyAnimations[transparencyAnimationIndex];
+ var transparencyAnimationIndex = _model.TransparencyLookupTable![renderBatch.TransparencyLookupTableIndex];
+ var transparencyAnimation = _model.TransparencyAnimations![transparencyAnimationIndex];
float alphaWeight;
if (transparencyAnimation.Weight.IsComposite)
{
- alphaWeight = transparencyAnimation.Weight.CompositeTimelineValues.First() / 0x7fff;
+ alphaWeight = (float)transparencyAnimation.Weight.CompositeTimelineValues!.First() / 0x7fff;
}
else
{
- alphaWeight = transparencyAnimation.Weight.Values.First().First() / 0x7fff;
+ alphaWeight = (float)transparencyAnimation.Weight.Values!.First().First() / 0x7fff;
}
- baseColour.A *= alphaWeight;
+ baseColour.W *= alphaWeight;
}
_shader.SetBaseInputColour(baseColour);
- var textureIndexes = _model.TextureLookupTable.Skip(renderBatch.TextureLookupTableIndex)
+ var textureIndexes = _model.TextureLookupTable!.Skip(renderBatch.TextureLookupTableIndex)
.Take(renderBatch.TextureCount);
- var textures = _model.Textures.Where((t, i) => textureIndexes.Contains((short)i)).ToList();
+ var textures = _model.Textures!.Where((t, i) => textureIndexes.Contains((short)i)).ToList();
for (var i = 0; i < textures.Count; ++i)
{
@@ -584,7 +626,7 @@ public IEnumerable GetSkinVariations()
r =>
string.Equals
(
- Path.ChangeExtension(r.ModelPath.Value, "mdx"),
+ Path.ChangeExtension(r!.ModelPath.Value, "mdx"),
Path.ChangeExtension(_modelPath, "mdx"),
StringComparison.InvariantCultureIgnoreCase
)
@@ -596,13 +638,13 @@ public IEnumerable GetSkinVariations()
}
// Then flatten out their IDs
- var modelDataRecordIDs = modelDataRecords.Select(r => r.ID).ToList();
+ var modelDataRecordIDs = modelDataRecords.Select(r => r!.ID).ToList();
// Then get any display info record which references this model
var displayInfoDatabase = _gameContext.Database.GetDatabase();
var modelDisplayRecords = displayInfoDatabase.Where
(
- r => modelDataRecordIDs.Contains(r.Model.Key)
+ r => modelDataRecordIDs.Contains(r!.Model.Key)
).ToList();
if (!modelDisplayRecords.Any())
@@ -618,6 +660,11 @@ public IEnumerable GetSkinVariations()
// Finally, return any record with a unique set of textures
foreach (var displayRecord in modelDisplayRecords)
{
+ if (displayRecord is null)
+ {
+ continue;
+ }
+
if (textureListMapping.ContainsKey(displayRecord.TextureVariations))
{
continue;
@@ -658,7 +705,7 @@ public void SetDisplayInfoByID(int variationID)
{
this.CurrentDisplayInfo = _gameContext.Database.GetDatabase()
.GetRecordByID(variationID);
- CacheDisplayInfo(this.CurrentDisplayInfo);
+ CacheDisplayInfo(this.CurrentDisplayInfo!);
}
///
@@ -667,17 +714,12 @@ public void SetDisplayInfoByID(int variationID)
/// The display info record to cache.
private void CacheDisplayInfo(CreatureDisplayInfoRecord displayInfoRecord)
{
- if (displayInfoRecord == null)
- {
- throw new ArgumentNullException(nameof(displayInfoRecord));
- }
-
if (_modelPath is null)
{
throw new InvalidOperationException();
}
- foreach (var texture in _model.Textures)
+ foreach (var texture in _model.Textures!)
{
int textureIndex;
switch (texture.TextureType)
@@ -715,7 +757,7 @@ private void CacheDisplayInfo(CreatureDisplayInfoRecord displayInfoRecord)
_textureLookup.Add
(
texturePath,
- _cache.GetTexture(texture, _gameContext, texturePath)
+ _renderCache.GetTexture(texture, _gameContext, texturePath)
);
}
}
@@ -728,7 +770,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(RenderableGameModel));
}
}
@@ -746,10 +788,9 @@ public void Dispose()
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var otherModel = obj as RenderableGameModel;
- if (otherModel == null)
+ if (!(obj is RenderableGameModel otherModel))
{
return false;
}
diff --git a/Everlook/Viewport/Rendering/RenderableImage.cs b/Everlook/Viewport/Rendering/RenderableImage.cs
index 235a0bb..6bfd8af 100644
--- a/Everlook/Viewport/Rendering/RenderableImage.cs
+++ b/Everlook/Viewport/Rendering/RenderableImage.cs
@@ -22,12 +22,13 @@
using System;
using System.Collections.Generic;
+using System.Numerics;
using Everlook.Viewport.Camera;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Interfaces;
using Everlook.Viewport.Rendering.Shaders;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
+using JetBrains.Annotations;
+using Silk.NET.OpenGL;
using Warcraft.Core.Extensions;
using Warcraft.Core.Structures;
@@ -36,12 +37,12 @@ namespace Everlook.Viewport.Rendering
///
/// Represents a renderable 2D image, and contains common functionality required to render one.
///
- public abstract class RenderableImage : IRenderable, IActor, IDefaultCameraPositionProvider
+ public abstract class RenderableImage : GraphicsObject, IRenderable, IActor, IDefaultCameraPositionProvider
{
///
/// Gets a reference to the global shader cache.
///
- protected static RenderCache Cache => RenderCache.Instance;
+ protected RenderCache RenderCache { get; }
///
/// Gets or sets a value indicating whether this object has been disposed.
@@ -132,6 +133,17 @@ public abstract class RenderableImage : IRenderable, IActor, IDefaultCameraPosit
///
public uint MipCount => GetNumReasonableMipLevels();
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL API.
+ /// The rendering cache.
+ protected RenderableImage([NotNull] GL gl, RenderCache renderCache)
+ : base(gl)
+ {
+ this.RenderCache = renderCache;
+ }
+
///
/// TODO: Put this in Warcraft.Core instead.
///
@@ -172,13 +184,13 @@ public void Initialize()
this.Texture = LoadTexture();
// Use cached shaders whenever possible
- this.Shader = Cache.GetShader(EverlookShader.Plain2D) as Plain2DShader;
+ this.Shader = this.RenderCache.GetShader(EverlookShader.Plain2D) as Plain2DShader;
this.ActorTransform = new Transform();
- GL.Enable(EnableCap.Blend);
- GL.BlendEquation(BlendEquationMode.FuncAdd);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ this.GL.Enable(EnableCap.Blend);
+ this.GL.BlendEquation(BlendEquationModeEXT.FuncAdd);
+ this.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
this.IsInitialized = true;
}
@@ -191,7 +203,7 @@ public void Initialize()
protected abstract Texture2D LoadTexture();
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
ThrowIfDisposed();
@@ -216,26 +228,37 @@ this.Texture is null
// Render the object
// Send the vertices to the shader
- GL.EnableVertexAttribArray(0);
+ this.GL.EnableVertexAttribArray(0);
this.VertexBuffer.Bind();
- GL.VertexAttribPointer(
- 0,
- 2,
- VertexAttribPointerType.Float,
- false,
- 0,
- 0);
+
+ unsafe
+ {
+ this.GL.VertexAttribPointer
+ (
+ 0u,
+ 2,
+ VertexAttribPointerType.Float,
+ false,
+ 0u,
+ (void*)0
+ );
+ }
// Send the UV coordinates to the shader
- GL.EnableVertexAttribArray(1);
+ this.GL.EnableVertexAttribArray(1);
this.UVBuffer.Bind();
- GL.VertexAttribPointer(
- 1,
- 2,
- VertexAttribPointerType.Float,
- false,
- 0,
- 0);
+ unsafe
+ {
+ this.GL.VertexAttribPointer
+ (
+ 1u,
+ 2,
+ VertexAttribPointerType.Float,
+ false,
+ 0u,
+ (void*)0
+ );
+ }
// Set the channel mask
this.Shader.SetChannelMask(this.ChannelMask);
@@ -243,7 +266,7 @@ this.Texture is null
// Set the texture ID as a uniform sampler in unit 0
this.Shader.SetTexture(this.Texture);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ this.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
// Set the model view matrix
var modelViewProjection = this.ActorTransform.GetModelMatrix() * viewMatrix * projectionMatrix;
@@ -253,11 +276,14 @@ this.Texture is null
// Finally, draw the image
this.VertexIndexBuffer.Bind();
- GL.DrawElements(BeginMode.Triangles, 6, DrawElementsType.UnsignedShort, 0);
+ unsafe
+ {
+ this.GL.DrawElements(PrimitiveType.Triangles, 6u, DrawElementsType.UnsignedShort, (void*)0);
+ }
// Release the attribute arrays
- GL.DisableVertexAttribArray(0);
- GL.DisableVertexAttribArray(1);
+ this.GL.DisableVertexAttribArray(0);
+ this.GL.DisableVertexAttribArray(1);
}
///
@@ -285,7 +311,7 @@ protected Buffer GenerateVertices()
};
// Buffer the generated vertices in the GPU
- return new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw)
+ return new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = vertexPositions.ToArray()
};
@@ -295,12 +321,12 @@ protected Buffer GenerateVertices()
/// Generates a vertex index buffer for the four corner vertices.
///
/// The vertex index buffer.
- protected static Buffer GenerateVertexIndexes()
+ protected Buffer GenerateVertexIndexes()
{
// Generate vertex indexes
var vertexIndexes = new List { 1, 0, 2, 2, 3, 1 };
- return new Buffer(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw)
+ return new Buffer(this.GL, BufferTargetARB.ElementArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = vertexIndexes.ToArray()
};
@@ -310,7 +336,7 @@ protected static Buffer GenerateVertexIndexes()
/// Generates a UV coordinate buffer for the four corner vertices.
///
/// The native OpenGL ID of the buffer.
- protected static Buffer GenerateTextureCoordinates()
+ protected Buffer GenerateTextureCoordinates()
{
// Generate UV coordinates
var textureCoordinates = new List
@@ -322,7 +348,7 @@ protected static Buffer GenerateTextureCoordinates()
};
// Buffer the generated UV coordinates in the GPU
- return new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw)
+ return new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw)
{
Data = textureCoordinates.ToArray()
};
@@ -336,7 +362,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(RenderableImage));
}
}
diff --git a/Everlook/Viewport/Rendering/RenderableWorldModel.cs b/Everlook/Viewport/Rendering/RenderableWorldModel.cs
index ff1edb6..b098f98 100644
--- a/Everlook/Viewport/Rendering/RenderableWorldModel.cs
+++ b/Everlook/Viewport/Rendering/RenderableWorldModel.cs
@@ -23,6 +23,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Numerics;
using Everlook.Configuration;
using Everlook.Exceptions.Shader;
using Everlook.Utility;
@@ -31,20 +32,10 @@
using Everlook.Viewport.Rendering.Interfaces;
using Everlook.Viewport.Rendering.Shaders;
using log4net;
-using OpenTK;
+using Silk.NET.OpenGL;
using Warcraft.WMO;
using Warcraft.WMO.GroupFile;
-using Warcraft.WMO.GroupFile.Chunks;
using Warcraft.WMO.RootFile.Chunks;
-using BufferTarget = OpenTK.Graphics.OpenGL.BufferTarget;
-using BufferUsageHint = OpenTK.Graphics.OpenGL.BufferUsageHint;
-using DrawElementsType = OpenTK.Graphics.OpenGL.DrawElementsType;
-using EnableCap = OpenTK.Graphics.OpenGL.EnableCap;
-using GL = OpenTK.Graphics.OpenGL.GL;
-using PrimitiveType = OpenTK.Graphics.OpenGL.PrimitiveType;
-using TextureUnit = OpenTK.Graphics.OpenGL.TextureUnit;
-using TextureWrapMode = OpenTK.Graphics.OpenGL.TextureWrapMode;
-using VertexAttribPointerType = OpenTK.Graphics.OpenGL.VertexAttribPointerType;
namespace Everlook.Viewport.Rendering
{
@@ -52,6 +43,7 @@ namespace Everlook.Viewport.Rendering
/// Represents a renderable World Model Object.
///
public sealed class RenderableWorldModel :
+ GraphicsObject,
IRenderable,
ITickingActor,
IDefaultCameraPositionProvider,
@@ -62,6 +54,11 @@ public sealed class RenderableWorldModel :
///
private static readonly ILog Log = LogManager.GetLogger(typeof(RenderableWorldModel));
+ ///
+ /// Holds the render cache.
+ ///
+ private readonly RenderCache _renderCache;
+
///
/// Gets or sets a value indicating whether this object has been disposed.
///
@@ -88,20 +85,20 @@ public Vector3 DefaultCameraPosition
return Vector3.Zero;
}
- return
+ var vec4 = Vector4.Transform
(
- this.ActorTransform.GetModelMatrix() *
new Vector4
(
_model.Groups
- .First()
- .GetBoundingBox()
- .GetCenterCoordinates()
- .ToOpenGLVector(),
+ .First()
+ .GetBoundingBox()
+ .GetCenterCoordinates(),
1.0f
- )
- )
- .Xyz;
+ ),
+ this.ActorTransform.GetModelMatrix()
+ );
+
+ return new Vector3(vec4.X, vec4.Y, vec4.Z);
}
}
@@ -114,7 +111,6 @@ public Vector3 DefaultCameraPosition
///
public Transform ActorTransform { get; set; }
- private readonly RenderCache _cache = RenderCache.Instance;
private readonly WarcraftGameContext _gameContext;
///
@@ -147,10 +143,10 @@ public Vector3 DefaultCameraPosition
new Dictionary>>();
///
- public int PolygonCount => _model.Groups.Sum(g => g.GroupData.VertexIndices.VertexIndices.Count / 3);
+ public int PolygonCount => _model.Groups.Sum(g => g.GroupData.VertexIndices!.VertexIndices.Count / 3);
///
- public int VertexCount => _model.Groups.Sum(g => g.GroupData.Vertices.Vertices.Count);
+ public int VertexCount => _model.Groups.Sum(g => g.GroupData.Vertices!.Vertices.Count);
///
public bool IsInitialized { get; set; }
@@ -180,10 +176,14 @@ public Vector3 DefaultCameraPosition
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The model to render.
/// The game context.
- public RenderableWorldModel(WMO inModel, WarcraftGameContext gameContext)
+ public RenderableWorldModel(GL gl, RenderCache renderCache, WMO inModel, WarcraftGameContext gameContext)
+ : base(gl)
{
+ _renderCache = renderCache;
_model = inModel;
_gameContext = gameContext;
@@ -204,9 +204,9 @@ public void Initialize()
this.IsInitialized = true;
- _shader = _cache.GetShader(EverlookShader.WorldModel) as WorldModelShader;
+ _shader = _renderCache.GetShader(EverlookShader.WorldModel) as WorldModelShader;
- if (_shader == null)
+ if (_shader is null)
{
throw new ShaderNullException(typeof(WorldModelShader));
}
@@ -218,12 +218,14 @@ public void Initialize()
// Load the textures used in this model
foreach (var texture in _model.GetTextures())
{
- if (!string.IsNullOrEmpty(texture))
+ if (string.IsNullOrEmpty(texture))
{
- if (!_textureLookup.ContainsKey(texture))
- {
- _textureLookup.Add(texture, _cache.GetTexture(texture, _gameContext.Assets));
- }
+ continue;
+ }
+
+ if (!_textureLookup.ContainsKey(texture))
+ {
+ _textureLookup.Add(texture, _renderCache.GetTexture(texture, _gameContext.Assets));
}
}
@@ -295,14 +297,21 @@ public void LoadDoodads()
var doodadReference = _gameContext.GetReferenceForDoodad(firstInstance);
var doodadModel = DataLoadingRoutines.LoadGameModel(doodadReference);
- if (doodadModel == null)
+ if (doodadModel is null)
{
Log.Warn($"Failed to load doodad \"{firstInstance.Name}\"");
continue;
}
// Then create a new renderable game model
- var renderableDoodad = new RenderableGameModel(doodadModel, _gameContext, firstInstance.Name);
+ var renderableDoodad = new RenderableGameModel
+ (
+ this.GL,
+ _renderCache,
+ doodadModel,
+ _gameContext,
+ firstInstance.Name
+ );
// And cache it
_doodadCache.Add(firstInstance.Name, renderableDoodad);
@@ -315,20 +324,24 @@ public void LoadDoodads()
(
new Transform
(
- doodadInstance.Position.ToOpenGLVector(),
- doodadInstance.Orientation.ToOpenGLQuaternion(),
+ doodadInstance.Position,
+ doodadInstance.Orientation,
new Vector3(doodadInstance.Scale)
)
);
}
- var instanceSet = new ActorInstanceSet(_doodadCache[firstInstance.Name]);
+ var instanceSet = new ActorInstanceSet
+ (
+ this.GL, _doodadCache[firstInstance.Name]
+ );
+
instanceSet.SetInstances(instanceTransforms);
doodadSetInstanceGroups.Add(instanceSet);
}
- _doodadSets.Add(doodadSet.Name, doodadSetInstanceGroups);
+ _doodadSets.Add(doodadSet.Name!, doodadSetInstanceGroups);
}
}
@@ -342,30 +355,39 @@ private void InitializeModelGroup(ModelGroup modelGroup)
Buffers
*/
- var vertexBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw);
- var normalBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw);
- var coordinateBuffer = new Buffer(BufferTarget.ArrayBuffer, BufferUsageHint.StaticDraw);
- var vertexIndexes = new Buffer(BufferTarget.ElementArrayBuffer, BufferUsageHint.StaticDraw);
+ var vertexBuffer = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw);
+ var normalBuffer = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw);
+ var coordinateBuffer = new Buffer(this.GL, BufferTargetARB.ArrayBuffer, BufferUsageARB.StaticDraw);
+ var vertexIndexes = new Buffer
+ (
+ this.GL, BufferTargetARB.ElementArrayBuffer, BufferUsageARB.StaticDraw
+ );
// Upload all of the vertices in this group
- vertexBuffer.Data = modelGroup.GetVertices().Select(v => v.ToOpenGLVector()).ToArray();
+ vertexBuffer.Data = modelGroup.GetVertices().Select(v => v).ToArray();
_vertexBufferLookup.Add(modelGroup, vertexBuffer);
- vertexBuffer.AttachAttributePointer(new VertexAttributePointer(0, 3, VertexAttribPointerType.Float, 0, 0));
+ vertexBuffer.AttachAttributePointer
+ (
+ new VertexAttributePointer(this.GL, 0, 3, VertexAttribPointerType.Float, 0, 0)
+ );
// Upload all of the normals in this group
- normalBuffer.Data = modelGroup.GetNormals().Select(v => v.ToOpenGLVector()).ToArray();
+ normalBuffer.Data = modelGroup.GetNormals().Select(v => v).ToArray();
_normalBufferLookup.Add(modelGroup, normalBuffer);
- normalBuffer.AttachAttributePointer(new VertexAttributePointer(1, 3, VertexAttribPointerType.Float, 0, 0));
+ normalBuffer.AttachAttributePointer
+ (
+ new VertexAttributePointer(this.GL, 1, 3, VertexAttribPointerType.Float, 0, 0)
+ );
// Upload all of the UVs in this group
- coordinateBuffer.Data = modelGroup.GetTextureCoordinates().Select(v => v.ToOpenGLVector()).ToArray();
+ coordinateBuffer.Data = modelGroup.GetTextureCoordinates().Select(v => v).ToArray();
_textureCoordinateBufferLookup.Add(modelGroup, coordinateBuffer);
coordinateBuffer.AttachAttributePointer
(
- new VertexAttributePointer(2, 2, VertexAttribPointerType.Float, 0, 0)
+ new VertexAttributePointer(this.GL, 2, 2, VertexAttribPointerType.Float, 0, 0)
);
// Upload vertex indices for this group
@@ -374,6 +396,8 @@ private void InitializeModelGroup(ModelGroup modelGroup)
var boundingBox = new RenderableBoundingBox
(
+ this.GL,
+ _renderCache,
modelGroup.GetBoundingBox(),
this.ActorTransform
);
@@ -398,7 +422,7 @@ public void Tick(float deltaTime)
}
///
- public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera camera)
+ public void Render(Matrix4x4 viewMatrix, Matrix4x4 projectionMatrix, ViewportCamera camera)
{
ThrowIfDisposed();
@@ -440,17 +464,19 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
}
}
- if (this.ShouldRenderDoodads)
+ if (!this.ShouldRenderDoodads)
{
- foreach (var doodadInstanceSet in _doodadSets[this.DoodadSet])
- {
- //doodadInstanceSet.ShouldRenderBounds = this.ShouldRenderBounds;
- }
+ return;
+ }
- foreach (var doodadInstanceSet in _doodadSets[this.DoodadSet])
- {
- doodadInstanceSet.Render(viewMatrix, projectionMatrix, camera);
- }
+ foreach (var doodadInstanceSet in _doodadSets[this.DoodadSet!])
+ {
+ doodadInstanceSet.ShouldRenderBounds = this.ShouldRenderBounds;
+ }
+
+ foreach (var doodadInstanceSet in _doodadSets[this.DoodadSet])
+ {
+ doodadInstanceSet.Render(viewMatrix, projectionMatrix, camera);
}
// TODO: Summarize the render batches from each group that has the same material ID
@@ -467,7 +493,7 @@ public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, ViewportCamera
///
/// Renders the specified model group on a batch basis.
///
- private void RenderGroup(ModelGroup modelGroup, Matrix4 modelViewProjection)
+ private void RenderGroup(ModelGroup modelGroup, Matrix4x4 modelViewProjection)
{
if (_shader is null || this.DoodadSet is null)
{
@@ -475,7 +501,7 @@ private void RenderGroup(ModelGroup modelGroup, Matrix4 modelViewProjection)
}
// Reenable depth test
- GL.Enable(EnableCap.DepthTest);
+ this.GL.Enable(EnableCap.DepthTest);
// Render the object
// Send the vertices to the shader
@@ -496,7 +522,7 @@ private void RenderGroup(ModelGroup modelGroup, Matrix4 modelViewProjection)
_shader.Wireframe.SetWireframeColour(EverlookConfiguration.Instance.WireframeColour);
// Override blend setting
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
// Render all the different materials (opaque first, transparent after)
@@ -512,28 +538,26 @@ private void RenderGroup(ModelGroup modelGroup, Matrix4 modelViewProjection)
_shader.SetMVPMatrix(modelViewProjection);
// Set the texture as the first diffuse texture in unit 0
- var texture = _cache.GetCachedTexture(modelMaterial.DiffuseTexture);
- if (modelMaterial.Flags.HasFlag(MaterialFlags.TextureWrappingClampS))
- {
- texture.WrappingMode = TextureWrapMode.Clamp;
- }
- else
- {
- texture.WrappingMode = TextureWrapMode.Repeat;
- }
+ var texture = _renderCache.GetCachedTexture(modelMaterial.DiffuseTexture!);
+ texture.WrappingMode = modelMaterial.Flags.HasFlag(MaterialFlags.TextureWrappingClampS)
+ ? TextureWrapMode.ClampToBorder
+ : TextureWrapMode.Repeat;
_shader.BindTexture2D(TextureUnit.Texture0, TextureUniform.Texture0, texture);
// Finally, draw the model
- GL.DrawRangeElements
- (
- PrimitiveType.Triangles,
- renderBatch.FirstPolygonIndex,
- renderBatch.FirstPolygonIndex + renderBatch.PolygonIndexCount - 1,
- renderBatch.PolygonIndexCount,
- DrawElementsType.UnsignedShort,
- new IntPtr(renderBatch.FirstPolygonIndex * 2)
- );
+ unsafe
+ {
+ this.GL.DrawRangeElements
+ (
+ PrimitiveType.Triangles,
+ renderBatch.FirstPolygonIndex,
+ renderBatch.FirstPolygonIndex + renderBatch.PolygonIndexCount - 1,
+ renderBatch.PolygonIndexCount,
+ DrawElementsType.UnsignedShort,
+ (void*)(renderBatch.FirstPolygonIndex * 2)
+ );
+ }
}
// Release the attribute arrays
@@ -548,7 +572,7 @@ private void RenderGroup(ModelGroup modelGroup, Matrix4 modelViewProjection)
/// The names of the doodad sets.
public IEnumerable GetDoodadSetNames()
{
- return _model.RootInformation.DoodadSets.DoodadSets.Select(ds => ds.Name);
+ return _model.RootInformation.DoodadSets.DoodadSets.Select(ds => ds.Name!);
}
///
@@ -559,7 +583,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(RenderableWorldModel));
}
}
@@ -595,10 +619,9 @@ public void Dispose()
}
///
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- var otherModel = obj as RenderableWorldModel;
- if (otherModel == null)
+ if (!(obj is RenderableWorldModel otherModel))
{
return false;
}
diff --git a/Everlook/Viewport/Rendering/Shaders/BaseGridShader.cs b/Everlook/Viewport/Rendering/Shaders/BaseGridShader.cs
index 164d6a8..5c9243b 100644
--- a/Everlook/Viewport/Rendering/Shaders/BaseGridShader.cs
+++ b/Everlook/Viewport/Rendering/Shaders/BaseGridShader.cs
@@ -20,8 +20,10 @@
// along with this program. If not, see .
//
+using System.Numerics;
using Everlook.Viewport.Rendering.Core;
-using OpenTK.Graphics;
+using JetBrains.Annotations;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders
{
@@ -41,13 +43,22 @@ public class BaseGridShader : ShaderProgram
private const string ColourIdentifier = "lineColour";
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL API.
+ public BaseGridShader([NotNull] GL gl)
+ : base(gl)
+ {
+ }
+
///
/// Sets the line colour of the bounding box.
///
/// The colour to set the lines to.
- public void SetLineColour(Color4 colour)
+ public void SetLineColour(Vector4 colour)
{
- SetColor4(colour, ColourIdentifier);
+ SetVector4(colour, ColourIdentifier);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Shaders/BoundingBoxShader.cs b/Everlook/Viewport/Rendering/Shaders/BoundingBoxShader.cs
index f633555..833f90f 100644
--- a/Everlook/Viewport/Rendering/Shaders/BoundingBoxShader.cs
+++ b/Everlook/Viewport/Rendering/Shaders/BoundingBoxShader.cs
@@ -20,9 +20,10 @@
// along with this program. If not, see .
//
+using System.Numerics;
using Everlook.Viewport.Rendering.Core;
-using OpenTK;
-using OpenTK.Graphics;
+using JetBrains.Annotations;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders
{
@@ -47,6 +48,15 @@ public class BoundingBoxShader : ShaderProgram
///
protected override string? GeometryShaderResourceName => null;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL API.
+ public BoundingBoxShader([NotNull] GL gl)
+ : base(gl)
+ {
+ }
+
///
/// Sets the instancing flag.
///
@@ -60,7 +70,7 @@ public void SetIsInstance(bool isInstanced)
/// Sets the current view matrix of the shader.
///
/// The model-view matrix.
- public void SetViewMatrix(Matrix4 viewMatrix)
+ public void SetViewMatrix(Matrix4x4 viewMatrix)
{
SetMatrix(viewMatrix, ViewMatrix);
}
@@ -69,7 +79,7 @@ public void SetViewMatrix(Matrix4 viewMatrix)
/// Sets the current projection matrix of the shader.
///
/// The projection matrix.
- public void SetProjectionMatrix(Matrix4 projectionMatrix)
+ public void SetProjectionMatrix(Matrix4x4 projectionMatrix)
{
SetMatrix(projectionMatrix, ProjectionMatrix);
}
@@ -78,9 +88,9 @@ public void SetProjectionMatrix(Matrix4 projectionMatrix)
/// Sets the line colour of the bounding box.
///
/// The colour to set the lines to.
- public void SetLineColour(Color4 colour)
+ public void SetLineColour(Vector4 colour)
{
- SetColor4(colour, ColourIdentifier);
+ SetVector4(colour, ColourIdentifier);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Shaders/Components/AmbientLighting.cs b/Everlook/Viewport/Rendering/Shaders/Components/AmbientLighting.cs
index 5df393d..e694517 100644
--- a/Everlook/Viewport/Rendering/Shaders/Components/AmbientLighting.cs
+++ b/Everlook/Viewport/Rendering/Shaders/Components/AmbientLighting.cs
@@ -20,27 +20,30 @@
// along with this program. If not, see .
//
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using System.Numerics;
+using Everlook.Viewport.Rendering.Core;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders.Components
{
///
/// An ambient lighting shader component.
///
- public class AmbientLighting
+ public class AmbientLighting : GraphicsObject
{
private const string AmbientColourIdentifier = "AmbientColour";
private const string AmbientIntensityIdentifier = "AmbientIntensity";
- private readonly int _parentShaderNativeID;
+ private readonly uint _parentShaderNativeID;
///
/// Initializes a new instance of the class, and attaches it to the given parent
/// shader.
///
+ /// The OpenGL API.
/// The native ID of the parent shader.
- public AmbientLighting(int parentShaderID)
+ public AmbientLighting(GL gl, uint parentShaderID)
+ : base(gl)
{
_parentShaderNativeID = parentShaderID;
}
@@ -49,10 +52,10 @@ public AmbientLighting(int parentShaderID)
/// Sets the colour of the ambient light shader.
///
/// The colour of the light.
- public void SetAmbientColour(Color4 lightColour)
+ public void SetAmbientColour(Vector4 lightColour)
{
- var colourLoc = GL.GetUniformLocation(_parentShaderNativeID, AmbientColourIdentifier);
- GL.Uniform4(colourLoc, lightColour);
+ var colourLoc = this.GL.GetUniformLocation(_parentShaderNativeID, AmbientColourIdentifier);
+ this.GL.Uniform4(colourLoc, lightColour);
}
///
@@ -61,8 +64,8 @@ public void SetAmbientColour(Color4 lightColour)
/// The intensity, in lux.
public void SetAmbientIntensity(float lightIntensity)
{
- var intensityLoc = GL.GetUniformLocation(_parentShaderNativeID, AmbientIntensityIdentifier);
- GL.Uniform1(intensityLoc, lightIntensity);
+ var intensityLoc = this.GL.GetUniformLocation(_parentShaderNativeID, AmbientIntensityIdentifier);
+ this.GL.Uniform1(intensityLoc, lightIntensity);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Shaders/Components/GlobalLighting.cs b/Everlook/Viewport/Rendering/Shaders/Components/GlobalLighting.cs
index 81026ad..46ad5f5 100644
--- a/Everlook/Viewport/Rendering/Shaders/Components/GlobalLighting.cs
+++ b/Everlook/Viewport/Rendering/Shaders/Components/GlobalLighting.cs
@@ -20,48 +20,50 @@
// along with this program. If not, see .
//
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using System.Numerics;
+using Everlook.Viewport.Rendering.Core;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders.Components
{
///
/// A global light shader component.
///
- public class GlobalLighting
+ public class GlobalLighting : GraphicsObject
{
private const string LightVectorIdentifier = "LightVector";
private const string LightColourIdentifier = "LightColour";
private const string LightIntensityIdentifier = "LightIntensity";
- private readonly int _parentShaderNativeID;
+ private readonly uint _parentShaderNativeID;
///
/// Initializes a new instance of the class, and attaches it to the given parent
/// shader.
///
+ /// The OpenGL API.
/// The native ID of the parent shader.
- public GlobalLighting(int parentShaderID)
+ public GlobalLighting(GL gl, uint parentShaderID)
+ : base(gl)
{
_parentShaderNativeID = parentShaderID;
}
private void EnableParent()
{
- GL.UseProgram(_parentShaderNativeID);
+ this.GL.UseProgram(_parentShaderNativeID);
}
///
/// Sets the colour of the global lighting shader component.
///
/// The colour of the light.
- public void SetLightColour(Color4 lightColour)
+ public void SetLightColour(Vector4 lightColour)
{
EnableParent();
- var colourLoc = GL.GetUniformLocation(_parentShaderNativeID, LightColourIdentifier);
- GL.Uniform4(colourLoc, lightColour);
+ var colourLoc = this.GL.GetUniformLocation(_parentShaderNativeID, LightColourIdentifier);
+ this.GL.Uniform4(colourLoc, lightColour);
}
///
@@ -72,8 +74,8 @@ public void SetLightDirection(Vector3 lightVector)
{
EnableParent();
- var vectorLoc = GL.GetUniformLocation(_parentShaderNativeID, LightVectorIdentifier);
- GL.Uniform3(vectorLoc, lightVector);
+ var vectorLoc = this.GL.GetUniformLocation(_parentShaderNativeID, LightVectorIdentifier);
+ this.GL.Uniform3(vectorLoc, lightVector);
}
///
@@ -84,8 +86,8 @@ public void SetLightIntensity(float lightIntensity)
{
EnableParent();
- var intensityLoc = GL.GetUniformLocation(_parentShaderNativeID, LightIntensityIdentifier);
- GL.Uniform1(intensityLoc, lightIntensity);
+ var intensityLoc = this.GL.GetUniformLocation(_parentShaderNativeID, LightIntensityIdentifier);
+ this.GL.Uniform1(intensityLoc, lightIntensity);
}
}
}
diff --git a/Everlook/Viewport/Rendering/Shaders/Components/SolidWireframe.cs b/Everlook/Viewport/Rendering/Shaders/Components/SolidWireframe.cs
index e680e52..412fb43 100644
--- a/Everlook/Viewport/Rendering/Shaders/Components/SolidWireframe.cs
+++ b/Everlook/Viewport/Rendering/Shaders/Components/SolidWireframe.cs
@@ -20,17 +20,17 @@
// along with this program. If not, see .
//
+using System.Numerics;
+using Everlook.Viewport.Rendering.Core;
using Gdk;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders.Components
{
///
/// This shader component controls an implementation of solid wireframe rendering.
///
- public class SolidWireframe
+ public class SolidWireframe : GraphicsObject
{
private const string ViewportMatrix = nameof(ViewportMatrix);
@@ -44,14 +44,14 @@ public class SolidWireframe
///
/// The standard colour of the wireframe.
///
- public static readonly Color4 StandardColour = new Color4(234, 161, 0, 255);
+ public static readonly Vector4 StandardColour = new Vector4(234, 161, 0, 255);
///
/// The standard highlight colour of the wireframe.
///
- public static readonly Color4 HighlightColour = new Color4(217, 129, 3, 255);
+ public static readonly Vector4 HighlightColour = new Vector4(217, 129, 3, 255);
- private readonly int _parentShaderNativeID;
+ private readonly uint _parentShaderNativeID;
private bool _enabledInternal;
@@ -72,8 +72,10 @@ public bool Enabled
/// Initializes a new instance of the class, and attaches it to the given parent
/// shader.
///
+ /// The OpenGL API.
/// The native ID of the parent shader.
- public SolidWireframe(int parentShaderID)
+ public SolidWireframe(GL gl, uint parentShaderID)
+ : base(gl)
{
_parentShaderNativeID = parentShaderID;
this.Enabled = false;
@@ -85,15 +87,15 @@ public SolidWireframe(int parentShaderID)
private void EnableParent()
{
- GL.UseProgram(_parentShaderNativeID);
+ this.GL.UseProgram(_parentShaderNativeID);
}
private void SetWireframeState(bool isEnabled)
{
EnableParent();
- var enabledLoc = GL.GetUniformLocation(_parentShaderNativeID, IsWireframeEnabled);
- GL.Uniform1(enabledLoc, isEnabled ? 1 : 0);
+ var enabledLoc = this.GL.GetUniformLocation(_parentShaderNativeID, IsWireframeEnabled);
+ this.GL.Uniform1(enabledLoc, isEnabled ? 1 : 0);
}
///
@@ -105,8 +107,8 @@ public void SetWireframeLineWidth(int lineWidth)
{
EnableParent();
- var lineWidthLoc = GL.GetUniformLocation(_parentShaderNativeID, WireframeLineWidth);
- GL.Uniform1(lineWidthLoc, lineWidth);
+ var lineWidthLoc = this.GL.GetUniformLocation(_parentShaderNativeID, WireframeLineWidth);
+ this.GL.Uniform1(lineWidthLoc, lineWidth);
}
///
@@ -115,7 +117,7 @@ public void SetWireframeLineWidth(int lineWidth)
/// The wire colour.
public void SetWireframeColour(RGBA wireframeColour)
{
- var colour = new Color4
+ var colour = new Vector4
(
(float)wireframeColour.Red,
(float)wireframeColour.Green,
@@ -130,12 +132,12 @@ public void SetWireframeColour(RGBA wireframeColour)
/// Sets the colour of the wireframe.
///
/// The wire colour.
- public void SetWireframeColour(Color4 wireframeColour)
+ public void SetWireframeColour(Vector4 wireframeColour)
{
EnableParent();
- var colourLoc = GL.GetUniformLocation(_parentShaderNativeID, WireframeColour);
- GL.Uniform4(colourLoc, wireframeColour);
+ var colourLoc = this.GL.GetUniformLocation(_parentShaderNativeID, WireframeColour);
+ this.GL.Uniform4(colourLoc, wireframeColour);
}
///
@@ -146,20 +148,23 @@ public void SetWireframeFadeWidth(int fadeWidth)
{
EnableParent();
- var fadeWidthLoc = GL.GetUniformLocation(_parentShaderNativeID, WireframeFadeWidth);
- GL.Uniform1(fadeWidthLoc, fadeWidth);
+ var fadeWidthLoc = this.GL.GetUniformLocation(_parentShaderNativeID, WireframeFadeWidth);
+ this.GL.Uniform1(fadeWidthLoc, fadeWidth);
}
///
/// Sets the viewport matrix that will transform NDC coordinates to screen space coordinates.
///
/// The viewport matrix.
- public void SetViewportMatrix(Matrix3 viewportMatrix)
+ public void SetViewportMatrix(Matrix4x4 viewportMatrix)
{
EnableParent();
- var viewportMatrixLoc = GL.GetUniformLocation(_parentShaderNativeID, ViewportMatrix);
- GL.UniformMatrix3(viewportMatrixLoc, false, ref viewportMatrix);
+ var viewportMatrixLoc = this.GL.GetUniformLocation(_parentShaderNativeID, ViewportMatrix);
+ unsafe
+ {
+ this.GL.UniformMatrix4(viewportMatrixLoc, 1, false, &viewportMatrix.M11);
+ }
}
}
}
diff --git a/Everlook/Viewport/Rendering/Shaders/GLSLExtended/GLSLPreprocessor.cs b/Everlook/Viewport/Rendering/Shaders/GLSLExtended/GLSLPreprocessor.cs
index aa579d1..33921d3 100644
--- a/Everlook/Viewport/Rendering/Shaders/GLSLExtended/GLSLPreprocessor.cs
+++ b/Everlook/Viewport/Rendering/Shaders/GLSLExtended/GLSLPreprocessor.cs
@@ -43,7 +43,7 @@ public static string ProcessIncludes(string source, string baseResourceDirectory
{
// Find a list of includes
var includeRegex = new Regex("#include\\s+?\"(?.+)\"", RegexOptions.Multiline);
- var matches = includeRegex.Matches(source).Cast().Reverse();
+ var matches = includeRegex.Matches(source).Reverse();
// Remove any trailing dot separators from the resource directory.
baseResourceDirectory = baseResourceDirectory.TrimEnd('.');
@@ -57,7 +57,7 @@ public static string ProcessIncludes(string source, string baseResourceDirectory
// Try loading it from the resource manifest
var fileContents = Utility.ResourceManager.LoadStringResource($"{baseResourceDirectory}.{resourceName}");
- if (fileContents == null)
+ if (fileContents is null)
{
throw new FileNotFoundException
(
diff --git a/Everlook/Viewport/Rendering/Shaders/GameModelShader.cs b/Everlook/Viewport/Rendering/Shaders/GameModelShader.cs
index 6944184..57c83e9 100644
--- a/Everlook/Viewport/Rendering/Shaders/GameModelShader.cs
+++ b/Everlook/Viewport/Rendering/Shaders/GameModelShader.cs
@@ -20,12 +20,10 @@
// along with this program. If not, see .
//
-using System;
+using System.Numerics;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Shaders.Components;
-using OpenTK;
-using OpenTK.Graphics;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using Warcraft.Core.Shading.Blending;
using Warcraft.Core.Shading.MDX;
using Warcraft.MDX.Visual;
@@ -64,11 +62,13 @@ public class GameModelShader : ShaderProgram
///
/// Initializes a new instance of the class.
///
- public GameModelShader()
+ /// The OpenGL API.
+ public GameModelShader(GL gl)
+ : base(gl)
{
- this.Wireframe = new SolidWireframe(this.NativeShaderProgramID);
+ this.Wireframe = new SolidWireframe(this.GL, this.NativeShaderProgramID);
- SetBaseInputColour(Color4.White);
+ SetBaseInputColour(Vector4.One);
SetFragmentShaderType(MDXFragmentShaderType.Combiners_Opaque);
}
@@ -85,7 +85,7 @@ public void SetIsInstance(bool isInstanced)
/// Sets the current model matrix of the shader.
///
/// The model matrix.
- public void SetModelMatrix(Matrix4 modelMatrix)
+ public void SetModelMatrix(Matrix4x4 modelMatrix)
{
SetMatrix(modelMatrix, ModelMatrix);
}
@@ -94,7 +94,7 @@ public void SetModelMatrix(Matrix4 modelMatrix)
/// Sets the current view matrix of the shader.
///
/// The model-view matrix.
- public void SetViewMatrix(Matrix4 viewMatrix)
+ public void SetViewMatrix(Matrix4x4 viewMatrix)
{
SetMatrix(viewMatrix, ViewMatrix);
}
@@ -103,7 +103,7 @@ public void SetViewMatrix(Matrix4 viewMatrix)
/// Sets the current projection matrix of the shader.
///
/// The projection matrix.
- public void SetProjectionMatrix(Matrix4 projectionMatrix)
+ public void SetProjectionMatrix(Matrix4x4 projectionMatrix)
{
SetMatrix(projectionMatrix, ProjectionMatrix);
}
@@ -112,9 +112,9 @@ public void SetProjectionMatrix(Matrix4 projectionMatrix)
/// Sets the base input colour for the shader.
///
/// The base colour.
- public void SetBaseInputColour(Color4 colour)
+ public void SetBaseInputColour(Vector4 colour)
{
- SetColor4(colour, BaseColour);
+ SetVector4(colour, BaseColour);
}
///
@@ -177,30 +177,25 @@ public void BindTexture3(Texture2D texture)
/// The material to use.
public void SetMaterial(MDXMaterial modelMaterial)
{
- if (modelMaterial == null)
- {
- throw new ArgumentNullException(nameof(modelMaterial));
- }
-
Enable();
// Set two-sided rendering
if (modelMaterial.Flags.HasFlag(MDXRenderFlag.TwoSided))
{
- GL.Disable(EnableCap.CullFace);
+ this.GL.Disable(EnableCap.CullFace);
}
else
{
- GL.Enable(EnableCap.CullFace);
+ this.GL.Enable(EnableCap.CullFace);
}
if (BlendingState.EnableBlending[modelMaterial.BlendMode])
{
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
else
{
- GL.Disable(EnableCap.Blend);
+ this.GL.Disable(EnableCap.Blend);
}
var dstA = BlendingState.DestinationAlpha[modelMaterial.BlendMode];
@@ -209,12 +204,12 @@ public void SetMaterial(MDXMaterial modelMaterial)
var dstC = BlendingState.DestinationColour[modelMaterial.BlendMode];
var srcC = BlendingState.SourceColour[modelMaterial.BlendMode];
- GL.BlendFuncSeparate
+ this.GL.BlendFuncSeparate
(
- (BlendingFactorSrc)srcC,
- (BlendingFactorDest)dstC,
- (BlendingFactorSrc)srcA,
- (BlendingFactorDest)dstA
+ (BlendingFactor)srcC,
+ (BlendingFactor)dstC,
+ (BlendingFactor)srcA,
+ (BlendingFactor)dstA
);
switch (modelMaterial.BlendMode)
diff --git a/Everlook/Viewport/Rendering/Shaders/Plain2DShader.cs b/Everlook/Viewport/Rendering/Shaders/Plain2DShader.cs
index dc6fa13..c5726c3 100644
--- a/Everlook/Viewport/Rendering/Shaders/Plain2DShader.cs
+++ b/Everlook/Viewport/Rendering/Shaders/Plain2DShader.cs
@@ -20,9 +20,10 @@
// along with this program. If not, see .
//
+using System.Numerics;
using Everlook.Viewport.Rendering.Core;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
+using JetBrains.Annotations;
+using Silk.NET.OpenGL;
namespace Everlook.Viewport.Rendering.Shaders
{
@@ -42,6 +43,15 @@ public class Plain2DShader : ShaderProgram
///
protected override string? GeometryShaderResourceName => null;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The OpenGL API.
+ public Plain2DShader([NotNull] GL gl)
+ : base(gl)
+ {
+ }
+
///
/// Sets the channel mask of the shader.
///
diff --git a/Everlook/Viewport/Rendering/Shaders/WorldModelShader.cs b/Everlook/Viewport/Rendering/Shaders/WorldModelShader.cs
index 1a62bd0..dbe83b1 100644
--- a/Everlook/Viewport/Rendering/Shaders/WorldModelShader.cs
+++ b/Everlook/Viewport/Rendering/Shaders/WorldModelShader.cs
@@ -20,10 +20,9 @@
// along with this program. If not, see .
//
-using System;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Shaders.Components;
-using OpenTK.Graphics.OpenGL;
+using Silk.NET.OpenGL;
using Warcraft.Core.Shading.Blending;
using Warcraft.WMO.RootFile.Chunks;
@@ -53,9 +52,11 @@ public class WorldModelShader : ShaderProgram
///
/// Initializes a new instance of the class.
///
- public WorldModelShader()
+ /// The OpenGL API.
+ public WorldModelShader(GL gl)
+ : base(gl)
{
- this.Wireframe = new SolidWireframe(this.NativeShaderProgramID);
+ this.Wireframe = new SolidWireframe(this.GL, this.NativeShaderProgramID);
}
///
@@ -64,30 +65,25 @@ public WorldModelShader()
/// The material to use.
public void SetMaterial(ModelMaterial modelMaterial)
{
- if (modelMaterial == null)
- {
- throw new ArgumentNullException(nameof(modelMaterial));
- }
-
Enable();
// Set two-sided rendering
if (modelMaterial.Flags.HasFlag(MaterialFlags.TwoSided))
{
- GL.Disable(EnableCap.CullFace);
+ this.GL.Disable(EnableCap.CullFace);
}
else
{
- GL.Enable(EnableCap.CullFace);
+ this.GL.Enable(EnableCap.CullFace);
}
if (BlendingState.EnableBlending[modelMaterial.BlendMode])
{
- GL.Enable(EnableCap.Blend);
+ this.GL.Enable(EnableCap.Blend);
}
else
{
- GL.Disable(EnableCap.Blend);
+ this.GL.Disable(EnableCap.Blend);
}
var dstA = BlendingState.DestinationAlpha[modelMaterial.BlendMode];
@@ -96,12 +92,12 @@ public void SetMaterial(ModelMaterial modelMaterial)
var dstC = BlendingState.DestinationColour[modelMaterial.BlendMode];
var srcC = BlendingState.SourceColour[modelMaterial.BlendMode];
- GL.BlendFuncSeparate
+ this.GL.BlendFuncSeparate
(
- (BlendingFactorSrc)srcC,
- (BlendingFactorDest)dstC,
- (BlendingFactorSrc)srcA,
- (BlendingFactorDest)dstA
+ (BlendingFactor)srcC,
+ (BlendingFactor)dstC,
+ (BlendingFactor)srcA,
+ (BlendingFactor)dstA
);
switch (modelMaterial.BlendMode)
diff --git a/Everlook/Viewport/ViewportRenderer.cs b/Everlook/Viewport/ViewportRenderer.cs
index e363984..782be62 100644
--- a/Everlook/Viewport/ViewportRenderer.cs
+++ b/Everlook/Viewport/ViewportRenderer.cs
@@ -26,13 +26,15 @@
using Everlook.Configuration;
using Everlook.UI.Widgets;
using Everlook.Viewport.Camera;
+using Everlook.Viewport.Rendering;
using Everlook.Viewport.Rendering.Core;
using Everlook.Viewport.Rendering.Interfaces;
using Gdk;
+using Gtk;
using log4net;
-using OpenTK;
-using OpenTK.Graphics.OpenGL;
-using OpenTK.Input;
+using Silk.NET.OpenGL;
+using Key = Gdk.Key;
+using Window = Gtk.Window;
namespace Everlook.Viewport
{
@@ -40,7 +42,7 @@ namespace Everlook.Viewport
/// Viewport renderer for the main Everlook UI. This class manages an OpenGL rendering thread, which
/// uses rendering built into the different renderable objects.
///
- public sealed class ViewportRenderer : IDisposable
+ public sealed class ViewportRenderer : GraphicsObject, IDisposable
{
///
/// Logger instance for this class.
@@ -53,6 +55,11 @@ public sealed class ViewportRenderer : IDisposable
///
private readonly ViewportArea _viewportWidget;
+ ///
+ /// Holds the rendering cache.
+ ///
+ private readonly RenderCache _renderCache;
+
/*
RenderTarget and related control flow data.
*/
@@ -100,14 +107,28 @@ RenderTarget and related control flow data.
public bool WantsToMove { get; set; }
///
- /// Gets or sets the X position of the mouse during the last frame, relative to the .
+ /// Gets or sets the X position of the mouse during the last frame, relative to the
+ /// .
+ ///
+ public double InitialMouseX { get; set; }
+
+ ///
+ /// Gets or sets the Y position of the mouse during the last frame, relative to the
+ /// .
///
- public int InitialMouseX { get; set; }
+ public double InitialMouseY { get; set; }
///
- /// Gets or sets the Y position of the mouse during the last frame, relative to the .
+ /// Gets or sets the Y position of the mouse at the last event time, relative to the
+ /// .
///
- public int InitialMouseY { get; set; }
+ public double CurrentMouseX { get; set; }
+
+ ///
+ /// Gets or sets the Y position of the mouse at the last event time, relative to the
+ /// .
+ ///
+ public double CurrentMouseY { get; set; }
/*
Runtime transitional OpenGL data.
@@ -116,7 +137,7 @@ Runtime transitional OpenGL data.
///
/// The OpenGL ID of the vertex array valid for the current context.
///
- private int _vertexArrayID;
+ private uint _vertexArrayID;
///
/// Gets a value indicating whether or not this instance has been initialized and is ready
@@ -145,12 +166,142 @@ Everlook caching and static data accessors.
///
/// Initializes a new instance of the class.
///
+ /// The OpenGL API.
+ /// The rendering cache.
/// The widget which the viewport should be rendered to.
- public ViewportRenderer(ViewportArea viewportWidget)
+ public ViewportRenderer(GL gl, RenderCache renderCache, ViewportArea viewportWidget)
+ : base(gl)
{
_viewportWidget = viewportWidget;
_camera = new ViewportCamera();
_movement = new CameraMovement(_camera);
+ _renderCache = renderCache;
+
+ _viewportWidget.MotionNotifyEvent += (o, args) =>
+ {
+ if (!this.WantsToMove)
+ {
+ return;
+ }
+
+ if (!this.HasRenderTarget || this.RenderTarget is null)
+ {
+ return;
+ }
+
+ if
+ (
+ Math.Abs(args.Event.X - this.InitialMouseX) < 1.0f &&
+ Math.Abs(args.Event.Y - this.InitialMouseY) < 1.0f
+ )
+ {
+ // When we warp the mouse, there may be some floating-point errors. We take a tolerance of one
+ // pixel, and reset the current to initial if we're within that tolerance.
+ this.CurrentMouseX = this.InitialMouseX;
+ this.CurrentMouseY = this.InitialMouseY;
+ }
+ else
+ {
+ this.CurrentMouseX = args.Event.X;
+ this.CurrentMouseY = args.Event.Y;
+ }
+ };
+
+ _viewportWidget.KeyPressEvent += (o, args) =>
+ {
+ switch (args.Event.Key)
+ {
+ case Key.Shift_L:
+ {
+ _movement.WantsToSprint = true;
+ break;
+ }
+ case Key.W:
+ case Key.w:
+ {
+ _movement.WantsToMoveForward = true;
+ break;
+ }
+ case Key.S:
+ case Key.s:
+ {
+ _movement.WantsToMoveBackward = true;
+ break;
+ }
+ case Key.A:
+ case Key.a:
+ {
+ _movement.WantsToMoveLeft = true;
+ break;
+ }
+ case Key.D:
+ case Key.d:
+ {
+ _movement.WantsToMoveRight = true;
+ break;
+ }
+ case Key.Q:
+ case Key.q:
+ {
+ _movement.WantsToMoveUp = true;
+ break;
+ }
+ case Key.E:
+ case Key.e:
+ {
+ _movement.WantsToMoveDown = true;
+ break;
+ }
+ }
+ };
+
+ _viewportWidget.KeyReleaseEvent += (o, args) =>
+ {
+ switch (args.Event.Key)
+ {
+ case Key.Shift_L:
+ {
+ _movement.WantsToSprint = false;
+ break;
+ }
+ case Key.W:
+ case Key.w:
+ {
+ _movement.WantsToMoveForward = false;
+ break;
+ }
+ case Key.S:
+ case Key.s:
+ {
+ _movement.WantsToMoveBackward = false;
+ break;
+ }
+ case Key.A:
+ case Key.a:
+ {
+ _movement.WantsToMoveLeft = false;
+ break;
+ }
+ case Key.D:
+ case Key.d:
+ {
+ _movement.WantsToMoveRight = false;
+ break;
+ }
+ case Key.Q:
+ case Key.q:
+ {
+ _movement.WantsToMoveUp = false;
+ break;
+ }
+ case Key.E:
+ case Key.e:
+ {
+ _movement.WantsToMoveDown = false;
+ break;
+ }
+ }
+ };
this.IsInitialized = false;
}
@@ -164,44 +315,55 @@ public void Initialize()
Log.Info($"Initializing {nameof(ViewportRenderer)} and setting up default OpenGL state...");
- var numExtensions = GL.GetInteger(GetPName.NumExtensions);
+ var numExtensions = this.GL.GetInteger(GetPName.NumExtensions);
var extensions = new List();
- for (var i = 0; i < numExtensions; ++i)
+ for (var i = 0u; i < numExtensions; ++i)
{
- extensions.Add(GL.GetString(StringNameIndexed.Extensions, i));
+ extensions.Add(this.GL.GetString(StringName.Extensions, i));
}
if (extensions.Contains("GL_KHR_debug"))
{
- //GL.Enable(EnableCap.DebugOutput);
- GL.Enable(EnableCap.DebugOutputSynchronous);
- GL.DebugMessageCallback(OnGLDebugMessage, IntPtr.Zero);
+ this.GL.Enable(EnableCap.DebugOutputSynchronous);
+
+ unsafe
+ {
+ this.GL.DebugMessageCallback(OnGLDebugMessage, (void*)0);
+ }
}
// Generate the vertex array
- GL.GenVertexArrays(1, out _vertexArrayID);
- GL.BindVertexArray(_vertexArrayID);
+ unsafe
+ {
+ fixed (uint* ptr = &_vertexArrayID)
+ {
+ this.GL.GenVertexArrays(1, ptr);
+ }
+ }
+
+ this.GL.BindVertexArray(_vertexArrayID);
// GL.Disable(EnableCap.AlphaTest);
// Make sure we use the depth buffer when drawing
- GL.Enable(EnableCap.DepthTest);
- GL.DepthFunc(DepthFunction.Lequal);
- GL.DepthMask(true);
+ this.GL.Enable(EnableCap.DepthTest);
+ this.GL.DepthFunc(DepthFunction.Lequal);
+ this.GL.DepthMask(true);
// Enable backface culling for performance reasons
- GL.Enable(EnableCap.CullFace);
+ this.GL.Enable(EnableCap.CullFace);
// Set a simple default blending function
- GL.Enable(EnableCap.Blend);
- GL.BlendEquation(BlendEquationMode.FuncAdd);
- GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
+ this.GL.Enable(EnableCap.Blend);
+ this.GL.BlendEquation(BlendEquationModeEXT.FuncAdd);
+ this.GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha);
// Initialize the viewport
- var widgetWidth = _viewportWidget.AllocatedWidth;
- var widgetHeight = _viewportWidget.AllocatedHeight;
- GL.Viewport(0, 0, widgetWidth, widgetHeight);
- GL.ClearColor
+ var widgetWidth = (uint)_viewportWidget.AllocatedWidth;
+ var widgetHeight = (uint)_viewportWidget.AllocatedHeight;
+
+ this.GL.Viewport(0, 0, widgetWidth, widgetHeight);
+ this.GL.ClearColor
(
(float)_configuration.ViewportBackgroundColour.Red,
(float)_configuration.ViewportBackgroundColour.Green,
@@ -209,9 +371,9 @@ public void Initialize()
(float)_configuration.ViewportBackgroundColour.Alpha
);
- GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+ this.GL.Clear((uint)(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
- _grid = new BaseGrid();
+ _grid = new BaseGrid(this.GL, _renderCache);
_grid.Initialize();
this.IsInitialized = true;
@@ -223,7 +385,7 @@ public void Initialize()
/// The new colour to use.
public void SetClearColour(RGBA colour)
{
- GL.ClearColor
+ this.GL.ClearColor
(
(float)colour.Red,
(float)colour.Green,
@@ -234,10 +396,10 @@ public void SetClearColour(RGBA colour)
private static void OnGLDebugMessage
(
- DebugSource source,
- DebugType type,
+ GLEnum source,
+ GLEnum type,
int id,
- DebugSeverity severity,
+ GLEnum severity,
int length,
IntPtr message,
IntPtr userparam
@@ -261,17 +423,18 @@ public void RenderFrame()
lock (_renderTargetLock)
{
// Make sure the viewport is accurate for the current widget size on screen
- var widgetWidth = _viewportWidget.AllocatedWidth;
- var widgetHeight = _viewportWidget.AllocatedHeight;
- GL.Viewport(0, 0, widgetWidth, widgetHeight);
- GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
+ var widgetWidth = (uint)_viewportWidget.AllocatedWidth;
+ var widgetHeight = (uint)_viewportWidget.AllocatedHeight;
+
+ this.GL.Viewport(0, 0, widgetWidth, widgetHeight);
+ this.GL.Clear((uint)(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit));
if (!this.HasRenderTarget || this.RenderTarget is null)
{
return;
}
- // Calculate the current relative movement of the camera
+ // Update camera orientation
if (this.WantsToMove)
{
switch (this.RenderTarget.Projection)
@@ -316,17 +479,14 @@ public void RenderFrame()
///
private void Calculate2DMovement()
{
- var mouseX = Mouse.GetCursorState().X;
- var mouseY = Mouse.GetCursorState().Y;
-
- float deltaMouseX = this.InitialMouseX - mouseX;
- float deltaMouseY = this.InitialMouseY - mouseY;
+ var deltaMouseX = this.InitialMouseX - this.CurrentMouseX;
+ var deltaMouseY = this.InitialMouseY - this.CurrentMouseY;
_movement.Calculate2DMovement(deltaMouseX, deltaMouseY, this.DeltaTime);
// Update the initial location for the next frame
- this.InitialMouseX = mouseX;
- this.InitialMouseY = mouseY;
+ this.InitialMouseX = this.CurrentMouseX;
+ this.InitialMouseY = this.CurrentMouseY;
}
///
@@ -334,16 +494,28 @@ private void Calculate2DMovement()
///
private void Calculate3DMovement()
{
- var mouseX = Mouse.GetCursorState().X;
- var mouseY = Mouse.GetCursorState().Y;
-
- float deltaMouseX = this.InitialMouseX - mouseX;
- float deltaMouseY = this.InitialMouseY - mouseY;
+ var deltaMouseX = this.InitialMouseX - this.CurrentMouseX;
+ var deltaMouseY = this.InitialMouseY - this.CurrentMouseY;
_movement.Calculate3DMovement(deltaMouseX, deltaMouseY, this.DeltaTime);
+ _viewportWidget.Toplevel.Window.GetOrigin(out var windowX, out var windowY);
+ _viewportWidget.TranslateCoordinates
+ (
+ _viewportWidget.Toplevel,
+ 0,
+ 0,
+ out var widgetX,
+ out var widgetY
+ );
+
// Return the mouse to its original position
- Mouse.SetPosition(this.InitialMouseX, this.InitialMouseY);
+ Display.Default.DeviceManager.ClientPointer.Warp
+ (
+ Screen.Default,
+ (int)(windowX + this.InitialMouseX + widgetX),
+ (int)(windowY + this.InitialMouseY + widgetY)
+ );
}
///
@@ -352,7 +524,7 @@ private void Calculate3DMovement()
/// true if movement is disabled; false otherwise.
public bool IsMovementDisabled()
{
- return this.RenderTarget == null || !this.RenderTarget.IsInitialized;
+ return this.RenderTarget is null || !this.RenderTarget.IsInitialized;
}
///
@@ -376,8 +548,8 @@ public void SetRenderTarget(IRenderable? inRenderable)
{
return;
}
- _camera.ViewportWidth = _viewportWidget.AllocatedWidth;
- _camera.ViewportHeight = _viewportWidget.AllocatedHeight;
+ _camera.ViewportWidth = (uint)_viewportWidget.AllocatedWidth;
+ _camera.ViewportHeight = (uint)_viewportWidget.AllocatedHeight;
if (this.RenderTarget is IDefaultCameraPositionProvider cameraPositionProvider)
{
@@ -398,7 +570,7 @@ private void ThrowIfDisposed()
{
if (this.IsDisposed)
{
- throw new ObjectDisposedException(ToString());
+ throw new ObjectDisposedException(ToString() ?? nameof(ViewportRenderer));
}
}
@@ -409,7 +581,13 @@ public void Dispose()
this.RenderTarget?.Dispose();
- GL.DeleteVertexArrays(1, ref _vertexArrayID);
+ unsafe
+ {
+ fixed (uint* ptr = &_vertexArrayID)
+ {
+ this.GL.DeleteVertexArrays(1u, ptr);
+ }
+ }
}
}
}
diff --git a/Everlook/app.config b/Everlook/app.config
deleted file mode 100644
index 6caee30..0000000
--- a/Everlook/app.config
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Everlook/config/appsettings.json b/Everlook/config/appsettings.json
new file mode 100644
index 0000000..6ba02f3
--- /dev/null
+++ b/Everlook/config/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Debug",
+ "System": "Information",
+ "Microsoft": "Information"
+ }
+ }
+}
diff --git a/Everlook/log4net.config b/Everlook/log4net.config
new file mode 100644
index 0000000..3598450
--- /dev/null
+++ b/Everlook/log4net.config
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NuGet.config b/NuGet.config
index e72b594..f072f57 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -1,8 +1,3 @@
-
-
-
-
-
diff --git a/stylecop.json b/stylecop.json
index 4a23c77..9e910ec 100644
--- a/stylecop.json
+++ b/stylecop.json
@@ -30,7 +30,8 @@
"db",
"x",
"y",
- "z"
+ "z",
+ "uv"
]
},
"maintainabilityRules" : {