Initial commit.
This commit is contained in:
commit
74c23c0ad5
57 changed files with 3491 additions and 0 deletions
828
ArtifactEngine.xcodeproj/project.pbxproj
Normal file
828
ArtifactEngine.xcodeproj/project.pbxproj
Normal file
|
|
@ -0,0 +1,828 @@
|
||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 77;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
9B20EE962F4BC69100117DD8 /* libwgpu_native.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE952F4BC69100117DD8 /* libwgpu_native.a */; };
|
||||||
|
9B20EE982F4BC6C600117DD8 /* libngtcp2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE972F4BC6C600117DD8 /* libngtcp2.a */; };
|
||||||
|
9B20EE9C2F4BCF7D00117DD8 /* libglfw3.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE9B2F4BCF7D00117DD8 /* libglfw3.a */; };
|
||||||
|
9B20EEAA2F4BD04000117DD8 /* libClient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE672F4BC09C00117DD8 /* libClient.a */; };
|
||||||
|
9B20EEAB2F4BD04400117DD8 /* libServer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE752F4BC0FD00117DD8 /* libServer.a */; };
|
||||||
|
9B20EEAC2F4BD04400117DD8 /* libShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE7F2F4BC11100117DD8 /* libShared.a */; };
|
||||||
|
9B20EEAD2F4BD05300117DD8 /* libShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE7F2F4BC11100117DD8 /* libShared.a */; };
|
||||||
|
9B20EEAE2F4BD05700117DD8 /* libShared.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EE7F2F4BC11100117DD8 /* libShared.a */; };
|
||||||
|
9B20EEC22F4D028400117DD8 /* libgnutls.30.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEC12F4D028400117DD8 /* libgnutls.30.dylib */; };
|
||||||
|
9B20EEC42F4D141600117DD8 /* libev.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEC32F4D141600117DD8 /* libev.a */; };
|
||||||
|
9B20EEDA2F60D87E00117DD8 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EED92F60D87E00117DD8 /* IOKit.framework */; };
|
||||||
|
9B20EEDC2F60D88D00117DD8 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEDB2F60D88D00117DD8 /* QuartzCore.framework */; };
|
||||||
|
9B20EEE02F60D92300117DD8 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEDF2F60D92300117DD8 /* Cocoa.framework */; };
|
||||||
|
9B20EF182F60F1DF00117DD8 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EF172F60F1DF00117DD8 /* CoreVideo.framework */; };
|
||||||
|
9B20EF192F60F1E500117DD8 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEDB2F60D88D00117DD8 /* QuartzCore.framework */; };
|
||||||
|
9B20EF1A2F60F1F000117DD8 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EEDF2F60D92300117DD8 /* Cocoa.framework */; };
|
||||||
|
9B20EF1C2F60F22500117DD8 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EED92F60D87E00117DD8 /* IOKit.framework */; };
|
||||||
|
9B20EF1D2F60F23C00117DD8 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9B20EF172F60F1DF00117DD8 /* CoreVideo.framework */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
9B20EE8B2F4BC55500117DD8 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 9B20EE7E2F4BC11100117DD8;
|
||||||
|
remoteInfo = Shared;
|
||||||
|
};
|
||||||
|
9B20EE8D2F4BC55F00117DD8 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 9B20EE7E2F4BC11100117DD8;
|
||||||
|
remoteInfo = Shared;
|
||||||
|
};
|
||||||
|
9B20EE8F2F4BC56500117DD8 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 9B20EE662F4BC09C00117DD8;
|
||||||
|
remoteInfo = Client;
|
||||||
|
};
|
||||||
|
9B20EE912F4BC56500117DD8 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 9B20EE742F4BC0FD00117DD8;
|
||||||
|
remoteInfo = Server;
|
||||||
|
};
|
||||||
|
9B20EE932F4BC56500117DD8 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 9B20EE7E2F4BC11100117DD8;
|
||||||
|
remoteInfo = Shared;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9B20EE582F4BBF4800117DD8 /* CopyFiles */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = /usr/share/man/man1/;
|
||||||
|
dstSubfolderSpec = 0;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 1;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
9B20EE3E2F4BBEEC00117DD8 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
|
||||||
|
9B20EE5A2F4BBF4800117DD8 /* TestGame */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TestGame; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
9B20EE672F4BC09C00117DD8 /* libClient.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libClient.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
9B20EE752F4BC0FD00117DD8 /* libServer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libServer.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
9B20EE7F2F4BC11100117DD8 /* libShared.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libShared.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
9B20EE952F4BC69100117DD8 /* libwgpu_native.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwgpu_native.a; path = "../../../eclipse-workspace/ArtifactEngine/deps/webgpu/lib/libwgpu_native.a"; sourceTree = "<group>"; };
|
||||||
|
9B20EE972F4BC6C600117DD8 /* libngtcp2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libngtcp2.a; path = "../../../eclipse-workspace/ArtifactEngine/deps/ngtcp2/build/lib/libngtcp2.a"; sourceTree = "<group>"; };
|
||||||
|
9B20EE9B2F4BCF7D00117DD8 /* libglfw3.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libglfw3.a; path = "../../../eclipse-workspace/ArtifactEngine/deps/glfw/install/lib/libglfw3.a"; sourceTree = "<group>"; };
|
||||||
|
9B20EEC12F4D028400117DD8 /* libgnutls.30.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libgnutls.30.dylib; path = ../../../homebrew/Cellar/gnutls/3.8.11/lib/libgnutls.30.dylib; sourceTree = "<group>"; };
|
||||||
|
9B20EEC32F4D141600117DD8 /* libev.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libev.a; path = ../../../homebrew/Cellar/libev/4.33/lib/libev.a; sourceTree = "<group>"; };
|
||||||
|
9B20EED42F60D84B00117DD8 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EED72F60D86C00117DD8 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EED92F60D87E00117DD8 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EEDB2F60D88D00117DD8 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EEDD2F60D89F00117DD8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EEDF2F60D92300117DD8 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EEE12F60D93200117DD8 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
|
||||||
|
9B20EF172F60F1DF00117DD8 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
|
||||||
|
9BE79E5E2F846F6D0038B496 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
9B20EE6C2F4BC0C500117DD8 /* Exceptions for "Client" folder in "Client" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
additionalCompilerFlagsByRelativePath = {
|
||||||
|
glfw3webgpu/glfw3webgpu.c = "-x objective-c";
|
||||||
|
};
|
||||||
|
membershipExceptions = (
|
||||||
|
Client.cpp,
|
||||||
|
Client.h,
|
||||||
|
glfw3webgpu/glfw3webgpu.c,
|
||||||
|
glfw3webgpu/glfw3webgpu.h,
|
||||||
|
Graphics/Camera.cpp,
|
||||||
|
Graphics/Camera.h,
|
||||||
|
Graphics/ChunkRenderer.cpp,
|
||||||
|
Graphics/EntityRenderer.cpp,
|
||||||
|
Graphics/EntityRenderer.h,
|
||||||
|
Graphics/Graphics.cpp,
|
||||||
|
Graphics/Graphics.h,
|
||||||
|
Graphics/UIRenderer.cpp,
|
||||||
|
Graphics/UIRenderer.h,
|
||||||
|
Graphics/WorldRenderer.cpp,
|
||||||
|
Graphics/WorldRenderer.h,
|
||||||
|
LocalPlayer.cpp,
|
||||||
|
LocalPlayer.h,
|
||||||
|
Network.h,
|
||||||
|
Platform/Keybinds.cpp,
|
||||||
|
Platform/Keybinds.h,
|
||||||
|
Platform/Window.cpp,
|
||||||
|
Platform/Window.h,
|
||||||
|
);
|
||||||
|
target = 9B20EE662F4BC09C00117DD8 /* Client */;
|
||||||
|
};
|
||||||
|
9B20EE7A2F4BC10500117DD8 /* Exceptions for "Server" folder in "Server" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Network.h,
|
||||||
|
Player.cpp,
|
||||||
|
Player.h,
|
||||||
|
Server.cpp,
|
||||||
|
Server.h,
|
||||||
|
World/WorldBackend.cpp,
|
||||||
|
World/WorldManager.cpp,
|
||||||
|
);
|
||||||
|
target = 9B20EE742F4BC0FD00117DD8 /* Server */;
|
||||||
|
};
|
||||||
|
9B20EE842F4BC11700117DD8 /* Exceptions for "Shared" folder in "Shared" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Events.h,
|
||||||
|
Network/Connection.cpp,
|
||||||
|
Network/Network.cpp,
|
||||||
|
Network/Network.h,
|
||||||
|
Paths.cpp,
|
||||||
|
Paths.h,
|
||||||
|
Settings.cpp,
|
||||||
|
Settings.h,
|
||||||
|
Shared.cpp,
|
||||||
|
Shared.h,
|
||||||
|
);
|
||||||
|
target = 9B20EE7E2F4BC11100117DD8 /* Shared */;
|
||||||
|
};
|
||||||
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
9B20EE4B2F4BBF0200117DD8 /* Client */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
9B20EE6C2F4BC0C500117DD8 /* Exceptions for "Client" folder in "Client" target */,
|
||||||
|
);
|
||||||
|
path = Client;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9B20EE522F4BBF0A00117DD8 /* Server */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
9B20EE7A2F4BC10500117DD8 /* Exceptions for "Server" folder in "Server" target */,
|
||||||
|
);
|
||||||
|
path = Server;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9B20EE552F4BBF0D00117DD8 /* Shared */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
9B20EE842F4BC11700117DD8 /* Exceptions for "Shared" folder in "Shared" target */,
|
||||||
|
);
|
||||||
|
path = Shared;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9B20EE5B2F4BBF4800117DD8 /* TestGame */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
path = TestGame;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
9B20EE572F4BBF4800117DD8 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
9B20EF1D2F60F23C00117DD8 /* CoreVideo.framework in Frameworks */,
|
||||||
|
9B20EEE02F60D92300117DD8 /* Cocoa.framework in Frameworks */,
|
||||||
|
9B20EEDC2F60D88D00117DD8 /* QuartzCore.framework in Frameworks */,
|
||||||
|
9B20EEDA2F60D87E00117DD8 /* IOKit.framework in Frameworks */,
|
||||||
|
9B20EEAB2F4BD04400117DD8 /* libServer.a in Frameworks */,
|
||||||
|
9B20EEAC2F4BD04400117DD8 /* libShared.a in Frameworks */,
|
||||||
|
9B20EEAA2F4BD04000117DD8 /* libClient.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE652F4BC09C00117DD8 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
9B20EF1C2F60F22500117DD8 /* IOKit.framework in Frameworks */,
|
||||||
|
9B20EF1A2F60F1F000117DD8 /* Cocoa.framework in Frameworks */,
|
||||||
|
9B20EF192F60F1E500117DD8 /* QuartzCore.framework in Frameworks */,
|
||||||
|
9B20EF182F60F1DF00117DD8 /* CoreVideo.framework in Frameworks */,
|
||||||
|
9B20EEAD2F4BD05300117DD8 /* libShared.a in Frameworks */,
|
||||||
|
9B20EE9C2F4BCF7D00117DD8 /* libglfw3.a in Frameworks */,
|
||||||
|
9B20EE962F4BC69100117DD8 /* libwgpu_native.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE732F4BC0FD00117DD8 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
9B20EEAE2F4BD05700117DD8 /* libShared.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE7D2F4BC11100117DD8 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
9B20EEC42F4D141600117DD8 /* libev.a in Frameworks */,
|
||||||
|
9B20EEC22F4D028400117DD8 /* libgnutls.30.dylib in Frameworks */,
|
||||||
|
9B20EE982F4BC6C600117DD8 /* libngtcp2.a in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
9B20EE282F4BBE9600117DD8 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9BE79E5E2F846F6D0038B496 /* README.md */,
|
||||||
|
9B20EE3E2F4BBEEC00117DD8 /* CMakeLists.txt */,
|
||||||
|
9B20EE4B2F4BBF0200117DD8 /* Client */,
|
||||||
|
9B20EE522F4BBF0A00117DD8 /* Server */,
|
||||||
|
9B20EE552F4BBF0D00117DD8 /* Shared */,
|
||||||
|
9B20EE5B2F4BBF4800117DD8 /* TestGame */,
|
||||||
|
9B20EE852F4BC12400117DD8 /* Frameworks */,
|
||||||
|
9B20EE322F4BBE9600117DD8 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9B20EE322F4BBE9600117DD8 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9B20EE5A2F4BBF4800117DD8 /* TestGame */,
|
||||||
|
9B20EE672F4BC09C00117DD8 /* libClient.a */,
|
||||||
|
9B20EE752F4BC0FD00117DD8 /* libServer.a */,
|
||||||
|
9B20EE7F2F4BC11100117DD8 /* libShared.a */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9B20EE852F4BC12400117DD8 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9B20EF172F60F1DF00117DD8 /* CoreVideo.framework */,
|
||||||
|
9B20EEE12F60D93200117DD8 /* Metal.framework */,
|
||||||
|
9B20EEDF2F60D92300117DD8 /* Cocoa.framework */,
|
||||||
|
9B20EEDD2F60D89F00117DD8 /* Foundation.framework */,
|
||||||
|
9B20EEDB2F60D88D00117DD8 /* QuartzCore.framework */,
|
||||||
|
9B20EED92F60D87E00117DD8 /* IOKit.framework */,
|
||||||
|
9B20EED72F60D86C00117DD8 /* CoreGraphics.framework */,
|
||||||
|
9B20EED42F60D84B00117DD8 /* CoreFoundation.framework */,
|
||||||
|
9B20EEC32F4D141600117DD8 /* libev.a */,
|
||||||
|
9B20EEC12F4D028400117DD8 /* libgnutls.30.dylib */,
|
||||||
|
9B20EE9B2F4BCF7D00117DD8 /* libglfw3.a */,
|
||||||
|
9B20EE972F4BC6C600117DD8 /* libngtcp2.a */,
|
||||||
|
9B20EE952F4BC69100117DD8 /* libwgpu_native.a */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
9B20EE632F4BC09C00117DD8 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE712F4BC0FD00117DD8 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE7B2F4BC11100117DD8 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
9B20EE592F4BBF4800117DD8 /* TestGame */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 9B20EE5E2F4BBF4800117DD8 /* Build configuration list for PBXNativeTarget "TestGame" */;
|
||||||
|
buildPhases = (
|
||||||
|
9B20EE562F4BBF4800117DD8 /* Sources */,
|
||||||
|
9B20EE572F4BBF4800117DD8 /* Frameworks */,
|
||||||
|
9B20EE582F4BBF4800117DD8 /* CopyFiles */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
9B20EE902F4BC56500117DD8 /* PBXTargetDependency */,
|
||||||
|
9B20EE922F4BC56500117DD8 /* PBXTargetDependency */,
|
||||||
|
9B20EE942F4BC56500117DD8 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
9B20EE5B2F4BBF4800117DD8 /* TestGame */,
|
||||||
|
);
|
||||||
|
name = TestGame;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = TestGame;
|
||||||
|
productReference = 9B20EE5A2F4BBF4800117DD8 /* TestGame */;
|
||||||
|
productType = "com.apple.product-type.tool";
|
||||||
|
};
|
||||||
|
9B20EE662F4BC09C00117DD8 /* Client */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 9B20EE682F4BC09C00117DD8 /* Build configuration list for PBXNativeTarget "Client" */;
|
||||||
|
buildPhases = (
|
||||||
|
9B20EE632F4BC09C00117DD8 /* Headers */,
|
||||||
|
9B20EE642F4BC09C00117DD8 /* Sources */,
|
||||||
|
9B20EE652F4BC09C00117DD8 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
9B20EE8E2F4BC55F00117DD8 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = Client;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = Client;
|
||||||
|
productReference = 9B20EE672F4BC09C00117DD8 /* libClient.a */;
|
||||||
|
productType = "com.apple.product-type.library.static";
|
||||||
|
};
|
||||||
|
9B20EE742F4BC0FD00117DD8 /* Server */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 9B20EE762F4BC0FD00117DD8 /* Build configuration list for PBXNativeTarget "Server" */;
|
||||||
|
buildPhases = (
|
||||||
|
9B20EE712F4BC0FD00117DD8 /* Headers */,
|
||||||
|
9B20EE722F4BC0FD00117DD8 /* Sources */,
|
||||||
|
9B20EE732F4BC0FD00117DD8 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
9B20EE8C2F4BC55500117DD8 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = Server;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = Server;
|
||||||
|
productReference = 9B20EE752F4BC0FD00117DD8 /* libServer.a */;
|
||||||
|
productType = "com.apple.product-type.library.static";
|
||||||
|
};
|
||||||
|
9B20EE7E2F4BC11100117DD8 /* Shared */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 9B20EE802F4BC11100117DD8 /* Build configuration list for PBXNativeTarget "Shared" */;
|
||||||
|
buildPhases = (
|
||||||
|
9B20EE7B2F4BC11100117DD8 /* Headers */,
|
||||||
|
9B20EE7C2F4BC11100117DD8 /* Sources */,
|
||||||
|
9B20EE7D2F4BC11100117DD8 /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Shared;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = Shared;
|
||||||
|
productReference = 9B20EE7F2F4BC11100117DD8 /* libShared.a */;
|
||||||
|
productType = "com.apple.product-type.library.static";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
9B20EE292F4BBE9600117DD8 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = 1;
|
||||||
|
LastUpgradeCheck = 1640;
|
||||||
|
TargetAttributes = {
|
||||||
|
9B20EE592F4BBF4800117DD8 = {
|
||||||
|
CreatedOnToolsVersion = 16.4;
|
||||||
|
};
|
||||||
|
9B20EE662F4BC09C00117DD8 = {
|
||||||
|
CreatedOnToolsVersion = 16.4;
|
||||||
|
};
|
||||||
|
9B20EE742F4BC0FD00117DD8 = {
|
||||||
|
CreatedOnToolsVersion = 16.4;
|
||||||
|
};
|
||||||
|
9B20EE7E2F4BC11100117DD8 = {
|
||||||
|
CreatedOnToolsVersion = 16.4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 9B20EE2C2F4BBE9600117DD8 /* Build configuration list for PBXProject "ArtifactEngine" */;
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 9B20EE282F4BBE9600117DD8;
|
||||||
|
minimizedProjectReferenceProxies = 1;
|
||||||
|
preferredProjectObjectVersion = 77;
|
||||||
|
productRefGroup = 9B20EE322F4BBE9600117DD8 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
9B20EE592F4BBF4800117DD8 /* TestGame */,
|
||||||
|
9B20EE662F4BC09C00117DD8 /* Client */,
|
||||||
|
9B20EE742F4BC0FD00117DD8 /* Server */,
|
||||||
|
9B20EE7E2F4BC11100117DD8 /* Shared */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
9B20EE562F4BBF4800117DD8 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE642F4BC09C00117DD8 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE722F4BC0FD00117DD8 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
9B20EE7C2F4BC11100117DD8 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
9B20EE8C2F4BC55500117DD8 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 9B20EE7E2F4BC11100117DD8 /* Shared */;
|
||||||
|
targetProxy = 9B20EE8B2F4BC55500117DD8 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
9B20EE8E2F4BC55F00117DD8 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 9B20EE7E2F4BC11100117DD8 /* Shared */;
|
||||||
|
targetProxy = 9B20EE8D2F4BC55F00117DD8 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
9B20EE902F4BC56500117DD8 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 9B20EE662F4BC09C00117DD8 /* Client */;
|
||||||
|
targetProxy = 9B20EE8F2F4BC56500117DD8 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
9B20EE922F4BC56500117DD8 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 9B20EE742F4BC0FD00117DD8 /* Server */;
|
||||||
|
targetProxy = 9B20EE912F4BC56500117DD8 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
9B20EE942F4BC56500117DD8 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 9B20EE7E2F4BC11100117DD8 /* Shared */;
|
||||||
|
targetProxy = 9B20EE932F4BC56500117DD8 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
9B20EE362F4BBE9600117DD8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
9B20EE372F4BBE9600117DD8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = macosx;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
9B20EE5F2F4BBF4800117DD8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/include",
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Client,
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Server,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
9B20EE602F4BBF4800117DD8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/include",
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Client,
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Server,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
9B20EE692F4BC09C00117DD8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/include",
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/lib",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/lib",
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
9B20EE6A2F4BC09C00117DD8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/include",
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glfw/install/lib",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/webgpu/lib",
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
9B20EE772F4BC0FD00117DD8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
9B20EE782F4BC0FD00117DD8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
/Users/iboettcher/Desktop/misc/ArtifactEngine/Shared,
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
9B20EE812F4BC11100117DD8 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/lib",
|
||||||
|
/Users/iboettcher/homebrew/lib,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
9B20EE822F4BC11100117DD8 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
EXECUTABLE_PREFIX = lib;
|
||||||
|
HEADER_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/include",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps",
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/glm",
|
||||||
|
/Users/iboettcher/homebrew/include,
|
||||||
|
);
|
||||||
|
LIBRARY_SEARCH_PATHS = (
|
||||||
|
"/Users/iboettcher/eclipse-workspace/ArtifactEngine/deps/ngtcp2/install/lib",
|
||||||
|
/Users/iboettcher/homebrew/lib,
|
||||||
|
);
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
9B20EE2C2F4BBE9600117DD8 /* Build configuration list for PBXProject "ArtifactEngine" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9B20EE362F4BBE9600117DD8 /* Debug */,
|
||||||
|
9B20EE372F4BBE9600117DD8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
9B20EE5E2F4BBF4800117DD8 /* Build configuration list for PBXNativeTarget "TestGame" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9B20EE5F2F4BBF4800117DD8 /* Debug */,
|
||||||
|
9B20EE602F4BBF4800117DD8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
9B20EE682F4BC09C00117DD8 /* Build configuration list for PBXNativeTarget "Client" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9B20EE692F4BC09C00117DD8 /* Debug */,
|
||||||
|
9B20EE6A2F4BC09C00117DD8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
9B20EE762F4BC0FD00117DD8 /* Build configuration list for PBXNativeTarget "Server" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9B20EE772F4BC0FD00117DD8 /* Debug */,
|
||||||
|
9B20EE782F4BC0FD00117DD8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
9B20EE802F4BC11100117DD8 /* Build configuration list for PBXNativeTarget "Shared" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
9B20EE812F4BC11100117DD8 /* Debug */,
|
||||||
|
9B20EE822F4BC11100117DD8 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 9B20EE292F4BBE9600117DD8 /* Project object */;
|
||||||
|
}
|
||||||
7
ArtifactEngine.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
ArtifactEngine.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
uuid = "85AB823F-9355-4481-B75D-B26D363783AE"
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
</Bucket>
|
||||||
20
CMakeLists.txt
Normal file
20
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(ArtifactEngine LANGUAGES CXX)
|
||||||
|
|
||||||
|
# MARK: - Options
|
||||||
|
|
||||||
|
option(BUILD_SHARED_LIBS "Build libraries as SHARED instead of STATIC" OFF)
|
||||||
|
option(BUILD_EXAMPLES "Build example/test applications" ON )
|
||||||
|
option(BUILD_TESTS "Build unit tests" OFF)
|
||||||
|
|
||||||
|
# MARK: - Libraries
|
||||||
|
|
||||||
|
add_subdirectory(Shared)
|
||||||
|
add_subdirectory(Client)
|
||||||
|
add_subdirectory(Server)
|
||||||
|
|
||||||
|
# MARK: - Test Game
|
||||||
|
|
||||||
|
if(BUILD_EXAMPLES)
|
||||||
|
add_subdirectory(Examples/TestGame)
|
||||||
|
endif()
|
||||||
6
Client/CMakeLists.txt
Normal file
6
Client/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(Client ${MY_SOURCES})
|
||||||
56
Client/Client.cpp
Normal file
56
Client/Client.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "Client.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "Graphics/UIRenderer.h"
|
||||||
|
#include "Graphics/Graphics.h"
|
||||||
|
#include <Network/Network.h>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void Client::init() {
|
||||||
|
window = subsystem<WindowImpl>();
|
||||||
|
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->client = this;
|
||||||
|
system->init();
|
||||||
|
system->reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::render() {
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::run() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
auto time = std::chrono::steady_clock::now();
|
||||||
|
while (!window->shouldClose()) {
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
if (time - now > std::chrono::milliseconds(50)) {
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::tick() {
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::addDefaultSubsystems() {
|
||||||
|
addSubsystem<Window>(1080, 640, "Artifact Engine");
|
||||||
|
addSubsystem<ClientNetwork>();
|
||||||
|
auto graphics = addSubsystem<Graphics>();
|
||||||
|
{
|
||||||
|
graphics->addSubsystem<UIRenderer>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
40
Client/Client.h
Normal file
40
Client/Client.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Shared.h"
|
||||||
|
#include <Settings.h>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class ClientSubsystem;
|
||||||
|
class WindowImpl;
|
||||||
|
|
||||||
|
/// The client class.
|
||||||
|
class Client: public Engine<ClientSubsystem> {
|
||||||
|
public:
|
||||||
|
WindowImpl * window = nullptr;
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
Client() : settings(getClientConfigPath()) {}
|
||||||
|
|
||||||
|
void addDefaultSubsystems();
|
||||||
|
void initDefault();
|
||||||
|
/// Initializes the client. This includes opening a window, creating a WebGPU device, etc.
|
||||||
|
void init();
|
||||||
|
/// Runs a single iteration of the render loop.
|
||||||
|
void render();
|
||||||
|
/// Runs a single iteration of the tick loop.
|
||||||
|
void tick();
|
||||||
|
/// Runs the client.
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClientSubsystem: public BaseSubsystem {
|
||||||
|
public:
|
||||||
|
Client * client = nullptr;
|
||||||
|
virtual void render() {}
|
||||||
|
virtual void tick() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
7
Client/Graphics/Camera.cpp
Normal file
7
Client/Graphics/Camera.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
24
Client/Graphics/Camera.h
Normal file
24
Client/Graphics/Camera.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
#include <glm/glm/glm.hpp>
|
||||||
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
glm::vec3 pos;
|
||||||
|
glm::quat rot;
|
||||||
|
double fov;
|
||||||
|
float near;
|
||||||
|
float far;
|
||||||
|
|
||||||
|
std::vector<std::type_index> renderPasses;
|
||||||
|
|
||||||
|
Camera(glm::vec3 pos, double fov, float near, float far) : pos(pos), fov(fov), near(near), far(far) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
1
Client/Graphics/ChunkRenderer.cpp
Normal file
1
Client/Graphics/ChunkRenderer.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "ChunkRenderer.h"
|
||||||
22
Client/Graphics/ChunkRenderer.h
Normal file
22
Client/Graphics/ChunkRenderer.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <glm/glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <World/Chunk.h>
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "Graphics.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class ChunkRenderer: public GraphicsSubsystem {
|
||||||
|
std::unordered_map<glm::ivec3, Chunk> chunks;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void render() {
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
7
Client/Graphics/EntityRenderer.cpp
Normal file
7
Client/Graphics/EntityRenderer.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "EntityRenderer.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
12
Client/Graphics/EntityRenderer.h
Normal file
12
Client/Graphics/EntityRenderer.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "Graphics.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class EntityRenderer: public GraphicsSubsystem {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
168
Client/Graphics/Graphics.cpp
Normal file
168
Client/Graphics/Graphics.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
#include "Graphics.h"
|
||||||
|
#include "../Platform/Window.h"
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void Graphics::init() {
|
||||||
|
instance = wgpuCreateInstance(nullptr);
|
||||||
|
|
||||||
|
window = client->subsystem<WindowImpl>();
|
||||||
|
|
||||||
|
surface = window->createWGPUSurface(instance);
|
||||||
|
|
||||||
|
WGPURequestAdapterOptions opts {
|
||||||
|
.compatibleSurface = surface
|
||||||
|
};
|
||||||
|
wgpuInstanceRequestAdapter(instance, &opts, {
|
||||||
|
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||||
|
.callback = [](auto status, auto adapter, auto msg, auto userdata, auto) {
|
||||||
|
if (status == WGPURequestAdapterStatus_Success) {
|
||||||
|
static_cast<Graphics *>(userdata)->adapter = adapter;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Failed to get wgpu adapter.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.userdata1 = this
|
||||||
|
});
|
||||||
|
|
||||||
|
// To avoid dealing with concurrency, we just block until the adapter is available (or the program errors).
|
||||||
|
while (!adapter) wgpuInstanceProcessEvents(instance);
|
||||||
|
|
||||||
|
WGPUDeviceDescriptor desc {
|
||||||
|
.uncapturedErrorCallbackInfo = {
|
||||||
|
.callback = [](auto device, auto type, auto msg, auto, auto) {
|
||||||
|
const char * message = (msg.data ? reinterpret_cast<const char *>(msg.data) : "No message");
|
||||||
|
fprintf(stderr, "Uncaptured WebGPU Error (type %d): %s\n", type, message);
|
||||||
|
}}
|
||||||
|
};
|
||||||
|
wgpuAdapterRequestDevice(adapter, &desc, {
|
||||||
|
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||||
|
.callback = [](auto status, auto device, auto msg, auto userdata, auto) {
|
||||||
|
if (status == WGPURequestDeviceStatus_Success) {
|
||||||
|
static_cast<Graphics *>(userdata)->device = device;
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Failed to get wgpu device.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.userdata1 = this
|
||||||
|
});
|
||||||
|
|
||||||
|
while (!device) wgpuInstanceProcessEvents(instance);
|
||||||
|
|
||||||
|
WGPUTextureDescriptor depthDesc = {};
|
||||||
|
depthDesc.dimension = WGPUTextureDimension_2D;
|
||||||
|
depthDesc.size.width = 1080;
|
||||||
|
depthDesc.size.height = 640;
|
||||||
|
depthDesc.size.depthOrArrayLayers = 1;
|
||||||
|
depthDesc.format = WGPUTextureFormat_Depth32Float;
|
||||||
|
depthDesc.usage = WGPUTextureUsage_RenderAttachment;
|
||||||
|
depthDesc.mipLevelCount = 1;
|
||||||
|
depthDesc.sampleCount = 1;
|
||||||
|
depthTexture = wgpuDeviceCreateTexture(device, &depthDesc);
|
||||||
|
depthTextureView = wgpuTextureCreateView(depthTexture, nullptr);
|
||||||
|
|
||||||
|
queue = wgpuDeviceGetQueue(device);
|
||||||
|
|
||||||
|
WGPUSurfaceConfiguration surfaceConfig = {};
|
||||||
|
surfaceConfig.device = device;
|
||||||
|
surfaceConfig.format = WGPUTextureFormat_BGRA8Unorm; // FIXME: Auto-detect
|
||||||
|
surfaceConfig.usage = WGPUTextureUsage_RenderAttachment;
|
||||||
|
surfaceConfig.width = 1080;
|
||||||
|
surfaceConfig.height = 640;
|
||||||
|
surfaceConfig.presentMode = WGPUPresentMode_Fifo;
|
||||||
|
wgpuSurfaceConfigure(surface, &surfaceConfig);
|
||||||
|
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->graphics = this;
|
||||||
|
printf("Graphics: %p", system->graphics);
|
||||||
|
system->init();
|
||||||
|
system->reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::deinit() {
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
wgpuTextureDestroy(depthTexture);
|
||||||
|
wgpuQueueRelease(queue);
|
||||||
|
wgpuDeviceDestroy(device);
|
||||||
|
wgpuAdapterRelease(adapter);
|
||||||
|
wgpuSurfaceRelease(surface);
|
||||||
|
wgpuInstanceRelease(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Graphics::render() {
|
||||||
|
WGPUSurfaceTexture surfaceTexture;
|
||||||
|
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
|
||||||
|
if (surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_Error || !surfaceTexture.texture) {
|
||||||
|
throw std::runtime_error("Failed to get surface texture");
|
||||||
|
}
|
||||||
|
WGPUTextureView nextTexture = wgpuTextureCreateView(surfaceTexture.texture, nullptr);
|
||||||
|
if (!nextTexture) {
|
||||||
|
throw std::runtime_error("Failed to create texture view");
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUCommandEncoder encoder = wgpuDeviceCreateCommandEncoder(device, nullptr);
|
||||||
|
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->render(nextTexture, encoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUCommandBufferDescriptor cmdBufferDesc = {};
|
||||||
|
cmdBufferDesc.label = WGPUStringView{"Command buffer", WGPU_STRLEN};
|
||||||
|
WGPUCommandBuffer cmdBuffer = wgpuCommandEncoderFinish(encoder, nullptr);
|
||||||
|
wgpuQueueSubmit(queue, 1, &cmdBuffer);
|
||||||
|
#ifndef WASM_BUILD
|
||||||
|
wgpuSurfacePresent(surface);
|
||||||
|
#endif
|
||||||
|
wgpuTextureViewRelease(nextTexture);
|
||||||
|
wgpuTextureRelease(surfaceTexture.texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUTexture Graphics::createTextureFromData(const void* data, uint32_t width, uint32_t height) {
|
||||||
|
WGPUTextureDescriptor textureDesc = {};
|
||||||
|
textureDesc.dimension = WGPUTextureDimension_2D;
|
||||||
|
textureDesc.size.width = width;
|
||||||
|
textureDesc.size.height = height;
|
||||||
|
textureDesc.size.depthOrArrayLayers = 1;
|
||||||
|
textureDesc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
textureDesc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
|
||||||
|
textureDesc.mipLevelCount = 1;
|
||||||
|
textureDesc.sampleCount = 1;
|
||||||
|
auto texture = wgpuDeviceCreateTexture(device, &textureDesc);
|
||||||
|
|
||||||
|
// WGPUTextureViewDescriptor viewDesc = {};
|
||||||
|
// viewDesc.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
// viewDesc.dimension = WGPUTextureViewDimension_2D;
|
||||||
|
// viewDesc.mipLevelCount = 1;
|
||||||
|
// viewDesc.arrayLayerCount = 1;
|
||||||
|
// tex->view = wgpuTextureCreateView(tex->texture, &viewDesc);
|
||||||
|
|
||||||
|
WGPUTexelCopyTextureInfo destination = {};
|
||||||
|
destination.texture = texture;
|
||||||
|
destination.mipLevel = 0;
|
||||||
|
destination.origin = {0, 0, 0};
|
||||||
|
destination.aspect = WGPUTextureAspect_All;
|
||||||
|
WGPUTexelCopyBufferLayout layout = {};
|
||||||
|
layout.offset = 0;
|
||||||
|
layout.bytesPerRow = width * 4;
|
||||||
|
layout.rowsPerImage = height;
|
||||||
|
WGPUExtent3D writeSize = {width, height, 1};
|
||||||
|
wgpuQueueWriteTexture(queue, &destination, data, width * height * 4, &layout, &writeSize);
|
||||||
|
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUTexture Graphics::createTextureFromFile(const char* file) {
|
||||||
|
int width, height, channels;
|
||||||
|
auto data = stbi_load(file, &width, &height, &channels, 4);
|
||||||
|
auto out = createTextureFromData(data, width, height);
|
||||||
|
stbi_image_free(data);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
43
Client/Graphics/Graphics.h
Normal file
43
Client/Graphics/Graphics.h
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "../Client.h"
|
||||||
|
#include "../Platform/Window.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class Graphics;
|
||||||
|
|
||||||
|
class GraphicsSubsystem {
|
||||||
|
public:
|
||||||
|
Graphics * graphics;
|
||||||
|
virtual void init() {}
|
||||||
|
virtual void reload() {}
|
||||||
|
virtual void deinit() {}
|
||||||
|
virtual void render(WGPUTextureView nextTexture, WGPUCommandEncoder encoder) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Graphics: public ClientSubsystem, public Engine<GraphicsSubsystem> {
|
||||||
|
public:
|
||||||
|
WGPUInstance instance = nullptr;
|
||||||
|
WGPUSurface surface = nullptr;
|
||||||
|
WGPUAdapter adapter = nullptr;
|
||||||
|
WGPUDevice device = nullptr;
|
||||||
|
|
||||||
|
WGPUTexture depthTexture = nullptr;
|
||||||
|
WGPUTextureView depthTextureView = nullptr;
|
||||||
|
WGPUQueue queue = nullptr;
|
||||||
|
|
||||||
|
WindowImpl * window;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void deinit() override;
|
||||||
|
void render() override;
|
||||||
|
|
||||||
|
WGPUTexture createTextureFromData(const void* data, uint32_t width, uint32_t height);
|
||||||
|
WGPUTexture createTextureFromFile(const char* file);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
429
Client/Graphics/UIRenderer.cpp
Normal file
429
Client/Graphics/UIRenderer.cpp
Normal file
|
|
@ -0,0 +1,429 @@
|
||||||
|
#include "UIRenderer.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define NK_IMPLEMENTATION
|
||||||
|
#include <nuklear.h>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace Events {
|
||||||
|
|
||||||
|
struct DrawUI {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::array<nk_keys, static_cast<size_t>(Key::Last) + 1> ArtifactToNuklear {};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
static struct _nkInit {
|
||||||
|
_nkInit() {
|
||||||
|
// Populate the Artifact-to-Nuklear key map.
|
||||||
|
#define X(nuklear, artifact) ArtifactToNuklear[static_cast<int>(Key::artifact)] = nuklear
|
||||||
|
X(NK_KEY_CTRL, ControlLeft);
|
||||||
|
X(NK_KEY_CTRL, ControlRight);
|
||||||
|
|
||||||
|
X(NK_KEY_SHIFT, ShiftLeft);
|
||||||
|
X(NK_KEY_SHIFT, ShiftRight);
|
||||||
|
|
||||||
|
X(NK_KEY_ENTER, Enter);
|
||||||
|
|
||||||
|
X(NK_KEY_BACKSPACE, DeleteBackward);
|
||||||
|
X(NK_KEY_DEL, DeleteForward);
|
||||||
|
|
||||||
|
X(NK_KEY_LEFT, ArrowLeft);
|
||||||
|
X(NK_KEY_RIGHT, ArrowRight);
|
||||||
|
X(NK_KEY_UP, ArrowUp);
|
||||||
|
X(NK_KEY_DOWN, ArrowDown);
|
||||||
|
|
||||||
|
X(NK_KEY_TAB, Tab);
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
} __nkInit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void UIRenderer::init() {
|
||||||
|
printf("UI: %p", graphics);
|
||||||
|
|
||||||
|
graphics->window->listen<Events::InputBegin>([this](auto ev) {
|
||||||
|
nk_input_begin(&ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::InputEnd>([this](auto ev) {
|
||||||
|
nk_input_end(&ctx);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::CursorPosEvent>([this](auto ev) {
|
||||||
|
nk_input_motion(&ctx, ev.x, ev.y);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::ScrollEvent>([this](auto ev) {
|
||||||
|
nk_input_scroll(&ctx, nk_vec2(ev.dx, ev.dy));
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::MouseEvent>([this](auto ev) {
|
||||||
|
nk_input_button(&ctx, ev.button == Events::MOUSE_BUTTON_RIGHT ? NK_BUTTON_RIGHT : NK_BUTTON_LEFT, (int)ev.x, (int)ev.y, ev.state);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::KeyDownEvent>([this](auto ev) {
|
||||||
|
nk_input_key(&ctx, ArtifactToNuklear[static_cast<int>(ev.key)], true);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::KeyUpEvent>([this](auto ev) {
|
||||||
|
nk_input_key(&ctx, ArtifactToNuklear[static_cast<int>(ev.key)], false);
|
||||||
|
});
|
||||||
|
|
||||||
|
graphics->window->listen<Events::CharInputEvent>([this](auto ev) {
|
||||||
|
nk_input_char(&ctx, ev.codepoint);
|
||||||
|
});
|
||||||
|
|
||||||
|
nk_init_default(&ctx, nullptr);
|
||||||
|
|
||||||
|
nk_font_atlas_init_default(&atlas);
|
||||||
|
nk_font_atlas_begin(&atlas);
|
||||||
|
|
||||||
|
nk_font* font;
|
||||||
|
void* fontData = nullptr;
|
||||||
|
|
||||||
|
// FIXME: Automatic path resolution
|
||||||
|
std::string assetPath = std::string(getenv("HOME")) + "/eclipse-workspace/ArtifactEngine/assets";
|
||||||
|
|
||||||
|
FILE* fontFile = fopen((assetPath + "/fonts/Arial.ttf").c_str(), "rb");
|
||||||
|
if (fontFile) {
|
||||||
|
fseek(fontFile, 0, SEEK_END);
|
||||||
|
long fontSize = ftell(fontFile);
|
||||||
|
fseek(fontFile, 0, SEEK_SET);
|
||||||
|
fontData = malloc(fontSize);
|
||||||
|
fread(fontData, 1, fontSize, fontFile);
|
||||||
|
fclose(fontFile);
|
||||||
|
font = nk_font_atlas_add_from_memory(&atlas, fontData, fontSize, 13.0f, nullptr);
|
||||||
|
} else {
|
||||||
|
font = nk_font_atlas_add_default(&atlas, 13.0f, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fontWidth, fontHeight;
|
||||||
|
const void* fontImage = nk_font_atlas_bake(&atlas, &fontWidth, &fontHeight, NK_FONT_ATLAS_RGBA32);
|
||||||
|
fontTexture = graphics->createTextureFromData(fontImage, fontWidth, fontHeight);
|
||||||
|
fontTextureView = wgpuTextureCreateView(fontTexture, nullptr);
|
||||||
|
nk_font_atlas_end(&atlas, nk_handle_id(0), nullptr);
|
||||||
|
nk_style_set_font(&ctx, &font->handle);
|
||||||
|
if (fontData) free(fontData);
|
||||||
|
|
||||||
|
unsigned char whitePixel[4] = {255, 255, 255, 255};
|
||||||
|
dummyTexture = graphics->createTextureFromData(whitePixel, 1, 1);
|
||||||
|
dummyTextureView = wgpuTextureCreateView(dummyTexture, nullptr);
|
||||||
|
|
||||||
|
nk_buffer_init_default(&vertexBufferNK);
|
||||||
|
nk_buffer_init_default(&indexBufferNK);
|
||||||
|
nk_buffer_init_default(&commandBufferNK);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct NKVertex {
|
||||||
|
float pos[2];
|
||||||
|
float uv[2];
|
||||||
|
uint8_t color[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
void UIRenderer::reload() {
|
||||||
|
WGPUBufferDescriptor uiVertexBufferDesc = {};
|
||||||
|
uiVertexBufferDesc.size = 1024 * 1024 * sizeof(NKVertex);
|
||||||
|
uiVertexBufferDesc.usage = WGPUBufferUsage_Vertex | WGPUBufferUsage_CopyDst;
|
||||||
|
uiVertexBufferDesc.label = WGPUStringView{"UI Vertex Buffer", WGPU_STRLEN};
|
||||||
|
vertexBuffer = wgpuDeviceCreateBuffer(graphics->device, &uiVertexBufferDesc);
|
||||||
|
|
||||||
|
WGPUBufferDescriptor uiIndexBufferDesc = {};
|
||||||
|
uiIndexBufferDesc.size = 1024 * 1024 * sizeof(uint16_t);
|
||||||
|
uiIndexBufferDesc.usage = WGPUBufferUsage_Index | WGPUBufferUsage_CopyDst;
|
||||||
|
uiIndexBufferDesc.label = WGPUStringView{"UI Index Buffer", WGPU_STRLEN};
|
||||||
|
indexBuffer = wgpuDeviceCreateBuffer(graphics->device, &uiIndexBufferDesc);
|
||||||
|
|
||||||
|
WGPUBufferDescriptor uiUniformBufferDesc = {};
|
||||||
|
uiUniformBufferDesc.size = sizeof(glm::mat4);
|
||||||
|
uiUniformBufferDesc.usage = WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst;
|
||||||
|
uiUniformBufferDesc.label = WGPUStringView{"UI Uniform Buffer", WGPU_STRLEN};
|
||||||
|
uniformBuffer = wgpuDeviceCreateBuffer(graphics->device, &uiUniformBufferDesc);
|
||||||
|
|
||||||
|
std::string uiVSCode = R"(
|
||||||
|
struct Uniforms {
|
||||||
|
ortho: mat4x4<f32>,
|
||||||
|
}
|
||||||
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) pos: vec4<f32>,
|
||||||
|
@location(0) uv: vec2<f32>,
|
||||||
|
@location(1) color: vec4<f32>,
|
||||||
|
}
|
||||||
|
@vertex
|
||||||
|
fn vs_main(@location(0) pos: vec2<f32>, @location(1) uv: vec2<f32>, @location(2) color: vec4<f32>) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.pos = uniforms.ortho * vec4<f32>(pos, 0.0, 1.0);
|
||||||
|
out.uv = uv;
|
||||||
|
out.color = color;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
std::string uiFSCode = R"(
|
||||||
|
@group(0) @binding(1) var texture: texture_2d<f32>;
|
||||||
|
@group(0) @binding(2) var sampler_: sampler;
|
||||||
|
@fragment
|
||||||
|
fn fs_main(@location(0) uv: vec2<f32>, @location(1) color: vec4<f32>) -> @location(0) vec4<f32> {
|
||||||
|
return textureSample(texture, sampler_, uv) * color;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
WGPUShaderModuleDescriptor uiVSDesc = {};
|
||||||
|
WGPUShaderSourceWGSL src = {.code = WGPUStringView{uiVSCode.c_str(), uiVSCode.size()}};
|
||||||
|
src.chain.sType = WGPUSType_ShaderSourceWGSL;
|
||||||
|
uiVSDesc.nextInChain = &src.chain;
|
||||||
|
WGPUShaderModule uiVSModule = wgpuDeviceCreateShaderModule(graphics->device, &uiVSDesc);
|
||||||
|
|
||||||
|
WGPUShaderModuleDescriptor uiFSDesc = {};
|
||||||
|
src = {.code = WGPUStringView{uiFSCode.c_str(), uiFSCode.size()}};
|
||||||
|
src.chain.sType = WGPUSType_ShaderSourceWGSL;
|
||||||
|
uiFSDesc.nextInChain = &src.chain;
|
||||||
|
WGPUShaderModule uiFSModule = wgpuDeviceCreateShaderModule(graphics->device, &uiFSDesc);
|
||||||
|
|
||||||
|
WGPUSamplerDescriptor uiSamplerDesc = {};
|
||||||
|
uiSamplerDesc.addressModeU = WGPUAddressMode_ClampToEdge;
|
||||||
|
uiSamplerDesc.addressModeV = WGPUAddressMode_ClampToEdge;
|
||||||
|
uiSamplerDesc.addressModeW = WGPUAddressMode_ClampToEdge;
|
||||||
|
uiSamplerDesc.magFilter = WGPUFilterMode_Linear;
|
||||||
|
uiSamplerDesc.minFilter = WGPUFilterMode_Linear;
|
||||||
|
uiSamplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
|
||||||
|
uiSamplerDesc.maxAnisotropy = 1;
|
||||||
|
sampler = wgpuDeviceCreateSampler(graphics->device, &uiSamplerDesc);
|
||||||
|
if (!sampler) {
|
||||||
|
throw std::runtime_error("Failed to create UI sampler");
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutEntry uiBglEntries[3] = {};
|
||||||
|
uiBglEntries[0].binding = 0;
|
||||||
|
uiBglEntries[0].visibility = WGPUShaderStage_Vertex;
|
||||||
|
uiBglEntries[0].buffer.type = WGPUBufferBindingType_Uniform;
|
||||||
|
uiBglEntries[1].binding = 1;
|
||||||
|
uiBglEntries[1].visibility = WGPUShaderStage_Fragment;
|
||||||
|
uiBglEntries[1].texture.sampleType = WGPUTextureSampleType_Float;
|
||||||
|
uiBglEntries[1].texture.viewDimension = WGPUTextureViewDimension_2D;
|
||||||
|
uiBglEntries[2].binding = 2;
|
||||||
|
uiBglEntries[2].visibility = WGPUShaderStage_Fragment;
|
||||||
|
uiBglEntries[2].sampler.type = WGPUSamplerBindingType_Filtering;
|
||||||
|
|
||||||
|
WGPUBindGroupLayoutDescriptor uiBglDesc = {};
|
||||||
|
uiBglDesc.entryCount = 3;
|
||||||
|
uiBglDesc.entries = uiBglEntries;
|
||||||
|
bgl = wgpuDeviceCreateBindGroupLayout(graphics->device, &uiBglDesc);
|
||||||
|
if (!bgl) {
|
||||||
|
throw std::runtime_error("Failed to create bind group layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUVertexAttribute uiAttributes[3] = {};
|
||||||
|
uiAttributes[0].format = WGPUVertexFormat_Float32x2;
|
||||||
|
uiAttributes[0].offset = offsetof(NKVertex, pos);
|
||||||
|
uiAttributes[0].shaderLocation = 0;
|
||||||
|
uiAttributes[1].format = WGPUVertexFormat_Float32x2;
|
||||||
|
uiAttributes[1].offset = offsetof(NKVertex, uv);
|
||||||
|
uiAttributes[1].shaderLocation = 1;
|
||||||
|
uiAttributes[2].format = WGPUVertexFormat_Unorm8x4;
|
||||||
|
uiAttributes[2].offset = offsetof(NKVertex, color);
|
||||||
|
uiAttributes[2].shaderLocation = 2;
|
||||||
|
|
||||||
|
WGPUVertexBufferLayout uiVBLayout = {};
|
||||||
|
uiVBLayout.arrayStride = sizeof(NKVertex);
|
||||||
|
uiVBLayout.stepMode = WGPUVertexStepMode_Vertex;
|
||||||
|
uiVBLayout.attributeCount = 3;
|
||||||
|
uiVBLayout.attributes = uiAttributes;
|
||||||
|
|
||||||
|
WGPUBlendState uiBlendState = {};
|
||||||
|
uiBlendState.color.srcFactor = WGPUBlendFactor_SrcAlpha;
|
||||||
|
uiBlendState.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
uiBlendState.color.operation = WGPUBlendOperation_Add;
|
||||||
|
uiBlendState.alpha.srcFactor = WGPUBlendFactor_One;
|
||||||
|
uiBlendState.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha;
|
||||||
|
uiBlendState.alpha.operation = WGPUBlendOperation_Add;
|
||||||
|
|
||||||
|
WGPUColorTargetState uiColorTarget = {};
|
||||||
|
uiColorTarget.format = WGPUTextureFormat_BGRA8Unorm;
|
||||||
|
uiColorTarget.blend = &uiBlendState;
|
||||||
|
uiColorTarget.writeMask = WGPUColorWriteMask_All;
|
||||||
|
|
||||||
|
WGPUFragmentState uiFragmentState = {};
|
||||||
|
uiFragmentState.module = uiFSModule;
|
||||||
|
uiFragmentState.entryPoint = WGPUStringView{"fs_main", WGPU_STRLEN};
|
||||||
|
uiFragmentState.targetCount = 1;
|
||||||
|
uiFragmentState.targets = &uiColorTarget;
|
||||||
|
|
||||||
|
WGPUPipelineLayoutDescriptor uiPlDesc = {};
|
||||||
|
uiPlDesc.bindGroupLayoutCount = 1;
|
||||||
|
uiPlDesc.bindGroupLayouts = &bgl;
|
||||||
|
WGPUPipelineLayout uiPipelineLayout = wgpuDeviceCreatePipelineLayout(graphics->device, &uiPlDesc);
|
||||||
|
|
||||||
|
WGPURenderPipelineDescriptor uiPipelineDesc = {};
|
||||||
|
uiPipelineDesc.vertex.module = uiVSModule;
|
||||||
|
uiPipelineDesc.vertex.entryPoint = WGPUStringView{"vs_main", WGPU_STRLEN};
|
||||||
|
uiPipelineDesc.vertex.bufferCount = 1;
|
||||||
|
uiPipelineDesc.vertex.buffers = &uiVBLayout;
|
||||||
|
uiPipelineDesc.fragment = &uiFragmentState;
|
||||||
|
uiPipelineDesc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
|
||||||
|
uiPipelineDesc.primitive.frontFace = WGPUFrontFace_CCW;
|
||||||
|
uiPipelineDesc.primitive.cullMode = WGPUCullMode_None;
|
||||||
|
uiPipelineDesc.layout = uiPipelineLayout;
|
||||||
|
uiPipelineDesc.multisample.count = 1;
|
||||||
|
uiPipelineDesc.multisample.mask = ~0u;
|
||||||
|
|
||||||
|
pipeline = wgpuDeviceCreateRenderPipeline(graphics->device, &uiPipelineDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string txt = "Test";
|
||||||
|
int _txt = 0;
|
||||||
|
|
||||||
|
void UIRenderer::render(WGPUTextureView nextTexture, WGPUCommandEncoder encoder) {
|
||||||
|
if (nk_begin(&ctx, "Test", nk_rect(10, 10, 100, 100), NK_WINDOW_TITLE | NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)) {
|
||||||
|
nk_layout_row_dynamic(&ctx, 50, 2);
|
||||||
|
nk_label(&ctx, "Test", 0);
|
||||||
|
nk_button_label(&ctx, "Test");
|
||||||
|
|
||||||
|
nk_layout_row_dynamic(&ctx, 50, 2);
|
||||||
|
nk_label(&ctx, "Test", 0);
|
||||||
|
nk_button_label(&ctx, "Test");
|
||||||
|
|
||||||
|
nk_layout_row_dynamic(&ctx, 50, 1);
|
||||||
|
nk_edit_string(&ctx, NK_EDIT_BOX, txt.data(), &_txt, 100, nk_filter_ascii);
|
||||||
|
|
||||||
|
if (nk_contextual_begin(&ctx, NK_PANEL_CONTEXTUAL, nk_vec2(100, 100), nk_rect(10, 10, 100, 100))) {
|
||||||
|
nk_layout_row_dynamic(&ctx, 25, 1);
|
||||||
|
nk_contextual_item_label(&ctx, "Button", NK_TEXT_CENTERED);
|
||||||
|
nk_contextual_end(&ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nk_end(&ctx);
|
||||||
|
|
||||||
|
dispatch(Events::DrawUI {});
|
||||||
|
|
||||||
|
nk_buffer_clear(&vertexBufferNK);
|
||||||
|
nk_buffer_clear(&indexBufferNK);
|
||||||
|
nk_buffer_clear(&commandBufferNK);
|
||||||
|
struct nk_convert_config config = {};
|
||||||
|
static const struct nk_draw_vertex_layout_element vertex_layout[] = {
|
||||||
|
{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(NKVertex, pos)},
|
||||||
|
{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(NKVertex, uv)},
|
||||||
|
{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(NKVertex, color)},
|
||||||
|
{NK_VERTEX_LAYOUT_END}
|
||||||
|
};
|
||||||
|
config.vertex_layout = vertex_layout;
|
||||||
|
config.vertex_size = sizeof(NKVertex);
|
||||||
|
config.vertex_alignment = alignof(NKVertex);
|
||||||
|
config.tex_null.texture = nk_handle_id(0);
|
||||||
|
config.tex_null.uv = {0.0f, 0.0f};
|
||||||
|
config.circle_segment_count = 22;
|
||||||
|
config.curve_segment_count = 22;
|
||||||
|
config.arc_segment_count = 22;
|
||||||
|
config.global_alpha = 1.0f;
|
||||||
|
config.shape_AA = NK_ANTI_ALIASING_ON;
|
||||||
|
config.line_AA = NK_ANTI_ALIASING_ON;
|
||||||
|
nk_convert(&ctx, &commandBufferNK, &vertexBufferNK, &indexBufferNK, &config);
|
||||||
|
|
||||||
|
// FIXME: Variable size
|
||||||
|
int viewportWidth = 1080;
|
||||||
|
int viewportHeight = 640;
|
||||||
|
|
||||||
|
auto ortho = glm::ortho(0.0f, (float)viewportWidth, (float)viewportHeight, 0.0f, -1.0f, 1.0f);
|
||||||
|
wgpuQueueWriteBuffer(graphics->queue, uniformBuffer, 0, &ortho, sizeof(ortho));
|
||||||
|
|
||||||
|
WGPURenderPassColorAttachment colorAttachment = {};
|
||||||
|
colorAttachment.view = nextTexture;
|
||||||
|
colorAttachment.loadOp = WGPULoadOp_Load;
|
||||||
|
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||||
|
colorAttachment.clearValue = {0, 0.2, 0.4, 1};
|
||||||
|
colorAttachment.depthSlice = -1;
|
||||||
|
|
||||||
|
WGPURenderPassDepthStencilAttachment depthAttachment = {};
|
||||||
|
depthAttachment.view = graphics->depthTextureView;
|
||||||
|
depthAttachment.depthLoadOp = WGPULoadOp_Clear;
|
||||||
|
depthAttachment.depthStoreOp = WGPUStoreOp_Store;
|
||||||
|
depthAttachment.depthClearValue = 1.0f;
|
||||||
|
depthAttachment.depthReadOnly = false;
|
||||||
|
depthAttachment.stencilLoadOp = WGPULoadOp_Undefined;
|
||||||
|
depthAttachment.stencilStoreOp = WGPUStoreOp_Undefined;
|
||||||
|
|
||||||
|
WGPURenderPassDescriptor renderPassDesc = {};
|
||||||
|
renderPassDesc.colorAttachmentCount = 1;
|
||||||
|
renderPassDesc.colorAttachments = &colorAttachment;
|
||||||
|
renderPassDesc.depthStencilAttachment = &depthAttachment;
|
||||||
|
|
||||||
|
colorAttachment.loadOp = WGPULoadOp_Load;
|
||||||
|
WGPURenderPassDescriptor uiRenderPassDesc = {};
|
||||||
|
uiRenderPassDesc.colorAttachmentCount = 1;
|
||||||
|
uiRenderPassDesc.colorAttachments = &colorAttachment;
|
||||||
|
|
||||||
|
WGPURenderPassEncoder uiRenderPass = wgpuCommandEncoderBeginRenderPass(encoder, &uiRenderPassDesc);
|
||||||
|
wgpuRenderPassEncoderSetPipeline(uiRenderPass, pipeline);
|
||||||
|
wgpuRenderPassEncoderSetViewport(uiRenderPass, 0, 0, (float)viewportWidth, (float)viewportHeight, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
|
||||||
|
size_t vertexSize = nk_buffer_total(&vertexBufferNK);
|
||||||
|
size_t indexSize = nk_buffer_total(&indexBufferNK);
|
||||||
|
if (vertexSize > 0 && indexSize > 0) {
|
||||||
|
wgpuQueueWriteBuffer(graphics->queue, vertexBuffer, 0, vertexBufferNK.memory.ptr, vertexSize);
|
||||||
|
wgpuQueueWriteBuffer(graphics->queue, indexBuffer, 0, indexBufferNK.memory.ptr, indexSize);
|
||||||
|
|
||||||
|
wgpuRenderPassEncoderSetVertexBuffer(uiRenderPass, 0, vertexBuffer, 0, vertexSize);
|
||||||
|
wgpuRenderPassEncoderSetIndexBuffer(uiRenderPass, indexBuffer, WGPUIndexFormat_Uint16, 0, indexSize);
|
||||||
|
|
||||||
|
std::vector<WGPUBindGroup> bindGroups;
|
||||||
|
WGPUBindGroupEntry uiBgEntries[3] = {};
|
||||||
|
uiBgEntries[0].binding = 0;
|
||||||
|
uiBgEntries[0].buffer = uniformBuffer;
|
||||||
|
uiBgEntries[0].offset = 0;
|
||||||
|
uiBgEntries[0].size = sizeof(glm::mat4);
|
||||||
|
uiBgEntries[2].binding = 2;
|
||||||
|
uiBgEntries[2].sampler = sampler;
|
||||||
|
|
||||||
|
std::unordered_map<int, WGPUTextureView> textureMap = {{0, fontTextureView}};
|
||||||
|
const struct nk_draw_command* cmd;
|
||||||
|
uint32_t offset = 0;
|
||||||
|
nk_draw_foreach(cmd, &ctx, &commandBufferNK) {
|
||||||
|
if (!cmd->elem_count) continue;
|
||||||
|
if (offset + cmd->elem_count > indexSize / sizeof(uint16_t)) break;
|
||||||
|
|
||||||
|
uint32_t scissorX = static_cast<uint32_t>(cmd->clip_rect.x < 0 ? 0 : cmd->clip_rect.x);
|
||||||
|
uint32_t scissorY = static_cast<uint32_t>(cmd->clip_rect.y < 0 ? 0 : cmd->clip_rect.y);
|
||||||
|
uint32_t scissorW = static_cast<uint32_t>(cmd->clip_rect.w);
|
||||||
|
uint32_t scissorH = static_cast<uint32_t>(cmd->clip_rect.h);
|
||||||
|
scissorX = std::min(scissorX, (uint32_t)viewportWidth - 1);
|
||||||
|
scissorY = std::min(scissorY, (uint32_t)viewportHeight - 1);
|
||||||
|
if (scissorW > viewportWidth || scissorH > viewportHeight || scissorX + scissorW > viewportWidth || scissorY + scissorH > viewportHeight) {
|
||||||
|
scissorW = std::min(scissorW, viewportWidth - scissorX);
|
||||||
|
scissorH = std::min(scissorH, viewportHeight - scissorY);
|
||||||
|
}
|
||||||
|
wgpuRenderPassEncoderSetScissorRect(uiRenderPass, scissorX, scissorY, scissorW, scissorH);
|
||||||
|
|
||||||
|
uiBgEntries[1].binding = 1;
|
||||||
|
uiBgEntries[1].textureView = cmd->texture.id >= 0 && textureMap.count(cmd->texture.id) ? textureMap[cmd->texture.id] : dummyTextureView;
|
||||||
|
|
||||||
|
WGPUBindGroupDescriptor uiBgDesc = {};
|
||||||
|
uiBgDesc.layout = bgl;
|
||||||
|
uiBgDesc.entryCount = 3;
|
||||||
|
uiBgDesc.entries = uiBgEntries;
|
||||||
|
|
||||||
|
WGPUBindGroup uiDynamicBindGroup = wgpuDeviceCreateBindGroup(graphics->device, &uiBgDesc);
|
||||||
|
bindGroups.push_back(uiDynamicBindGroup);
|
||||||
|
|
||||||
|
wgpuRenderPassEncoderSetBindGroup(uiRenderPass, 0, uiDynamicBindGroup, 0, nullptr);
|
||||||
|
wgpuRenderPassEncoderDrawIndexed(uiRenderPass, cmd->elem_count, 1, offset, 0, 0);
|
||||||
|
|
||||||
|
offset += cmd->elem_count;
|
||||||
|
}
|
||||||
|
wgpuRenderPassEncoderEnd(uiRenderPass);
|
||||||
|
for (WGPUBindGroup bg : bindGroups) wgpuBindGroupRelease(bg);
|
||||||
|
} else {
|
||||||
|
wgpuRenderPassEncoderEnd(uiRenderPass);
|
||||||
|
}
|
||||||
|
|
||||||
|
nk_clear(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
46
Client/Graphics/UIRenderer.h
Normal file
46
Client/Graphics/UIRenderer.h
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define NK_INCLUDE_FIXED_TYPES
|
||||||
|
#define NK_INCLUDE_STANDARD_IO
|
||||||
|
#define NK_INCLUDE_STANDARD_VARARGS
|
||||||
|
#define NK_INCLUDE_DEFAULT_ALLOCATOR
|
||||||
|
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
|
||||||
|
#define NK_INCLUDE_FONT_BAKING
|
||||||
|
#define NK_INCLUDE_DEFAULT_FONT
|
||||||
|
#include <nuklear.h>
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "Graphics.h"
|
||||||
|
#include "../Platform/Window.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class UIRenderer: public GraphicsSubsystem, public EventTarget {
|
||||||
|
nk_context ctx {};
|
||||||
|
nk_font_atlas atlas {};
|
||||||
|
|
||||||
|
WGPURenderPipeline pipeline = nullptr;
|
||||||
|
|
||||||
|
WGPUBuffer vertexBuffer = nullptr;
|
||||||
|
WGPUBuffer indexBuffer = nullptr;
|
||||||
|
WGPUBuffer uniformBuffer = nullptr;
|
||||||
|
WGPUSampler sampler = nullptr;
|
||||||
|
WGPUBindGroupLayout bgl = nullptr;
|
||||||
|
WGPUTexture fontTexture = nullptr;
|
||||||
|
WGPUTextureView fontTextureView = nullptr;
|
||||||
|
WGPUTexture dummyTexture = nullptr;
|
||||||
|
WGPUTextureView dummyTextureView = nullptr;
|
||||||
|
|
||||||
|
nk_buffer vertexBufferNK;
|
||||||
|
nk_buffer indexBufferNK;
|
||||||
|
nk_buffer commandBufferNK;
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void reload() override;
|
||||||
|
void render(WGPUTextureView nextTexture, WGPUCommandEncoder encoder) override;
|
||||||
|
|
||||||
|
WGPURenderPipeline makePipeline();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
1
Client/Graphics/WorldRenderer.cpp
Normal file
1
Client/Graphics/WorldRenderer.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "WorldRenderer.h"
|
||||||
11
Client/Graphics/WorldRenderer.h
Normal file
11
Client/Graphics/WorldRenderer.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class WorldRenderer {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
17
Client/LocalPlayer.cpp
Normal file
17
Client/LocalPlayer.cpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#include "LocalPlayer.h"
|
||||||
|
|
||||||
|
#include "Platform/Window.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void LocalPlayer::init() {
|
||||||
|
window = client->subsystem<WindowImpl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalPlayer::tick() {
|
||||||
|
if (window->isKeyDown(Key::W)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
26
Client/LocalPlayer.h
Normal file
26
Client/LocalPlayer.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "Client.h"
|
||||||
|
#include "Graphics/Camera.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class LocalPlayerImpl: public ClientSubsystem {
|
||||||
|
public:
|
||||||
|
std::unique_ptr<Camera> camera = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LocalPlayer: public LocalPlayerImpl {
|
||||||
|
WindowImpl * window = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LocalPlayer() {
|
||||||
|
//camera = std::make_unique<Camera>(glm::vec3(0, 0, 0), 75);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() override;
|
||||||
|
void tick() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
11
Client/Network.h
Normal file
11
Client/Network.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Client.h"
|
||||||
|
#include <Network/Network.h>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class ClientNetwork: public NetworkClient, public ClientSubsystem {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
12
Client/Platform/Keybinds.cpp
Normal file
12
Client/Platform/Keybinds.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include "Keybinds.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace Keybinds {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
13
Client/Platform/Keybinds.h
Normal file
13
Client/Platform/Keybinds.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace Keybinds {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
177
Client/Platform/Window.cpp
Normal file
177
Client/Platform/Window.cpp
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "Window.h"
|
||||||
|
#include "glfw3webgpu/glfw3webgpu.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
static std::array<Key, GLFW_KEY_LAST + 1> GLFWToArtifact {};
|
||||||
|
static std::array<int, static_cast<size_t>(Key::Last) + 1> ArtifactToGLFW {};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// Ensure that GLFW is transparently initialized prior to window creation.
|
||||||
|
static struct _glfwInit {
|
||||||
|
_glfwInit() {
|
||||||
|
if(!glfwInit()) throw std::runtime_error("Failed to initialize GLFW.");
|
||||||
|
|
||||||
|
// Populate the global GLFW-to-Artifact keycode mapping.
|
||||||
|
GLFWToArtifact.fill(Key::Unknown);
|
||||||
|
#define X(glfw, artifact) GLFWToArtifact[glfw] = Key::artifact;\
|
||||||
|
ArtifactToGLFW[static_cast<int>(Key::artifact)] = glfw
|
||||||
|
X(GLFW_KEY_A, A);
|
||||||
|
X(GLFW_KEY_B, B);
|
||||||
|
X(GLFW_KEY_C, C);
|
||||||
|
X(GLFW_KEY_D, D);
|
||||||
|
X(GLFW_KEY_E, E);
|
||||||
|
X(GLFW_KEY_F, F);
|
||||||
|
X(GLFW_KEY_G, G);
|
||||||
|
X(GLFW_KEY_H, H);
|
||||||
|
X(GLFW_KEY_I, I);
|
||||||
|
X(GLFW_KEY_J, J);
|
||||||
|
X(GLFW_KEY_K, K);
|
||||||
|
X(GLFW_KEY_L, L);
|
||||||
|
X(GLFW_KEY_M, M);
|
||||||
|
X(GLFW_KEY_N, N);
|
||||||
|
X(GLFW_KEY_O, O);
|
||||||
|
X(GLFW_KEY_P, P);
|
||||||
|
X(GLFW_KEY_Q, Q);
|
||||||
|
X(GLFW_KEY_R, R);
|
||||||
|
X(GLFW_KEY_S, S);
|
||||||
|
X(GLFW_KEY_T, T);
|
||||||
|
X(GLFW_KEY_U, U);
|
||||||
|
X(GLFW_KEY_V, V);
|
||||||
|
X(GLFW_KEY_W, W);
|
||||||
|
X(GLFW_KEY_X, X);
|
||||||
|
X(GLFW_KEY_Y, Y);
|
||||||
|
X(GLFW_KEY_Z, Z);
|
||||||
|
|
||||||
|
X(GLFW_KEY_0, Zero);
|
||||||
|
X(GLFW_KEY_1, One);
|
||||||
|
X(GLFW_KEY_2, Two);
|
||||||
|
X(GLFW_KEY_3, Three);
|
||||||
|
X(GLFW_KEY_4, Four);
|
||||||
|
X(GLFW_KEY_5, Five);
|
||||||
|
X(GLFW_KEY_6, Six);
|
||||||
|
X(GLFW_KEY_7, Seven);
|
||||||
|
X(GLFW_KEY_8, Eight);
|
||||||
|
X(GLFW_KEY_9, Nine);
|
||||||
|
|
||||||
|
X(GLFW_KEY_ENTER, Enter);
|
||||||
|
|
||||||
|
X(GLFW_KEY_LEFT_SHIFT, ShiftLeft);
|
||||||
|
X(GLFW_KEY_RIGHT_SHIFT, ShiftRight);
|
||||||
|
|
||||||
|
X(GLFW_KEY_LEFT_CONTROL, ControlLeft);
|
||||||
|
X(GLFW_KEY_RIGHT_CONTROL, ControlRight);
|
||||||
|
|
||||||
|
X(GLFW_KEY_LEFT_ALT, OptionLeft);
|
||||||
|
X(GLFW_KEY_RIGHT_ALT, OptionRight);
|
||||||
|
|
||||||
|
X(GLFW_KEY_LEFT_SUPER, CommandLeft);
|
||||||
|
X(GLFW_KEY_RIGHT_SUPER, CommandRight);
|
||||||
|
|
||||||
|
X(GLFW_KEY_BACKSPACE, DeleteBackward);
|
||||||
|
X(GLFW_KEY_DELETE, DeleteForward);
|
||||||
|
|
||||||
|
X(GLFW_KEY_LEFT, ArrowLeft);
|
||||||
|
X(GLFW_KEY_RIGHT, ArrowRight);
|
||||||
|
X(GLFW_KEY_UP, ArrowUp);
|
||||||
|
X(GLFW_KEY_DOWN, ArrowDown);
|
||||||
|
|
||||||
|
X(GLFW_KEY_TAB, Tab);
|
||||||
|
#undef X
|
||||||
|
}
|
||||||
|
|
||||||
|
~_glfwInit() {
|
||||||
|
glfwTerminate();
|
||||||
|
}
|
||||||
|
} __glfwInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
Window::Window(uint32_t width, uint32_t height, std::string title) {
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
window = glfwCreateWindow(width, height, "", nullptr, nullptr);
|
||||||
|
glfwSetWindowUserPointer(window, this);
|
||||||
|
|
||||||
|
glfwSetCursorPosCallback(window, [](auto window, auto x, auto y) {
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::CursorPosEvent {
|
||||||
|
.x = x,
|
||||||
|
.y = y
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwSetMouseButtonCallback(window, [](auto window, auto button, auto action, auto mods) {
|
||||||
|
Events::MouseButton myButton = Events::MOUSE_BUTTON_LEFT;
|
||||||
|
if (button == GLFW_MOUSE_BUTTON_2) {
|
||||||
|
myButton = Events::MOUSE_BUTTON_RIGHT;
|
||||||
|
} else if (button == GLFW_MOUSE_BUTTON_3) {
|
||||||
|
myButton = Events::MOUSE_BUTTON_MIDDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
glfwGetCursorPos(window, &x, &y);
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::MouseEvent {
|
||||||
|
.button = myButton,
|
||||||
|
.state = action == GLFW_PRESS,
|
||||||
|
.x = x,
|
||||||
|
.y = y
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwSetScrollCallback(window, [](auto window, auto dx, auto dy) {
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::ScrollEvent {
|
||||||
|
.dx = dx,
|
||||||
|
.dy = dy
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwSetKeyCallback(window, [](auto window, auto key, auto scancode, auto action, auto mods) {
|
||||||
|
if (action == GLFW_PRESS) {
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::KeyDownEvent {
|
||||||
|
.key = GLFWToArtifact[key]
|
||||||
|
});
|
||||||
|
} else if (action == GLFW_RELEASE) {
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::KeyUpEvent {
|
||||||
|
.key = GLFWToArtifact[key]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
glfwSetCharCallback(window, [](auto window, auto codepoint) {
|
||||||
|
static_cast<Window *>(glfwGetWindowUserPointer(window))->dispatch(Events::CharInputEvent {
|
||||||
|
.codepoint = codepoint
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::render() {
|
||||||
|
dispatch(Events::InputBegin {});
|
||||||
|
glfwPollEvents();
|
||||||
|
dispatch(Events::InputEnd {});
|
||||||
|
}
|
||||||
|
|
||||||
|
WGPUSurface Window::createWGPUSurface(WGPUInstance instance) {
|
||||||
|
return glfwCreateWindowWGPUSurface(instance, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::setTitle(std::string title) {
|
||||||
|
glfwSetWindowTitle(window, title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::shouldClose() {
|
||||||
|
return glfwWindowShouldClose(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::setPointerLock() {
|
||||||
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::releasePointerLock() {
|
||||||
|
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::isKeyDown(Key key) {
|
||||||
|
return glfwGetKey(window, ArtifactToGLFW[static_cast<int>(key)]) == GLFW_PRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
103
Client/Platform/Window.h
Normal file
103
Client/Platform/Window.h
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "Events.h"
|
||||||
|
#include "Client.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
enum class Key {
|
||||||
|
Unknown = 0,
|
||||||
|
A, B, C, D, E, F, G, H, I, J, K, L, M,
|
||||||
|
N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
|
||||||
|
Zero, One, Two, Three, Four, Five,
|
||||||
|
Six, Seven, Eight, Nine,
|
||||||
|
ShiftLeft, ShiftRight,
|
||||||
|
ControlLeft, ControlRight,
|
||||||
|
OptionLeft, OptionRight,
|
||||||
|
CommandLeft, CommandRight,
|
||||||
|
Enter,
|
||||||
|
DeleteForward, DeleteBackward,
|
||||||
|
ArrowLeft, ArrowRight, ArrowUp, ArrowDown,
|
||||||
|
Tab,
|
||||||
|
|
||||||
|
Last
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Events {
|
||||||
|
|
||||||
|
struct InputBegin {};
|
||||||
|
struct InputEnd {};
|
||||||
|
|
||||||
|
enum Action {
|
||||||
|
ACTION_PRESS,
|
||||||
|
ACTION_RELEASE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyDownEvent {
|
||||||
|
Key key;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KeyUpEvent {
|
||||||
|
Key key;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharInputEvent {
|
||||||
|
uint32_t codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CursorPosEvent {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScrollEvent {
|
||||||
|
double dx;
|
||||||
|
double dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MouseButton {
|
||||||
|
MOUSE_BUTTON_LEFT,
|
||||||
|
MOUSE_BUTTON_RIGHT,
|
||||||
|
MOUSE_BUTTON_MIDDLE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MouseEvent {
|
||||||
|
MouseButton button;
|
||||||
|
bool state;
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class WindowImpl: public EventTarget, public ClientSubsystem {
|
||||||
|
public:
|
||||||
|
virtual bool shouldClose() = 0;
|
||||||
|
virtual WGPUSurface createWGPUSurface(WGPUInstance instance) = 0;
|
||||||
|
virtual void setPointerLock() = 0;
|
||||||
|
virtual void releasePointerLock() = 0;
|
||||||
|
virtual bool isKeyDown(Key key) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Window: public WindowImpl {
|
||||||
|
private:
|
||||||
|
GLFWwindow * window = nullptr;
|
||||||
|
public:
|
||||||
|
Window(uint32_t width, uint32_t height, std::string title);
|
||||||
|
|
||||||
|
void render() override;
|
||||||
|
|
||||||
|
WGPUSurface createWGPUSurface(WGPUInstance instance) override;
|
||||||
|
void setTitle(std::string title);
|
||||||
|
bool shouldClose() override;
|
||||||
|
void setPointerLock() override;
|
||||||
|
void releasePointerLock() override;
|
||||||
|
bool isKeyDown(Key key) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
1
Client/glfw3webgpu/.gitignore
vendored
Normal file
1
Client/glfw3webgpu/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
releases/
|
||||||
15
Client/glfw3webgpu/CMakeLists.txt
Normal file
15
Client/glfw3webgpu/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
# This is only meant to be included as a subdirectory in another project.
|
||||||
|
# It assumes that targets 'glfw' and 'webgpu' exist.
|
||||||
|
# Look at examples/CMakeLists.txt to see how to use it in a project.
|
||||||
|
|
||||||
|
# The glfw3webgpu target
|
||||||
|
add_library(glfw3webgpu STATIC glfw3webgpu.c)
|
||||||
|
target_include_directories(glfw3webgpu PUBLIC .)
|
||||||
|
target_link_libraries(glfw3webgpu PUBLIC glfw webgpu)
|
||||||
|
|
||||||
|
# Copy compile definitions that are PRIVATE in glfw
|
||||||
|
if (GLFW_BUILD_COCOA)
|
||||||
|
target_compile_definitions(glfw3webgpu PRIVATE _GLFW_COCOA)
|
||||||
|
target_compile_options(glfw3webgpu PRIVATE -x objective-c)
|
||||||
|
target_link_libraries(glfw3webgpu PRIVATE "-framework Cocoa" "-framework CoreVideo" "-framework IOKit" "-framework QuartzCore")
|
||||||
|
endif()
|
||||||
20
Client/glfw3webgpu/LICENSE.txt
Normal file
20
Client/glfw3webgpu/LICENSE.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
MIT License
|
||||||
|
Copyright (c) 2022-2024 Élie Michel and the wgpu-native authors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
94
Client/glfw3webgpu/README.md
Normal file
94
Client/glfw3webgpu/README.md
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
<img src="https://github.com/eliemichel/glfw3webgpu/actions/workflows/cmake.yml/badge.svg" alt="CMake Badge" />
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<picture>
|
||||||
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/eliemichel/LearnWebGPU/main/images/webgpu-dark.svg">
|
||||||
|
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/eliemichel/LearnWebGPU/main/images/webgpu-light.svg">
|
||||||
|
<img alt="Learn WebGPU Logo" src="images/webgpu-dark.svg" width="200">
|
||||||
|
</picture>
|
||||||
|
|
||||||
|
<a href="https://github.com/eliemichel/LearnWebGPU">LearnWebGPU</a> | <a href="https://github.com/eliemichel/WebGPU-Cpp">WebGPU-C++</a> | <a href="https://github.com/eliemichel/WebGPU-distribution">WebGPU-distribution</a><br/>
|
||||||
|
<a href="https://github.com/eliemichel/glfw3webgpu">glfw3webgpu</a> | <a href="https://github.com/eliemichel/sdl2webgpu">sdl2webgpu</a> | <a href="https://github.com/eliemichel/sdl3webgpu">sdl3webgpu</a>
|
||||||
|
|
||||||
|
<a href="https://discord.gg/2Tar4Kt564"><img src="https://img.shields.io/static/v1?label=Discord&message=Join%20us!&color=blue&logo=discord&logoColor=white" alt="Discord | Join us!"/></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
GLFW WebGPU Extension
|
||||||
|
=====================
|
||||||
|
|
||||||
|
This is an extension for the great [GLFW](https://www.glfw.org/) library for using it with **WebGPU native**. It was written as part of the [Learn WebGPU for native C++](https://eliemichel.github.io/LearnWebGPU) tutorial series.
|
||||||
|
|
||||||
|
Table of Contents
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
- [Overview](#overview)
|
||||||
|
- [Usage](#usage)
|
||||||
|
- [Example](#example)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
This extension simply provides the following function:
|
||||||
|
|
||||||
|
```C
|
||||||
|
WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window);
|
||||||
|
```
|
||||||
|
|
||||||
|
Given a GLFW window, `glfwCreateWindowWGPUSurface` returns a WebGPU *surface* that corresponds to the window's back-end. This is a process that is highly platform-specific, which is why I believe it belongs to GLFW.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
|
||||||
|
**NB** The current version of this extension is written for GLFW 3.4. Up to version 1.2.0, it was written for GLFW 3.3.8.
|
||||||
|
|
||||||
|
Your project must link to an implementation of WebGPU (providing `webgpu.h`) and of course to GLFW. Then:
|
||||||
|
|
||||||
|
**Option A** If you use CMake, you can simply include this project as a subdirectory with `add_subdirectory(glfw3webgpu)` (see the content of [`CMakeLists.txt`](CMakeLists.txt)).
|
||||||
|
|
||||||
|
**Option B** Just copy [`glfw3webgpu.h`](glfw3webgpu.h) and [`glfw3webgpu.c`](glfw3webgpu.c) to your project's source tree. On MacOS, you must add the compile option `-x objective-c` and the link libraries `-framework Cocoa`, `-framework CoreVideo`, `-framework IOKit`, and `-framework QuartzCore`.
|
||||||
|
|
||||||
|
Example
|
||||||
|
-------
|
||||||
|
|
||||||
|
Thanks to this extension it is possible to simply write a fully cross-platform WebGPU hello world:
|
||||||
|
|
||||||
|
```C
|
||||||
|
#include "glfw3webgpu.h"
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_NONE
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
// Init WebGPU
|
||||||
|
WGPUInstanceDescriptor desc;
|
||||||
|
desc.nextInChain = NULL;
|
||||||
|
WGPUInstance instance = wgpuCreateInstance(&desc);
|
||||||
|
|
||||||
|
// Init GLFW
|
||||||
|
glfwInit();
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
GLFWwindow* window = glfwCreateWindow(640, 480, "Learn WebGPU", NULL, NULL);
|
||||||
|
|
||||||
|
// Here we create our WebGPU surface from the window!
|
||||||
|
WGPUSurface surface = glfwCreateWindowWGPUSurface(instance, window);
|
||||||
|
printf("surface = %p", surface);
|
||||||
|
|
||||||
|
// Terminate GLFW
|
||||||
|
while (!glfwWindowShouldClose(window)) glfwPollEvents();
|
||||||
|
glfwDestroyWindow(window);
|
||||||
|
glfwTerminate();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**NB** The linking process depends on the implementation of WebGPU that you are using. You can find detailed instructions for the `wgpu-native` implementation in [this Hello WebGPU chapter](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html). You may also check out [`examples/CMakeLists.txt`](examples/CMakeLists.txt).
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
See [LICENSE.txt](LICENSE.txt).
|
||||||
191
Client/glfw3webgpu/glfw3webgpu.c
Normal file
191
Client/glfw3webgpu/glfw3webgpu.c
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of GLFW for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* Most of this code comes from the wgpu-native triangle example:
|
||||||
|
* https://github.com/gfx-rs/wgpu-native/blob/master/examples/triangle/main.c
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2025 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "glfw3webgpu.h"
|
||||||
|
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
// Begin hack
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#define _GLFW_COCOA
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define _GLFW_WIN32
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#define _GLFW_X11 // or _GLFW_WAYLAND if you built GLFW with Wayland
|
||||||
|
#endif
|
||||||
|
// End hack
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
# define GLFW_EXPOSE_NATIVE_EMSCRIPTEN
|
||||||
|
# ifndef GLFW_PLATFORM_EMSCRIPTEN // not defined in older versions of emscripten
|
||||||
|
# define GLFW_PLATFORM_EMSCRIPTEN 0
|
||||||
|
# endif
|
||||||
|
#else // __EMSCRIPTEN__
|
||||||
|
# ifdef _GLFW_X11
|
||||||
|
# define GLFW_EXPOSE_NATIVE_X11
|
||||||
|
# endif
|
||||||
|
# ifdef _GLFW_WAYLAND
|
||||||
|
# define GLFW_EXPOSE_NATIVE_WAYLAND
|
||||||
|
# endif
|
||||||
|
# ifdef _GLFW_COCOA
|
||||||
|
# define GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
# endif
|
||||||
|
# ifdef _GLFW_WIN32
|
||||||
|
# define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
# endif
|
||||||
|
#endif // __EMSCRIPTEN__
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
# include <Foundation/Foundation.h>
|
||||||
|
# include <QuartzCore/CAMetalLayer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
# include <GLFW/glfw3native.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window) {
|
||||||
|
#ifndef __EMSCRIPTEN__
|
||||||
|
switch (glfwGetPlatform()) {
|
||||||
|
#else
|
||||||
|
// glfwGetPlatform is not available in older versions of emscripten
|
||||||
|
switch (GLFW_PLATFORM_EMSCRIPTEN) {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_X11
|
||||||
|
case GLFW_PLATFORM_X11: {
|
||||||
|
Display* x11_display = glfwGetX11Display();
|
||||||
|
Window x11_window = glfwGetX11Window(window);
|
||||||
|
|
||||||
|
WGPUSurfaceSourceXlibWindow fromXlibWindow;
|
||||||
|
fromXlibWindow.chain.sType = WGPUSType_SurfaceSourceXlibWindow;
|
||||||
|
fromXlibWindow.chain.next = NULL;
|
||||||
|
fromXlibWindow.display = x11_display;
|
||||||
|
fromXlibWindow.window = x11_window;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromXlibWindow.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#endif // GLFW_EXPOSE_NATIVE_X11
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_WAYLAND
|
||||||
|
case GLFW_PLATFORM_WAYLAND: {
|
||||||
|
struct wl_display* wayland_display = glfwGetWaylandDisplay();
|
||||||
|
struct wl_surface* wayland_surface = glfwGetWaylandWindow(window);
|
||||||
|
|
||||||
|
WGPUSurfaceSourceWaylandSurface fromWaylandSurface;
|
||||||
|
fromWaylandSurface.chain.sType = WGPUSType_SurfaceSourceWaylandSurface;
|
||||||
|
fromWaylandSurface.chain.next = NULL;
|
||||||
|
fromWaylandSurface.display = wayland_display;
|
||||||
|
fromWaylandSurface.surface = wayland_surface;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromWaylandSurface.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#endif // GLFW_EXPOSE_NATIVE_WAYLAND
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
case GLFW_PLATFORM_COCOA: {
|
||||||
|
id metal_layer = [CAMetalLayer layer];
|
||||||
|
NSWindow* ns_window = glfwGetCocoaWindow(window);
|
||||||
|
[ns_window.contentView setWantsLayer : YES] ;
|
||||||
|
[ns_window.contentView setLayer : metal_layer] ;
|
||||||
|
|
||||||
|
WGPUSurfaceSourceMetalLayer fromMetalLayer;
|
||||||
|
fromMetalLayer.chain.sType = WGPUSType_SurfaceSourceMetalLayer;
|
||||||
|
fromMetalLayer.chain.next = NULL;
|
||||||
|
fromMetalLayer.layer = (__bridge void *)(metal_layer);
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromMetalLayer.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#endif // GLFW_EXPOSE_NATIVE_COCOA
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
case GLFW_PLATFORM_WIN32: {
|
||||||
|
HWND hwnd = glfwGetWin32Window(window);
|
||||||
|
HINSTANCE hinstance = GetModuleHandle(NULL);
|
||||||
|
|
||||||
|
WGPUSurfaceSourceWindowsHWND fromWindowsHWND;
|
||||||
|
fromWindowsHWND.chain.sType = WGPUSType_SurfaceSourceWindowsHWND;
|
||||||
|
fromWindowsHWND.chain.next = NULL;
|
||||||
|
fromWindowsHWND.hinstance = hinstance;
|
||||||
|
fromWindowsHWND.hwnd = hwnd;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromWindowsHWND.chain;
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#endif // GLFW_EXPOSE_NATIVE_WIN32
|
||||||
|
|
||||||
|
#ifdef GLFW_EXPOSE_NATIVE_EMSCRIPTEN
|
||||||
|
case GLFW_PLATFORM_EMSCRIPTEN: {
|
||||||
|
# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
|
||||||
|
WGPUEmscriptenSurfaceSourceCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.chain.sType = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.selector = (WGPUStringView){ "canvas", WGPU_STRLEN };
|
||||||
|
# else
|
||||||
|
WGPUSurfaceDescriptorFromCanvasHTMLSelector fromCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.chain.sType = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector;
|
||||||
|
fromCanvasHTMLSelector.selector = "canvas";
|
||||||
|
# endif
|
||||||
|
fromCanvasHTMLSelector.chain.next = NULL;
|
||||||
|
|
||||||
|
WGPUSurfaceDescriptor surfaceDescriptor;
|
||||||
|
surfaceDescriptor.nextInChain = &fromCanvasHTMLSelector.chain;
|
||||||
|
# ifdef WEBGPU_BACKEND_EMDAWNWEBGPU
|
||||||
|
surfaceDescriptor.label = (WGPUStringView){ NULL, WGPU_STRLEN };
|
||||||
|
# else
|
||||||
|
surfaceDescriptor.label = NULL;
|
||||||
|
# endif
|
||||||
|
return wgpuInstanceCreateSurface(instance, &surfaceDescriptor);
|
||||||
|
}
|
||||||
|
#endif // GLFW_EXPOSE_NATIVE_EMSCRIPTEN
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unsupported platform
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
62
Client/glfw3webgpu/glfw3webgpu.h
Normal file
62
Client/glfw3webgpu/glfw3webgpu.h
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* This is an extension of GLFW for WebGPU, abstracting away the details of
|
||||||
|
* OS-specific operations.
|
||||||
|
*
|
||||||
|
* This file is part of the "Learn WebGPU for C++" book.
|
||||||
|
* https://eliemichel.github.io/LearnWebGPU
|
||||||
|
*
|
||||||
|
* MIT License
|
||||||
|
* Copyright (c) 2022-2024 Elie Michel and the wgpu-native authors
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _glfw3_webgpu_h_
|
||||||
|
#define _glfw3_webgpu_h_
|
||||||
|
|
||||||
|
#include <webgpu/webgpu.h>
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! @brief Creates a WebGPU surface for the specified window.
|
||||||
|
*
|
||||||
|
* This function creates a WGPUSurface object for the specified window.
|
||||||
|
*
|
||||||
|
* If the surface cannot be created, this function returns `NULL`.
|
||||||
|
*
|
||||||
|
* It is the responsibility of the caller to destroy the window surface. The
|
||||||
|
* window surface must be destroyed using `wgpuSurfaceRelease`.
|
||||||
|
*
|
||||||
|
* @param[in] instance The WebGPU instance to create the surface in.
|
||||||
|
* @param[in] window The window to create the surface for.
|
||||||
|
* @return The handle of the surface. This is set to `NULL` if an error
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
|
* @ingroup webgpu
|
||||||
|
*/
|
||||||
|
WGPUSurface glfwCreateWindowWGPUSurface(WGPUInstance instance, GLFWwindow* window);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _glfw3_webgpu_h_
|
||||||
12
README.md
Normal file
12
README.md
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
# What is this?
|
||||||
|
|
||||||
|
Artifact Engine is a game engine designed to make creating a voxel game as simple as possible.
|
||||||
|
|
||||||
|
# Status
|
||||||
|
|
||||||
|
The engine is currently in very early development. The only thing it really has is
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
|
||||||
|
Testing on non-macOS platforms is
|
||||||
6
Server/CMakeLists.txt
Normal file
6
Server/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(Server ${MY_SOURCES})
|
||||||
10
Server/Network.h
Normal file
10
Server/Network.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Network/Network.h>
|
||||||
|
#include "Server.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class ServerNetwork: public NetworkServer, public ServerSubsystem {};
|
||||||
|
|
||||||
|
}
|
||||||
7
Server/Player.cpp
Normal file
7
Server/Player.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
9
Server/Player.h
Normal file
9
Server/Player.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class Player {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
37
Server/Server.cpp
Normal file
37
Server/Server.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "Server.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "World/WorldManager.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void Server::init() {
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->init();
|
||||||
|
system->reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::tick() {
|
||||||
|
for (auto & system : subsystems) {
|
||||||
|
system->tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::run() {
|
||||||
|
init();
|
||||||
|
|
||||||
|
auto time = std::chrono::steady_clock::now();
|
||||||
|
while (true) {
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
if (time - now > std::chrono::milliseconds(50)) {
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Server::addDefaultSubsystems() {
|
||||||
|
addSubsystem<ServerNetwork>();
|
||||||
|
addSubsystem<WorldManager>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
28
Server/Server.h
Normal file
28
Server/Server.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Shared.h"
|
||||||
|
#include <Settings.h>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class ServerSubsystem;
|
||||||
|
|
||||||
|
class Server: public Engine<ServerSubsystem> {
|
||||||
|
public:
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
Server() : settings(getServerConfigPath()) {}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void tick();
|
||||||
|
void run();
|
||||||
|
void addDefaultSubsystems();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerSubsystem: public BaseSubsystem {
|
||||||
|
public:
|
||||||
|
Server * server = nullptr;
|
||||||
|
virtual void tick() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
7
Server/World/WorldBackend.cpp
Normal file
7
Server/World/WorldBackend.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
//
|
||||||
|
// WorldBackend.cpp
|
||||||
|
// ArtifactEngine
|
||||||
|
//
|
||||||
|
// Created by Isaac Boettcher on 3/11/26.
|
||||||
|
//
|
||||||
|
|
||||||
10
Server/World/WorldBackend.h
Normal file
10
Server/World/WorldBackend.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class WorldBackend {
|
||||||
|
virtual void saveChunk();
|
||||||
|
virtual void loadChukn();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
11
Server/World/WorldManager.cpp
Normal file
11
Server/World/WorldManager.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "WorldManager.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void WorldManager::tick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
Server/World/WorldManager.h
Normal file
16
Server/World/WorldManager.h
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Shared.h>
|
||||||
|
#include "../Server.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
class WorldManagerImpl: public ServerSubsystem {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class WorldManager: public WorldManagerImpl {
|
||||||
|
void tick() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
6
Shared/CMakeLists.txt
Normal file
6
Shared/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS
|
||||||
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(Shared ${MY_SOURCES})
|
||||||
91
Shared/Events.h
Normal file
91
Shared/Events.h
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <any>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
class EventTarget {
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
using Callback = std::function<void(const T &)>;
|
||||||
|
|
||||||
|
// Subscribe to an event type.
|
||||||
|
template<typename T>
|
||||||
|
uint64_t listen(Callback<T> callback) {
|
||||||
|
auto type = std::type_index(typeid(T));
|
||||||
|
auto & vec = callbacks[type];
|
||||||
|
|
||||||
|
uint64_t id = nextEventId++;
|
||||||
|
|
||||||
|
vec.emplace_back([cb = std::move(callback)](const std::any & e) {
|
||||||
|
cb(std::any_cast<const T &>(e));
|
||||||
|
});
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unsubscribe a specific listener.
|
||||||
|
template<typename T>
|
||||||
|
void unlisten(uint64_t id) {
|
||||||
|
_unlisten(std::type_index(typeid(T)), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Synchronously dispatch an event.
|
||||||
|
template<typename T>
|
||||||
|
void dispatch(const T & event) {
|
||||||
|
auto it = callbacks.find(std::type_index(typeid(T)));
|
||||||
|
if (it == callbacks.end()) return;
|
||||||
|
|
||||||
|
// Copy the list in case a callback unsubscribes during dispatch.
|
||||||
|
auto copy = it->second;
|
||||||
|
for (const auto & cb : copy) {
|
||||||
|
cb(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be called on a main loop to dispatch queued events.
|
||||||
|
void processQueue() {
|
||||||
|
for (auto & [anyEvent, copy] : queued) {
|
||||||
|
auto it = callbacks.find(anyEvent.type());
|
||||||
|
if (it != callbacks.end()) {
|
||||||
|
for (const auto & cb : copy) {
|
||||||
|
cb(anyEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queued.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue an event to be dispatched on the next call to `processQueue`.
|
||||||
|
template<typename T>
|
||||||
|
void queue(const T & event) {
|
||||||
|
auto type = std::type_index(typeid(T));
|
||||||
|
auto it = callbacks.find(type);
|
||||||
|
if (it == callbacks.end()) return;
|
||||||
|
queued.emplace_back(std::any(event), it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using AnyCallback = std::function<void(const std::any &)>;
|
||||||
|
using CallbackWithId = std::pair<AnyCallback, uint64_t>;
|
||||||
|
|
||||||
|
std::unordered_map<std::type_index, std::vector<AnyCallback>> callbacks {};
|
||||||
|
std::vector<std::pair<std::any, std::vector<AnyCallback>>> queued {};
|
||||||
|
|
||||||
|
uint64_t nextEventId = 0;
|
||||||
|
|
||||||
|
void _unlisten(std::type_index type, uint64_t id) {
|
||||||
|
// auto it = callbacks.find(type);
|
||||||
|
// if (it == callbacks.end()) return;
|
||||||
|
//
|
||||||
|
// auto & vec = it->second;
|
||||||
|
// auto erase_it = std::find_if(vec.begin(), vec.end(),
|
||||||
|
// [id](const auto& p) { return p.second == id; });
|
||||||
|
//
|
||||||
|
// if (erase_it != vec.end()) {
|
||||||
|
// *erase_it = std::move(vec.back());
|
||||||
|
// vec.pop_back();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
};
|
||||||
148
Shared/Network/Connection.cpp
Normal file
148
Shared/Network/Connection.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <ngtcp2/ngtcp2_crypto.h>
|
||||||
|
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
#include <cista.h>
|
||||||
|
|
||||||
|
#include "Connection.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
Connection::Connection() {
|
||||||
|
ngtcp2_settings_default(&settings);
|
||||||
|
ngtcp2_transport_params_default(&transportParams);
|
||||||
|
transportParams.initial_max_streams_bidi = 1;
|
||||||
|
transportParams.initial_max_data = 65535;
|
||||||
|
transportParams.initial_max_stream_data_bidi_local = 65535;
|
||||||
|
|
||||||
|
callbacks.encrypt = ngtcp2_crypto_encrypt_cb;
|
||||||
|
callbacks.decrypt = ngtcp2_crypto_decrypt_cb;
|
||||||
|
callbacks.hp_mask = ngtcp2_crypto_hp_mask_cb;
|
||||||
|
callbacks.update_key = ngtcp2_crypto_update_key_cb;
|
||||||
|
callbacks.delete_crypto_aead_ctx = ngtcp2_crypto_delete_crypto_aead_ctx_cb;
|
||||||
|
callbacks.delete_crypto_cipher_ctx = ngtcp2_crypto_delete_crypto_cipher_ctx_cb;
|
||||||
|
callbacks.get_path_challenge_data = ngtcp2_crypto_get_path_challenge_data_cb;
|
||||||
|
callbacks.rand = [](auto dest, auto len, auto ctx) {
|
||||||
|
gnutls_rnd(GNUTLS_RND_RANDOM, dest, len);
|
||||||
|
};
|
||||||
|
callbacks.get_new_connection_id = [](auto conn, auto cid, auto token, auto cidlen, auto userdata) {
|
||||||
|
gnutls_rnd(GNUTLS_RND_RANDOM, cid, cidlen);
|
||||||
|
gnutls_rnd(GNUTLS_RND_RANDOM, token, NGTCP2_STATELESS_RESET_TOKENLEN);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
callbacks.version_negotiation = ngtcp2_crypto_version_negotiation_cb;
|
||||||
|
|
||||||
|
gnutls_rnd(GNUTLS_RND_RANDOM, dcid.data, dcid.datalen);
|
||||||
|
gnutls_rnd(GNUTLS_RND_RANDOM, scid.data, scid.datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readPacket(ngtcp2_pkt_info * info, void * packet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientConnection::ClientConnection(std::string host, std::string port) {
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo * local = nullptr;
|
||||||
|
struct addrinfo * remote = nullptr;
|
||||||
|
getaddrinfo("::", "", &hints, &local);
|
||||||
|
getaddrinfo(host.c_str(), port.c_str(), &hints, &remote);
|
||||||
|
ngtcp2_path path = {
|
||||||
|
.local = {
|
||||||
|
.addr = local->ai_addr,
|
||||||
|
.addrlen = local->ai_addrlen
|
||||||
|
},
|
||||||
|
.remote = {
|
||||||
|
.addr = remote->ai_addr,
|
||||||
|
.addrlen = remote->ai_addrlen
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) {
|
||||||
|
throw std::runtime_error("Failed to initialize gnutls.");
|
||||||
|
}
|
||||||
|
gnutls_set_default_priority(session);
|
||||||
|
|
||||||
|
ngtcp2_conn_client_new(&conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1, &callbacks, &settings, &transportParams, nullptr, this);
|
||||||
|
ngtcp2_conn_set_tls_native_handle(conn, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerConnection::ServerConnection(ngtcp2_path path) : path(path) {
|
||||||
|
if (gnutls_init(&session, GNUTLS_CLIENT) != GNUTLS_E_SUCCESS) {
|
||||||
|
throw std::runtime_error("Failed to initialize gnutls.");
|
||||||
|
}
|
||||||
|
gnutls_set_default_priority(session);
|
||||||
|
|
||||||
|
ngtcp2_conn_server_new(&conn, &dcid, &scid, &path, NGTCP2_PROTO_VER_V1, &callbacks, &settings, &transportParams, nullptr, this);
|
||||||
|
ngtcp2_conn_set_tls_native_handle(conn, session);
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerListener::ServerListener(std::string port) {
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct addrinfo * local = nullptr;
|
||||||
|
getaddrinfo("::", "", &hints, &local);
|
||||||
|
|
||||||
|
socketDescriptor = socket(local->ai_family, local->ai_socktype, local->ai_protocol);
|
||||||
|
|
||||||
|
int on = 1;
|
||||||
|
setsockopt(socketDescriptor, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char *>(&on), sizeof(int));
|
||||||
|
|
||||||
|
if (local->ai_family == AF_INET6) {
|
||||||
|
int off = 0;
|
||||||
|
setsockopt(socketDescriptor, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char *>(&off), sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(socketDescriptor, local->ai_addr, local->ai_addrlen)) {
|
||||||
|
// Save our actual local address for later use.
|
||||||
|
getsockname(socketDescriptor, reinterpret_cast<sockaddr *>(&localAddr.addr), &localAddr.addrlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerListener::onReadable(struct ev_loop *, ev_io * watcher, int) {
|
||||||
|
auto self = static_cast<ServerListener *>(watcher->data);
|
||||||
|
|
||||||
|
uint8_t buf[2048];
|
||||||
|
ngtcp2_addr remote;
|
||||||
|
auto len = recvfrom(self->socketDescriptor, buf, sizeof(buf), 0, remote.addr, &remote.addrlen);
|
||||||
|
|
||||||
|
ngtcp2_pkt_info pi{};
|
||||||
|
ngtcp2_pkt_hd hd{};
|
||||||
|
ngtcp2_pkt_decode_hd_long(&hd, buf, len);
|
||||||
|
|
||||||
|
auto it = self->connections.find(hd.dcid);
|
||||||
|
if (it != self->connections.end()) {
|
||||||
|
ServerConnection * conn = it->second.get();
|
||||||
|
|
||||||
|
ngtcp2_conn_read_pkt(conn->conn, &conn->path, &pi, buf, len, std::chrono::steady_clock::now().time_since_epoch().count());
|
||||||
|
|
||||||
|
conn->readPacket(&pi, buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hd.flags & NGTCP2_PKT_FLAG_LONG_FORM && hd.type == NGTCP2_PKT_INITIAL) {
|
||||||
|
ngtcp2_pkt_hd accept_hd{};
|
||||||
|
if (ngtcp2_accept(&accept_hd, buf, static_cast<size_t>(len)) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_conn = std::make_unique<ServerConnection>(ngtcp2_path {
|
||||||
|
.local = self->localAddr,
|
||||||
|
.remote = remote
|
||||||
|
});
|
||||||
|
|
||||||
|
self->connections[accept_hd.dcid] = std::move(new_conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ServerListener::run() {
|
||||||
|
std::thread([this]() {
|
||||||
|
loop = ev_loop_new(EVFLAG_AUTO);
|
||||||
|
ev_io_init(&watcher, onReadable, socketDescriptor, EV_READ);
|
||||||
|
watcher.data = this;
|
||||||
|
ev_io_start(loop, &watcher);
|
||||||
|
ev_run(loop, 0);
|
||||||
|
}).detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
95
Shared/Network/Connection.h
Normal file
95
Shared/Network/Connection.h
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <ngtcp2/ngtcp2.h>
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <ev.h>
|
||||||
|
|
||||||
|
// Platform-specific socket includes and helpers
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
using socket_t = SOCKET;
|
||||||
|
#define CLOSE_SOCKET closesocket
|
||||||
|
#define SOCKLEN_T int
|
||||||
|
#define IS_INVALID_SOCKET(s) ((s) == INVALID_SOCKET)
|
||||||
|
#define GET_LAST_ERROR() WSAGetLastError()
|
||||||
|
#else
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
using socket_t = int;
|
||||||
|
#define CLOSE_SOCKET close
|
||||||
|
#define SOCKLEN_T socklen_t
|
||||||
|
#define IS_INVALID_SOCKET(s) ((s) < 0)
|
||||||
|
#define GET_LAST_ERROR() errno
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct Ngtcp2CidEqual {
|
||||||
|
bool operator()(const ngtcp2_cid& a, const ngtcp2_cid& b) const noexcept {
|
||||||
|
return a.datalen == b.datalen &&
|
||||||
|
std::memcmp(a.data, b.data, a.datalen) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Ngtcp2CidHash {
|
||||||
|
size_t operator()(const ngtcp2_cid& cid) const noexcept {
|
||||||
|
size_t h = cid.datalen;
|
||||||
|
for (uint8_t i = 0; i < cid.datalen; ++i) {
|
||||||
|
h = (h * 31) ^ cid.data[i]; // or better hash as above
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Connection {
|
||||||
|
public:
|
||||||
|
ngtcp2_settings settings;
|
||||||
|
ngtcp2_transport_params transportParams;
|
||||||
|
ngtcp2_callbacks callbacks;
|
||||||
|
ngtcp2_cid dcid, scid;
|
||||||
|
gnutls_session_t session;
|
||||||
|
ngtcp2_conn * conn;
|
||||||
|
|
||||||
|
Connection();
|
||||||
|
|
||||||
|
void readPacket(ngtcp2_pkt_info * info, void * packet);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClientConnection: public Connection {
|
||||||
|
public:
|
||||||
|
ClientConnection(std::string host, std::string port);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerConnection: public Connection {
|
||||||
|
public:
|
||||||
|
ngtcp2_path path;
|
||||||
|
ServerConnection(ngtcp2_path path);
|
||||||
|
};
|
||||||
|
|
||||||
|
class ServerListener {
|
||||||
|
socket_t socketDescriptor;
|
||||||
|
std::unordered_map<ngtcp2_cid, std::unique_ptr<ServerConnection>, Ngtcp2CidHash, Ngtcp2CidEqual> connections;
|
||||||
|
ngtcp2_addr localAddr;
|
||||||
|
|
||||||
|
struct ev_loop * loop;
|
||||||
|
ev_io watcher;
|
||||||
|
public:
|
||||||
|
ServerListener(std::string port);
|
||||||
|
static void onReadable(struct ev_loop *, ev_io * watcher, int);
|
||||||
|
void run();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
31
Shared/Network/Network.cpp
Normal file
31
Shared/Network/Network.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include "Network.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void NetworkServer::host(NetworkClient * local) {
|
||||||
|
if (active) {
|
||||||
|
unhost();
|
||||||
|
}
|
||||||
|
|
||||||
|
active = true;
|
||||||
|
localClient = local;
|
||||||
|
listener = local->listen<Events::NetworkMessage>([](auto ev) {
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkServer::unhost() {
|
||||||
|
active = false;
|
||||||
|
if (localClient) {
|
||||||
|
localClient->unlisten<Events::NetworkMessage>(listener);
|
||||||
|
localClient = nullptr;
|
||||||
|
} else if (server) {
|
||||||
|
server = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkClient::connect(NetworkServer * local) {
|
||||||
|
localServer = local;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
45
Shared/Network/Network.h
Normal file
45
Shared/Network/Network.h
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Shared.h"
|
||||||
|
#include "Events.h"
|
||||||
|
#include "Connection.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace Events {
|
||||||
|
|
||||||
|
struct NetworkMessage {
|
||||||
|
void * data;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class NetworkClient;
|
||||||
|
|
||||||
|
class NetworkServer: public BaseSubsystem, public EventTarget {
|
||||||
|
NetworkClient * localClient = nullptr;
|
||||||
|
std::unique_ptr<ServerListener> server = nullptr;
|
||||||
|
bool active = false;
|
||||||
|
uint64_t listener;
|
||||||
|
public:
|
||||||
|
|
||||||
|
void host(NetworkClient * client);
|
||||||
|
void host(std::string port);
|
||||||
|
|
||||||
|
void unhost();
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetworkClient: public BaseSubsystem, public EventTarget {
|
||||||
|
NetworkServer * localServer = nullptr;
|
||||||
|
std::unique_ptr<Connection> server = nullptr;
|
||||||
|
bool active = false;
|
||||||
|
uint64_t listener;
|
||||||
|
public:
|
||||||
|
|
||||||
|
void connect(NetworkServer * local);
|
||||||
|
void connect(std::string host, std::string port);
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
60
Shared/Paths.cpp
Normal file
60
Shared/Paths.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include "Paths.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
Path getDataPath() {
|
||||||
|
Path base;
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
// 1. Windows — AppData/Roaming (most common choice)
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
#ifdef _WIN32
|
||||||
|
const char* appdata = std::getenv("APPDATA");
|
||||||
|
if (!appdata || !fs::exists(appdata)) {
|
||||||
|
throw std::runtime_error("Cannot find APPDATA environment variable");
|
||||||
|
}
|
||||||
|
base = Path(appdata) / organization / GAME;
|
||||||
|
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
// 2. macOS — Application Support
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
const char* home = std::getenv("HOME");
|
||||||
|
if (!home) throw std::runtime_error("Cannot find HOME");
|
||||||
|
base = Path(home) / "Library" / "Application Support" / GAME;
|
||||||
|
|
||||||
|
#else
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
// 3. Linux / BSD / Steam Deck — XDG_DATA_HOME
|
||||||
|
// ────────────────────────────────────────────────
|
||||||
|
const char* xdg_data = std::getenv("XDG_DATA_HOME");
|
||||||
|
if (xdg_data && *xdg_data) {
|
||||||
|
base = fs::path(xdg_data) / game;
|
||||||
|
} else {
|
||||||
|
const char* home = std::getenv("HOME");
|
||||||
|
if (!home) throw std::runtime_error("Cannot find HOME");
|
||||||
|
base = Path(home) / ".local" / "share" / GAME;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Create folder structure if it doesn't exist
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::create_directories(base, ec);
|
||||||
|
|
||||||
|
if (ec) {
|
||||||
|
throw std::runtime_error("Failed to create directory: " +
|
||||||
|
base.string() + " → " + ec.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getClientConfigPath() {
|
||||||
|
return getDataPath() / "client.conf";
|
||||||
|
}
|
||||||
|
|
||||||
|
Path getServerConfigPath() {
|
||||||
|
return getDataPath() / "server.conf";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
Shared/Paths.h
Normal file
24
Shared/Paths.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifndef APP_NAME
|
||||||
|
# define APP_NAME ArtifactEngine
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TOSTRING(x) #x
|
||||||
|
|
||||||
|
#define GAME TOSTRING(APP_NAME)
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
using Path = std::filesystem::path;
|
||||||
|
|
||||||
|
Path getDataPath();
|
||||||
|
|
||||||
|
Path getClientConfigPath();
|
||||||
|
|
||||||
|
Path getServerConfigPath();
|
||||||
|
|
||||||
|
}
|
||||||
58
Shared/Settings.cpp
Normal file
58
Shared/Settings.cpp
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#include "Settings.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
Settings::Settings() : Settings(getDataPath() / "settings.conf") {}
|
||||||
|
|
||||||
|
Settings::Settings(Path path) : path(path) {
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string trim(const std::string& str) {
|
||||||
|
size_t first = str.find_first_not_of(" \t\r\n");
|
||||||
|
if (first == std::string::npos) return "";
|
||||||
|
size_t last = str.find_last_not_of(" \t\r\n");
|
||||||
|
return str.substr(first, last - first + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::reload() {
|
||||||
|
clear();
|
||||||
|
std::ifstream file(path);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
// TODO: Log a warning
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
line = trim(line);
|
||||||
|
if (line.empty() || line[0] == '#' || line[0] == ';') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t eq_pos = line.find('=');
|
||||||
|
if (eq_pos == std::string::npos) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string key = trim(line.substr(0, eq_pos));
|
||||||
|
std::string value = trim(line.substr(eq_pos + 1));
|
||||||
|
|
||||||
|
if (!key.empty()) {
|
||||||
|
data[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::save() {
|
||||||
|
std::ofstream file(path);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto & [key, value] : data) {
|
||||||
|
file << key << " = " << value << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
Shared/Settings.h
Normal file
85
Shared/Settings.h
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "Paths.h"
|
||||||
|
#include "Events.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
namespace Events {
|
||||||
|
|
||||||
|
struct SettingChanged {
|
||||||
|
std::string key;
|
||||||
|
std::optional<std::string> value;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Settings: public EventTarget {
|
||||||
|
const Path path;
|
||||||
|
std::unordered_map<std::string, std::string> data;
|
||||||
|
public:
|
||||||
|
Settings();
|
||||||
|
Settings(Path path);
|
||||||
|
|
||||||
|
void reload();
|
||||||
|
void save();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T get(std::string & key, const T & fallback = {}) {
|
||||||
|
auto it = data.find(key);
|
||||||
|
if (it == data.end()) {
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string & str = it->second;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, std::string>) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, bool>) {
|
||||||
|
std::string lower = str;
|
||||||
|
std::transform(lower.begin(), lower.end(), lower.begin(),
|
||||||
|
[](unsigned char c){ return static_cast<char>(std::tolower(c)); });
|
||||||
|
if (lower == "true" || lower == "1" || lower == "yes" || lower == "on") {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (lower == "false" || lower == "0" || lower == "no" || lower == "off") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istringstream iss(str);
|
||||||
|
T value;
|
||||||
|
if (iss >> value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void set(const std::string & key, const T & value) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::boolalpha << value;
|
||||||
|
data[key] = oss.str();
|
||||||
|
dispatch(Events::SettingChanged { .key = key, .value = value });
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(const std::string & key) {
|
||||||
|
data.erase(key);
|
||||||
|
dispatch(Events::SettingChanged { .key = key, .value = std::nullopt });
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
11
Shared/Shared.cpp
Normal file
11
Shared/Shared.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "Shared.h"
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
void log(std::string msg) {
|
||||||
|
std::cout << msg << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
147
Shared/Shared.h
Normal file
147
Shared/Shared.h
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct hash<glm::ivec3> {
|
||||||
|
std::size_t operator()(const glm::ivec3& v) const noexcept {
|
||||||
|
// Very common and reasonably good quality combination for floats
|
||||||
|
// (tries to mix bits while being fast)
|
||||||
|
|
||||||
|
std::size_t seed = 0;
|
||||||
|
|
||||||
|
// You can use any of these styles — pick one:
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────────
|
||||||
|
// Style 1: Boost hash_combine pattern (very popular)
|
||||||
|
auto hash_float = [](float f) -> std::size_t {
|
||||||
|
return std::hash<float>{}(f);
|
||||||
|
};
|
||||||
|
|
||||||
|
seed ^= hash_float(v.x) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
seed ^= hash_float(v.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
seed ^= hash_float(v.z) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────────
|
||||||
|
// Style 2: Simpler — fold with multiplication (often enough)
|
||||||
|
// seed = std::hash<float>{}(v.x);
|
||||||
|
// seed = seed * 31 + std::hash<float>{}(v.y);
|
||||||
|
// seed = seed * 31 + std::hash<float>{}(v.z);
|
||||||
|
|
||||||
|
// ────────────────────────────────────────────────────────────────
|
||||||
|
// Style 3: Treat as 12-byte blob → good quality, but slower on some platforms
|
||||||
|
// std::size_t h = 0;
|
||||||
|
// std::memcpy(&h, &v, sizeof(float)); // x
|
||||||
|
// h ^= std::hash<std::uint32_t>{}(h);
|
||||||
|
// std::memcpy(&h, reinterpret_cast<const char*>(&v) + 4, sizeof(float));
|
||||||
|
// h ^= std::hash<std::uint32_t>{}(h) * 0x85ebca6b;
|
||||||
|
// std::memcpy(&h, reinterpret_cast<const char*>(&v) + 8, sizeof(float));
|
||||||
|
// return std::hash<std::uint32_t>{}(h);
|
||||||
|
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
namespace Artifact {
|
||||||
|
|
||||||
|
template<typename Subsystem>
|
||||||
|
class Engine {
|
||||||
|
public:
|
||||||
|
std::vector<std::unique_ptr<Subsystem>> subsystems;
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
T * addSubsystem(Args &&... args) {
|
||||||
|
auto system = std::make_unique<T>(std::forward<Args>(args)...);
|
||||||
|
auto ptr = system.get();
|
||||||
|
subsystems.push_back(std::move(system));
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
T * subsystem() const {
|
||||||
|
for (const auto & system : subsystems) {
|
||||||
|
if (T * ptr = dynamic_cast<T *>(system.get())) {
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseSubsystem {
|
||||||
|
public:
|
||||||
|
virtual void init() {}
|
||||||
|
virtual void reload() {}
|
||||||
|
virtual void deinit() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> requires std::integral<T> || std::floating_point<T>
|
||||||
|
class Composed {
|
||||||
|
enum ModifierType {
|
||||||
|
Add, Multiply
|
||||||
|
};
|
||||||
|
using Modifier = std::pair<ModifierType, T>;
|
||||||
|
|
||||||
|
uint64_t nextID = 0;
|
||||||
|
|
||||||
|
std::vector<Modifier> modifiers;
|
||||||
|
T _value;
|
||||||
|
public:
|
||||||
|
Composed() : Composed(T{0}) {}
|
||||||
|
Composed(T base) {
|
||||||
|
add(Add, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
T value() {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recompute() {
|
||||||
|
T sum;
|
||||||
|
T fac;
|
||||||
|
for (auto [type, value] : modifiers) {
|
||||||
|
if (type == Add) {
|
||||||
|
sum += value;
|
||||||
|
} else if (type == Multiply) {
|
||||||
|
fac *= value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_value = sum * fac;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t add(ModifierType type, T value) {
|
||||||
|
modifiers.emplace_back(type, value);
|
||||||
|
recompute();
|
||||||
|
return nextID++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(uint64_t id) {
|
||||||
|
auto it = std::find_if(modifiers.begin(), modifiers.end(),
|
||||||
|
[id](const Modifier & m) { return m.id == id; });
|
||||||
|
if (it == modifiers.end()) return false;
|
||||||
|
|
||||||
|
modifiers.erase(it);
|
||||||
|
recompute();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(uint64_t id, T newValue) {
|
||||||
|
auto it = std::find_if(modifiers.begin(), modifiers.end(),
|
||||||
|
[id](const Modifier& m) { return m.id == id; });
|
||||||
|
if (it == modifiers.end()) return false;
|
||||||
|
|
||||||
|
it->value = newValue;
|
||||||
|
recompute();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void log(std::string msg);
|
||||||
|
|
||||||
|
}
|
||||||
9
Shared/World/Chunk.h
Normal file
9
Shared/World/Chunk.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <glm/glm/glm.hpp>
|
||||||
|
|
||||||
|
struct Chunk {
|
||||||
|
glm::ivec3 pos;
|
||||||
|
std::vector<uint16_t> data;
|
||||||
|
bool dirty = false;
|
||||||
|
};
|
||||||
52
TestGame/main.cpp
Normal file
52
TestGame/main.cpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <Client.h>
|
||||||
|
#include <Server.h>
|
||||||
|
#include <Network/Network.h>
|
||||||
|
#include <Paths.h>
|
||||||
|
|
||||||
|
using namespace Artifact;
|
||||||
|
|
||||||
|
struct Args {
|
||||||
|
bool server = false;
|
||||||
|
std::string host = "";
|
||||||
|
std::string port = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
Args args {};
|
||||||
|
for (int i = 0; i < argc; ++i) {
|
||||||
|
if (strcmp(argv[i], "--server")) {
|
||||||
|
args.server = true;
|
||||||
|
} else if (strcmp(argv[i], "--host")) {
|
||||||
|
args.host = argv[++i];
|
||||||
|
} else if (strcmp(argv[i], "--port")) {
|
||||||
|
args.port = argv[++i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataPath();
|
||||||
|
|
||||||
|
Client client;
|
||||||
|
|
||||||
|
client.addDefaultSubsystems();
|
||||||
|
|
||||||
|
std::thread([&client]() {
|
||||||
|
Server server;
|
||||||
|
|
||||||
|
server.addDefaultSubsystems();
|
||||||
|
|
||||||
|
auto serverListener = server.subsystem<NetworkServer>();
|
||||||
|
auto clientConnection = client.subsystem<NetworkClient>();
|
||||||
|
|
||||||
|
serverListener->host(clientConnection);
|
||||||
|
clientConnection->connect(serverListener);
|
||||||
|
|
||||||
|
server.run();
|
||||||
|
}).detach();
|
||||||
|
|
||||||
|
client.run();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue