diff --git a/.gitea/workflows/build_pc.yml b/.gitea/workflows/build_pc.yml index 864c439..a8aade2 100644 --- a/.gitea/workflows/build_pc.yml +++ b/.gitea/workflows/build_pc.yml @@ -12,23 +12,11 @@ env: jobs: build: name: Build desktop - runs-on: ${{matrix.config.os}} + runs-on: ${{matrix.os}} strategy: fail-fast: false matrix: - config: - - { - name: "Windows", - os: windows_x64 - } - - { - name: "Linux", - os: ubuntu-latest - } -# - { -# name: "macOS", -# os: macos-latest -# } + os: [ windows_x64, ubuntu-latest, mac_arm ] steps: - name: Checkout @@ -36,13 +24,13 @@ jobs: with: submodules: true - name: Install Vulkan SDK - if: matrix.config.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' uses: humbletim/install-vulkan-sdk@v1.1.1 with: version: 1.3.250.1 cache: true - name: Install Dev Packages - if: matrix.config.os == 'ubuntu-latest' + if: matrix.os == 'ubuntu-latest' run: > sudo apt update && sudo apt install -y extra-cmake-modules libwayland-dev libxkbcommon-dev xorg-dev libarchive-dev libassimp-dev ninja-build glslang-tools glslang-dev unzip && sudo wget https://sourceforge.net/projects/bin2c/files/1.1/bin2c-1.1.zip && sudo unzip bin2c-1.1.zip && cd bin2c && sudo gcc -o bin2c bin2c.c && sudo mv bin2c /usr/bin @@ -55,3 +43,18 @@ jobs: run: ctest -C ${{env.BUILD_TYPE}} #TODO archive executables + + + build_iOS: + name: Build iOS + runs-on: mac_arm + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: true + - name: Configure CMake + run: mkdir cmake-build && mkdir cmake-build/iOS && cd cmake-build/iOS && cmake ../.. -G Xcode -DCMAKE_TOOLCHAIN_FILE=../../cmake/toolchain/ios.toolchain.cmake -DPLATFORM=OS64 -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + - name: Build & Archive + run: xcodebuild -project ${{github.workspace}}/cmake-build/iOS/openVulkanoCpp.xcodeproj -scheme OpenVulkano_Examples -configuration ${{env.BUILD_TYPE}} -archivePath ${{github.workspace}}/cmake-build/iOS/app.xcarchive -sdk iphoneos archive \ No newline at end of file diff --git a/3rdParty/CMakeLists.txt b/3rdParty/CMakeLists.txt index 6808d83..ff26917 100644 --- a/3rdParty/CMakeLists.txt +++ b/3rdParty/CMakeLists.txt @@ -22,12 +22,12 @@ add_subdirectory(rapidyaml) add_subdirectory(libarchive) add_subdirectory(boost) add_subdirectory(units) +add_subdirectory(libjpeg-turbo) +if (NOT IOS) + add_subdirectory(curl) +endif() if(ENABLE_TEST) add_subdirectory(catch2) endif() -if (NOT IOS) - add_subdirectory(libjpeg-turbo) - add_subdirectory(curl) -endif() diff --git a/3rdParty/glfw/CMakeLists.txt b/3rdParty/glfw/CMakeLists.txt index 0ff8d20..030c155 100644 --- a/3rdParty/glfw/CMakeLists.txt +++ b/3rdParty/glfw/CMakeLists.txt @@ -13,5 +13,8 @@ FetchContent_Declare( ) set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE) +if(APPLE) + set(GLFW_VULKAN_STATIC ON CACHE BOOL "" FORCE) +endif() FetchContent_MakeAvailable(glfw) -set(glfw_FOUND ON PARENT_SCOPE) \ No newline at end of file +set(glfw_FOUND ON PARENT_SCOPE) diff --git a/3rdParty/libarchive/CMakeLists.txt b/3rdParty/libarchive/CMakeLists.txt index fa68821..3955713 100644 --- a/3rdParty/libarchive/CMakeLists.txt +++ b/3rdParty/libarchive/CMakeLists.txt @@ -28,12 +28,21 @@ function(LinkLibArchive TARGET) find_package(zstd QUIET) find_package(BZip2 QUIET) find_package(LibLZMA QUIET) + find_package(LibXml2 QUIET) + find_package(EXPAT QUIET) target_include_directories(${TARGET} PUBLIC ${LibArchive_INCLUDE_DIR}) target_link_libraries(${TARGET} PUBLIC ${LibArchive_LIBRARIES} ${ZLIB_LIBRARIES} ${zstd_LIBRARIES} ${LZ4_LIBRARIES}) + if (BZIP2_LIBRARIES) target_link_libraries(${TARGET} PUBLIC ${BZIP2_LIBRARIES}) endif() if (LIBLZMA_LIBRARIES) target_link_libraries(${TARGET} PUBLIC ${LIBLZMA_LIBRARIES}) endif() -endfunction() \ No newline at end of file + if (LibXml2_FOUND) + target_link_libraries(${TARGET} PUBLIC ${LIBXML2_LIBRARIES}) + endif() + if (EXPAT_FOUND) + target_link_libraries(${TARGET} PUBLIC ${EXPAT_LIBRARIES}) + endif() +endfunction() diff --git a/3rdParty/libjpeg-turbo/CMakeLists.txt b/3rdParty/libjpeg-turbo/CMakeLists.txt index ce77077..425e08c 100644 --- a/3rdParty/libjpeg-turbo/CMakeLists.txt +++ b/3rdParty/libjpeg-turbo/CMakeLists.txt @@ -31,6 +31,11 @@ endif () function(LinkLibJpegTurbo TARGET) + if (IOS) + target_link_libraries(${TARGET} PRIVATE "/opt/libjpeg-turbo-ios/lib/libturbojpeg.a") + target_include_directories(${TARGET} PRIVATE "/opt/libjpeg-turbo-ios/include") + return() + endif () if (libjpeg-turbo_BUILT) FindCmakeConfigDirs("${CMAKE_BINARY_DIR}/deps_ljt/INSTALL/" CMAKE_PREFIX_PATH) endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 92860e0..d289169 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ cmake_minimum_required(VERSION 3.28 FATAL_ERROR) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(CMAKE_CXX_STANDARD 20) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + if(LINUX) find_package(ECM REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) @@ -45,3 +47,5 @@ endif() if(ENABLE_EXAMPLE) add_subdirectory(examples) endif() + +set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT openVulkanoCpp) \ No newline at end of file diff --git a/Scripts/CompileShaders.sh b/Scripts/CompileShaders.sh index 110b161..e613447 100755 --- a/Scripts/CompileShaders.sh +++ b/Scripts/CompileShaders.sh @@ -27,8 +27,8 @@ check_return_code() { fi } -rm -f *.spv mkdir -p "$GENERATED_DATA_PATH" +rm -f "$GENERATED_DATA_PATH/*.spv" touch "$GENERATED_DATA_PATH"/GeneratedShaderData.h touch "$GENERATED_DATA_PATH"/GeneratedShaderData.c @@ -48,13 +48,13 @@ for unique_name in ${unique_file_names[@]} ; do same_files=$(find $SHADER_PATH/ -type f -name "${unique_name}.*") for same_file in ${same_files[@]} ; do filename_with_ext_no_path=$(basename -- "$same_file") - glslangValidator -V $same_file -o $filename_with_ext_no_path.spv + glslangValidator -V $same_file -o "$GENERATED_DATA_PATH/$filename_with_ext_no_path.spv" check_return_code done - bin2c -t -d "$GENERATED_DATA_PATH"/$unique_name.h -o "$GENERATED_DATA_PATH"/$unique_name.c *.spv + (cd "$GENERATED_DATA_PATH" && bin2c -t -d $unique_name.h -o $unique_name.c *.spv) check_return_code - rm *.spv + rm "$GENERATED_DATA_PATH"/*.spv echo -e "#include \"${unique_name}.h\"" >> "$GENERATED_DATA_PATH"/GeneratedShaderData.c filename_no_ext_first_upper=$(echo $unique_name | awk '{print toupper(substr($0,1,1))substr($0,2)}') diff --git a/cmake/functions/AppleHelper.cmake b/cmake/functions/AppleHelper.cmake index 7ab0175..b331843 100644 --- a/cmake/functions/AppleHelper.cmake +++ b/cmake/functions/AppleHelper.cmake @@ -4,14 +4,20 @@ function(LinkAppleFrameworks TARGET) PUBLIC "-framework Foundation" PUBLIC "-framework CoreImage" PUBLIC "-framework CoreVideo" + PUBLIC "-framework CoreGraphics" PUBLIC "-framework Metal" PUBLIC "-framework MetalPerformanceShaders" - PUBLIC "-framework ARKit" + PUBLIC "-framework MetalKit" + PUBLIC "-framework IOSurface" + PUBLIC "-framework QuartzCore" PUBLIC "-lstdc++" PUBLIC c++ PUBLIC c ) + if(IOS) + target_link_libraries(${TARGET} PUBLIC "-framework ARKit") + endif() # Locate system libraries on iOS find_library(UIKIT UIKit) @@ -19,11 +25,20 @@ function(LinkAppleFrameworks TARGET) find_library(MOBILECORESERVICES MobileCoreServices) find_library(CFNETWORK CFNetwork) find_library(SYSTEMCONFIGURATION SystemConfiguration) + find_library(APPKIT AppKit) + find_library(IOSURFACE IOSurface) + find_library(QUARTZ Quartz) # link the frameworks located above - target_link_libraries(${TARGET} PUBLIC ${UIKIT}) + if(IOS) + target_link_libraries(${TARGET} PUBLIC ${UIKIT}) + target_link_libraries(${TARGET} PUBLIC ${MOBILECORESERVICES}) + else() + target_link_libraries(${TARGET} PUBLIC ${APPKIT}) + target_link_libraries(${TARGET} PUBLIC ${QUARTZ}) + endif() + target_link_libraries(${TARGET} PUBLIC ${IOSURFACE}) target_link_libraries(${TARGET} PUBLIC ${FOUNDATION}) - target_link_libraries(${TARGET} PUBLIC ${MOBILECORESERVICES}) target_link_libraries(${TARGET} PUBLIC ${CFNETWORK}) target_link_libraries(${TARGET} PUBLIC ${SYSTEMCONFIGURATION}) -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/functions/Filter.cmake b/cmake/functions/Filter.cmake index dde772f..cb942a4 100644 --- a/cmake/functions/Filter.cmake +++ b/cmake/functions/Filter.cmake @@ -1,9 +1,13 @@ function(FilterPlatformPaths sourcesVar) - if (IOS) list(FILTER ${sourcesVar} EXCLUDE REGEX ".*GLFW.*") + list(FILTER ${sourcesVar} EXCLUDE REGEX ".*[\\/]Host[\\/]MacOS[\\/].*") else () list(FILTER ${sourcesVar} EXCLUDE REGEX ".*[\\/]Host[\\/]iOS[\\/].*") + list(FILTER ${sourcesVar} EXCLUDE REGEX ".*[\\/]AR[\\/]Provider[\\/]ArKit[\\/].*") + endif () + if (NOT APPLE) + list(FILTER ${sourcesVar} EXCLUDE REGEX ".*[\\/]Host[\\/]Apple[\\/].*") endif () if (NOT LINUX) list(FILTER ${sourcesVar} EXCLUDE REGEX ".*[\\/]Host[\\/]Linux[\\/].*") @@ -15,4 +19,4 @@ function(FilterPlatformPaths sourcesVar) list(FILTER ${sourcesVar} EXCLUDE REGEX "main\.(m|mm|c|cpp)") set(${sourcesVar} ${${sourcesVar}} PARENT_SCOPE) -endfunction() \ No newline at end of file +endfunction() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7f2f40b..b0eec3d 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -3,15 +3,42 @@ cmake_minimum_required(VERSION 3.28 FATAL_ERROR) include(SetupVulkan) include(Utils) -file(GLOB_RECURSE SUBDIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") -source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SUBDIRECTORIES}) -add_executable(examples main.cpp ${SUBDIRECTORIES}) +file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp") +if (IOS) + file(GLOB_RECURSE SRC_IOS "${CMAKE_CURRENT_SOURCE_DIR}/Host/iOS/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/Host/iOS/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/Host/iOS/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Host/iOS/*.m" "${CMAKE_CURRENT_SOURCE_DIR}/Host/iOS/*.mm") + list(APPEND SOURCES ${SRC_IOS}) +endif () +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES ${SOURCES}) -target_include_directories(examples PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +set(MAIN_FILE main.cpp) +if (IOS) + set(MAIN_FILE Host/iOS/main.mm) +endif () +add_executable(OpenVulkano_Examples ${MAIN_FILE} ${SOURCES}) +set_property(TARGET OpenVulkano_Examples PROPERTY CXX_STANDARD 20) -target_include_directories(examples PRIVATE openVulkanoCpp) -target_link_libraries(examples PRIVATE "$") -SetupVulkan(examples) -SetGlmDefines(examples) -SetWarningSettings(examples) -LinkCurl(openVulkanoCpp) \ No newline at end of file +# Setup IOS +if(IOS) + set(APP_BUNDLE_IDENTIFIER "eu.georgh93.openVulkano") + set(MACOSX_BUNDLE_INFO_STRING ${APP_BUNDLE_IDENTIFIER}) + set(MACOSX_BUNDLE_GUI_IDENTIFIER ${APP_BUNDLE_IDENTIFIER}) + set(MACOSX_BUNDLE_BUNDLE_NAME ${APP_BUNDLE_IDENTIFIER}) + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}) + + set(CMAKE_XCODE_EMBED_FRAMEWORKS ON) + + set_target_properties(OpenVulkano_Examples PROPERTIES XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "466MGSD624") +endif() +if(APPLE) + LinkAppleFrameworks(OpenVulkano_Examples) +endif () + + + +target_include_directories(OpenVulkano_Examples PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_include_directories(OpenVulkano_Examples PRIVATE openVulkanoCpp) + +target_link_libraries(OpenVulkano_Examples PRIVATE "$") +SetupVulkan(OpenVulkano_Examples) +SetGlmDefines(OpenVulkano_Examples) +SetWarningSettings(OpenVulkano_Examples) \ No newline at end of file diff --git a/examples/ExampleAppList.hpp b/examples/ExampleAppList.hpp new file mode 100644 index 0000000..3308eb3 --- /dev/null +++ b/examples/ExampleAppList.hpp @@ -0,0 +1,23 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "ExampleApps/CubesExampleApp.hpp" +#include "ExampleApps/MovingCubeApp.hpp" +#include "ExampleApps/TexturedCubeExampleApp.hpp" +#include "ExampleApps/BillboardExampleApp.hpp" +#include + +namespace OpenVulkano +{ + const std::vector> EXAMPLE_APPS = { + { "Cubes Example App", &CubesExampleApp::Create }, + { "Moving Cube Example App", &MovingCubeApp::Create }, + { "Textured Cube Example App", &TexturedCubeExampleApp::Create }, + { "Billboard Example App", &BillboardExampleApp::Create } + }; +} diff --git a/examples/ExampleApps/BillboardExampleApp.cpp b/examples/ExampleApps/BillboardExampleApp.cpp index f839f66..3c98ba6 100644 --- a/examples/ExampleApps/BillboardExampleApp.cpp +++ b/examples/ExampleApps/BillboardExampleApp.cpp @@ -52,7 +52,7 @@ namespace OpenVulkano m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboardFromSinglePoint"); m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::GEOMETRY, "Shader/billboardFromSinglePoint"); - m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basicTexture"); + m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basic"); m_quadBillboardShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); m_quadBillboardShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); m_quadBillboardShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); diff --git a/examples/Host/iOS/ExampleViewController.h b/examples/Host/iOS/ExampleViewController.h new file mode 100644 index 0000000..de2621c --- /dev/null +++ b/examples/Host/iOS/ExampleViewController.h @@ -0,0 +1,19 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#import +#import +#import "Host/iOS/OpenVulkanoViewController.h" + +@interface MainMenuViewController : UIViewController +@end + +@interface ExampleViewController : OpenVulkanoViewController +@property(nonatomic, strong)OpenVulkanoView* renderView; +@property size_t exampleId; +@end diff --git a/examples/Host/iOS/ExampleViewController.mm b/examples/Host/iOS/ExampleViewController.mm new file mode 100644 index 0000000..350c9c6 --- /dev/null +++ b/examples/Host/iOS/ExampleViewController.mm @@ -0,0 +1,75 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#import "ExampleViewController.h" + +#include "../../ExampleAppList.hpp" + +@implementation MainMenuViewController +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + + CGFloat buttonHeight = 50; + CGFloat buttonSpacing = 10; + CGFloat topMargin = 50; + + int i = 0; + for (const auto& app : OpenVulkano::EXAMPLE_APPS) + { + UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; + button.frame = CGRectMake(20, + topMargin + i * (buttonHeight + buttonSpacing), + self.view.bounds.size.width - 40, + buttonHeight); + [button setTitle:[NSString stringWithUTF8String:app.first] forState:UIControlStateNormal]; + button.tag = i; + [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; + [self.view addSubview:button]; + i++; + } + + self.view.frame = [UIScreen mainScreen].bounds; + self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +} + +- (void)buttonPressed:(UIButton *)sender { + ExampleViewController* example = [[ExampleViewController alloc] init]; + example.exampleId = sender.tag; + example.modalPresentationStyle = UIModalPresentationFullScreen; + [self presentViewController:example animated:true completion:nil]; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + self.view.frame = self.view.superview.bounds; +} +@end + +@implementation ExampleViewController +- (void)viewDidLoad { + self.renderView = [[OpenVulkanoView alloc] initWithFrame:self.view.frame]; + self.openVulkanoView = self.renderView; + [self.view addSubview:self.renderView]; + [super viewDidLoad]; + + self.view.frame = [UIScreen mainScreen].bounds; + self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + self.view.frame = self.view.superview.bounds; + self.renderView.frame = self.view.frame; +} + +- (BOOL)prefersStatusBarHidden { return true; } + +- (void *)makeGraphicsApp { + return OpenVulkano::EXAMPLE_APPS[self.exampleId].second(); +} +@end diff --git a/examples/Host/iOS/main.mm b/examples/Host/iOS/main.mm new file mode 100644 index 0000000..8bfea05 --- /dev/null +++ b/examples/Host/iOS/main.mm @@ -0,0 +1,57 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#import +#import +#import "ExampleViewController.h" +#import "Host/iOS/OpenVulkanoAppDelegate.h" + +#include "Base/Logger.hpp" + +@interface SceneDelegate : UIResponder +@end + +@implementation SceneDelegate +@synthesize window = _window; +- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { + if ([scene isKindOfClass:[UIWindowScene class]]) { + UIWindowScene* wScene = (UIWindowScene*)scene; + self.window = [[UIWindow alloc] initWithWindowScene:wScene]; + + MainMenuViewController* rootViewController = [[MainMenuViewController alloc] init]; + UINavigationController* navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController]; + + self.window.rootViewController = navigationController; + [self.window makeKeyAndVisible]; + } +} +@end + +@interface AppDelegate : OpenVulkanoAppDelegate +@end + +@implementation AppDelegate +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + // Override point for customization after application launch. + return YES; +} + +- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { + UISceneConfiguration *configuration = [[UISceneConfiguration alloc] initWithName:nil sessionRole:UIWindowSceneSessionRoleApplication]; + configuration.delegateClass = SceneDelegate.class; + return configuration; +} +@end + +int main(int argCount, char** args) +{ + using namespace OpenVulkano; + Logger::SetupLogger(); + @autoreleasepool + { + return UIApplicationMain(argCount, args, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/examples/main.cpp b/examples/main.cpp index 388087e..002e431 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -5,10 +5,7 @@ */ #include "Host/GraphicsAppManager.hpp" -#include "ExampleApps/CubesExampleApp.hpp" -#include "ExampleApps/MovingCubeApp.hpp" -#include "ExampleApps/TexturedCubeExampleApp.hpp" -#include "ExampleApps/BillboardExampleApp.hpp" +#include "ExampleAppList.hpp" #include #include @@ -22,12 +19,11 @@ using namespace OpenVulkano; int main(int argc, char** argv) { - std::vector examples = { - "Cubes Example App", - "Moving Cube Example App", - "Textured Cube Example App", - "Billboard Example App" - }; + std::vector examples; + for (const auto& e : EXAMPLE_APPS) + { + examples.emplace_back(e.first); + } int selectedExample = 0; ftxui::MenuOption option; @@ -37,15 +33,9 @@ int main(int argc, char** argv) screen.Loop(menu); - std::unique_ptr app; - switch (selectedExample) - { - case 0: app = CubesExampleApp::CreateUnique(); break; - case 1: app = MovingCubeApp::CreateUnique(); break; - case 2: app = TexturedCubeExampleApp::CreateUnique(); break; - case 3: app = BillboardExampleApp::CreateUnique(); break; - default: throw std::runtime_error("Invalid menu selection!"); break; - } + if (selectedExample >= examples.size()) throw std::runtime_error("Invalid menu selection!"); + + std::unique_ptr app( EXAMPLE_APPS[selectedExample].second() ); GraphicsAppManager manager(app.get()); manager.Run(); diff --git a/openVulkanoCpp/AR/ArFrame.cpp b/openVulkanoCpp/AR/ArFrame.cpp index 989b713..3bb6b70 100644 --- a/openVulkanoCpp/AR/ArFrame.cpp +++ b/openVulkanoCpp/AR/ArFrame.cpp @@ -7,6 +7,8 @@ #include "ArFrame.hpp" #include "ArSession.hpp" #include "ArRecorder.hpp" +#include +#include namespace OpenVulkano::AR { @@ -26,6 +28,11 @@ namespace OpenVulkano::AR void ArFrame::SaveToFile(const std::filesystem::path& path, bool downsample) { m_session->GetRecorder().SaveToFile(shared_from_this(), path, downsample); + std::string metaContent = GetFrameMetadata().ToXML(); + std::string metaPath = path.string() + std::string(".meta"); + std::ofstream file (metaPath, std::ios::out); + file << metaContent; + file.close(); } const Scene::Texture* ArFrame::GetImageTexture() @@ -38,4 +45,4 @@ namespace OpenVulkano::AR { if (m_texture) m_session->ReturnTexture(m_texture); } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/AR/ArFrame.hpp b/openVulkanoCpp/AR/ArFrame.hpp index b0678ce..c06fcc4 100644 --- a/openVulkanoCpp/AR/ArFrame.hpp +++ b/openVulkanoCpp/AR/ArFrame.hpp @@ -122,7 +122,20 @@ namespace OpenVulkano::AR [[nodiscard]] ArTrackingState GetTrackingState() const { return frameMetadata.trackingState; }; - [[nodiscard]] virtual Math::PoseF GetPose() const { return Math::PoseF(); }; //TODO + [[nodiscard]] virtual Math::PoseF GetPose() const { return Math::PoseF(frameMetadata.transformation); }; + + [[nodiscard]] virtual Math::Vector3f GetEulerAngle() const { + return { + asin(-frameMetadata.transformation[2][1]), + atan2(frameMetadata.transformation[2][0], frameMetadata.transformation[2][2]), + atan2(frameMetadata.transformation[0][1], frameMetadata.transformation[1][1]) + }; + } + + [[nodiscard]] virtual const Math::Vector3f_SIMD& GetPosition() const + { + return reinterpret_cast(frameMetadata.transformation[3]); + } [[nodiscard]] Math::Timestamp GetTimestamp() const { return frameMetadata.timestamp; }; diff --git a/openVulkanoCpp/AR/ArSession.cpp b/openVulkanoCpp/AR/ArSession.cpp index cbf3395..b234af6 100644 --- a/openVulkanoCpp/AR/ArSession.cpp +++ b/openVulkanoCpp/AR/ArSession.cpp @@ -8,8 +8,13 @@ #include "Provider/Playback/ArSessionPlayback.hpp" #include "Provider/Network/ArSessionStream.h" #ifdef __APPLE__ +#include +#if TARGET_OS_IOS == 1 #include "Provider/ArKit/ArSessionArKit.h" #else +#include "Provider/ArSessionNull.hpp" +#endif +#else #ifdef ANDROID #include "Provider/ArCore/ArSessionArCore.h" #else diff --git a/openVulkanoCpp/AR/ArSession.hpp b/openVulkanoCpp/AR/ArSession.hpp index 5a47143..1cf1101 100644 --- a/openVulkanoCpp/AR/ArSession.hpp +++ b/openVulkanoCpp/AR/ArSession.hpp @@ -45,16 +45,22 @@ namespace OpenVulkano::AR ArSessionType sessionType = ArSessionType::NATIVE; bool uncompressed = true; bool depthSupported = false; + bool supportsExposureLocking = false; + bool supportsWhitebalanceLocking = false; + bool hasFlashlight = false; public: ArSessionCapabilities() = default; - ArSessionCapabilities(const ArType type, const ArSessionType sessionType, const bool uncompressed, const bool depthSupported) - : type(type), sessionType(sessionType), uncompressed(uncompressed), depthSupported(depthSupported) + ArSessionCapabilities(const ArType type, const ArSessionType sessionType, const bool uncompressed, const bool depthSupported, const bool supportsExposureLocking, const bool supportsWhitebalanceLocking, const bool hasFlash) + : type(type), sessionType(sessionType), uncompressed(uncompressed), depthSupported(depthSupported), supportsExposureLocking(supportsExposureLocking), supportsWhitebalanceLocking(supportsWhitebalanceLocking), hasFlashlight(hasFlash) {} [[nodiscard]] bool IsUncompressed() const { return uncompressed; } [[nodiscard]] bool IsDepthSupported() const { return depthSupported; } + [[nodiscard]] bool IsExposureLockSupported() const { return supportsExposureLocking; } + [[nodiscard]] bool IsWhitebalanceLockSupported() const { return supportsWhitebalanceLocking; } + [[nodiscard]] bool HasFlashlight() const { return hasFlashlight; } [[nodiscard]] bool IsNative() const { return sessionType == ArSessionType::NATIVE; } [[nodiscard]] bool IsPlayback() const { return sessionType == ArSessionType::PLAYBACK; } [[nodiscard]] bool IsStream() const { return sessionType == ArSessionType::NETWORK_STREAM; } @@ -213,6 +219,12 @@ namespace OpenVulkano::AR * @param renderer The renderer to be used to create textures. */ virtual void SetRenderer(IRenderer* renderer) = 0; + + virtual void LockExposureTime(bool locked) {}; + + virtual void LockWhitebalance(bool locked) {}; + + virtual void SetFlashlightOn(bool on) {}; /** * Gets the capabilities for this ArSession. diff --git a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKit.mm b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKit.mm index d9fb276..f1f75ed 100644 --- a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKit.mm +++ b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKit.mm @@ -14,7 +14,7 @@ namespace OpenVulkano::AR::ArKit ArSessionCapabilities QueryNativeCapabilities() { bool supportsDepth = [ARWorldTrackingConfiguration supportsFrameSemantics:ARFrameSemanticSceneDepth]; - ArSessionCapabilities capabilities(ArType::AR_KIT, ArSessionType::NATIVE, true, supportsDepth); + ArSessionCapabilities capabilities(ArType::AR_KIT, ArSessionType::NATIVE, true, supportsDepth, true, true, true); return capabilities; } } diff --git a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.h b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.h index 5fc8f8d..75c7e10 100644 --- a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.h +++ b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.h @@ -50,6 +50,10 @@ namespace OpenVulkano::AR::ArKit bool ArShouldAttemptRelocalization(); void SetRenderer(IRenderer* renderer) override; + + void LockExposureTime(bool locked) override; + void LockWhitebalance(bool locked) override; + void SetFlashlightOn(bool on) override; protected: Scene::Texture * MakeTexture(ArFrame *frame) override; @@ -66,6 +70,9 @@ namespace OpenVulkano::AR::ArKit #else*/ SpintexProtectedObject> m_frame; //#endif - std::atomic_size_t m_frameId; + std::atomic_size_t m_frameId = 0; + bool m_lockedConfiguration = false; + bool m_lockedExposure = false; + bool m_lockedWhitebalance = false; }; } diff --git a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.mm b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.mm index 0556893..08f5a10 100644 --- a/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.mm +++ b/openVulkanoCpp/AR/Provider/ArKit/ArSessionArKitInternal.mm @@ -22,6 +22,7 @@ #import #import #import +#import #import #import "ArKitDelegate.h" @@ -138,6 +139,11 @@ namespace OpenVulkano::AR::ArKit void ArSessionArKitInternal::Stop() { + if (m_lockedConfiguration) + { + m_lockedConfiguration = false; + [[ARWorldTrackingConfiguration configurableCaptureDeviceForPrimaryCamera] unlockForConfiguration]; + } OnStopped(); [m_arSession pause]; /*#if (__cplusplus >= 202002L) @@ -183,6 +189,27 @@ namespace OpenVulkano::AR::ArKit Logger::AR->warn("Failed to perform high resolution still frame capture: requires iOS 16 or later!"); } } + + void ArSessionArKitInternal::LockExposureTime(bool locked) + { + AVCaptureDevice* dev = [ARWorldTrackingConfiguration configurableCaptureDeviceForPrimaryCamera]; + if (!m_lockedConfiguration) m_lockedConfiguration |=[dev lockForConfiguration:nil]; + [dev setExposureMode: locked ? AVCaptureExposureModeLocked : AVCaptureExposureModeContinuousAutoExposure]; + } + + void ArSessionArKitInternal::LockWhitebalance(bool locked) + { + AVCaptureDevice* dev = [ARWorldTrackingConfiguration configurableCaptureDeviceForPrimaryCamera]; + if (!m_lockedConfiguration) m_lockedConfiguration |=[dev lockForConfiguration:nil]; + [dev setWhiteBalanceMode: locked ? AVCaptureWhiteBalanceModeLocked : AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance]; + } + + void ArSessionArKitInternal::SetFlashlightOn(bool on) + { + AVCaptureDevice* dev = [ARWorldTrackingConfiguration configurableCaptureDeviceForPrimaryCamera]; + if (!m_lockedConfiguration) m_lockedConfiguration |=[dev lockForConfiguration:nil]; + [dev setTorchMode: on ? AVCaptureTorchModeOn : AVCaptureTorchModeOff]; + } // AR Kit delegate events diff --git a/openVulkanoCpp/AR/Provider/Playback/ArSessionPlayback.cpp b/openVulkanoCpp/AR/Provider/Playback/ArSessionPlayback.cpp index 47fd852..480708e 100644 --- a/openVulkanoCpp/AR/Provider/Playback/ArSessionPlayback.cpp +++ b/openVulkanoCpp/AR/Provider/Playback/ArSessionPlayback.cpp @@ -17,7 +17,7 @@ namespace OpenVulkano::AR::Playback ArSessionPlayback::ArSessionPlayback(const std::string& recordingPath, bool autoAdvance) : ArSession(ArSessionMetadata(recordingPath)), recordingPath(recordingPath), autoAdvance(autoAdvance), playbackReader(recordingPath) { - capabilities = ArSessionCapabilities(metadata.type, ArSessionType::PLAYBACK, false, metadata.depthFormat != ArDepthFormat::UNAVAILABLE); + capabilities = ArSessionCapabilities(metadata.type, ArSessionType::PLAYBACK, false, metadata.depthFormat != ArDepthFormat::UNAVAILABLE, false, false, false); constants = { Math::Matrix4f(1), metadata.confidenceRange }; m_playbackReaderThread = std::thread([this](){ReadWorker();}); diff --git a/openVulkanoCpp/Base/Event.hpp b/openVulkanoCpp/Base/Event.hpp index 5224a70..a547e88 100644 --- a/openVulkanoCpp/Base/Event.hpp +++ b/openVulkanoCpp/Base/Event.hpp @@ -227,12 +227,30 @@ namespace OpenVulkano {} void Notify(Arguments... args) const override + { + NotifyImpl(std::forward(args)...); + } + + void NotifyImpl(Arguments... args) const { if (INamedEventProcessor::HasProcessor()) { std::vector attributes; attributes.reserve(sizeof...(Arguments)); - (attributes.emplace_back(args), ...); + if constexpr (!std::conjunction_v>...>) + { + (attributes.emplace_back(args), ...); + } + else + { + auto fill = [&](auto&& arg) { + if constexpr (std::is_enum_v>) + attributes.emplace_back(static_cast(arg)); + else + attributes.emplace_back(std::forward(arg)); + }; + (fill(std::forward(args)), ...); + } INamedEventProcessor::NotifyAll(m_name, attributes); } } diff --git a/openVulkanoCpp/Base/Observable.hpp b/openVulkanoCpp/Base/Observable.hpp index 2569e8d..d364afc 100644 --- a/openVulkanoCpp/Base/Observable.hpp +++ b/openVulkanoCpp/Base/Observable.hpp @@ -32,14 +32,14 @@ namespace OpenVulkano {} Observable(T&& initValue, const std::string& observableName) - : object(std::forward(initValue)), OnChange(observableName) + : object(initValue), OnChange(observableName) {} template>> auto& operator = (const T& val) { object = val; Notify(); return *this; } template>> - auto& operator = (T&& val) { object = std::forward(val); Notify(); return *this; } + auto& operator = (T&& val) { object = val; Notify(); return *this; } template>> operator T() const { return object; } @@ -54,7 +54,9 @@ namespace OpenVulkano bool operator >=(const T& other) const { return object >= other; } bool operator !() const { return !object; } - operator bool() const { return object.operator bool(); } + template>> + operator bool() const { return static_cast(object); } + auto& operator ++() { ++object; Notify(); return *this; } auto& operator --() { --object; Notify(); return *this; } auto& operator ++(int) { object++; Notify(); return *this; } diff --git a/openVulkanoCpp/Base/Render/IRenderer.hpp b/openVulkanoCpp/Base/Render/IRenderer.hpp index 3c01ef3..59d8dd7 100644 --- a/openVulkanoCpp/Base/Render/IRenderer.hpp +++ b/openVulkanoCpp/Base/Render/IRenderer.hpp @@ -35,5 +35,8 @@ namespace OpenVulkano virtual Scene::UI::Ui* GetActiveUi() = 0; virtual IResourceManager* GetIResourceManager() = 0; + + virtual float GetLastQueriedDepthValue() = 0; + virtual void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) = 0; }; } diff --git a/openVulkanoCpp/Base/UI/IWindow.hpp b/openVulkanoCpp/Base/UI/IWindow.hpp index e685073..aee6a6e 100644 --- a/openVulkanoCpp/Base/UI/IWindow.hpp +++ b/openVulkanoCpp/Base/UI/IWindow.hpp @@ -84,6 +84,9 @@ namespace OpenVulkano [[nodiscard]] virtual uint32_t GetWindowId() const = 0; virtual void* GetNativeWindowHandle() = 0; + + virtual float GetContentScale() const { return 1; } + virtual float GetInterfaceOrientation() const { return 0; } protected: static uint32_t CreateWindowId() { diff --git a/openVulkanoCpp/Base/Utils.hpp b/openVulkanoCpp/Base/Utils.hpp index 97def0c..0697990 100644 --- a/openVulkanoCpp/Base/Utils.hpp +++ b/openVulkanoCpp/Base/Utils.hpp @@ -46,6 +46,12 @@ namespace OpenVulkano return result; } + template + static auto MakeStdArray(N&&... args) -> std::array + { + return { std::forward(args)... }; + } + template static bool GetFlag(T var, U flag) { diff --git a/openVulkanoCpp/CMakeLists.txt b/openVulkanoCpp/CMakeLists.txt index ff01292..d31db98 100644 --- a/openVulkanoCpp/CMakeLists.txt +++ b/openVulkanoCpp/CMakeLists.txt @@ -15,22 +15,19 @@ configure_file(${CMAKE_SOURCE_DIR}/cmake/TryCompileShaders.cmake.in ${CMAKE_BINA execute_process(COMMAND ${BASH_EXECUTABLE} CompileShaders.sh "${SHADER_OUTPUT_DEST}" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/Scripts) file(GLOB GENERATED_SHADER_SOURCES "${SHADER_OUTPUT_DEST}/*") -if(IOS) - set(CMAKE_Swift_LANGUAGE_VERSION 5.0) - enable_language(Swift) - file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.mm" "${CMAKE_CURRENT_SOURCE_DIR}/*.m" "${CMAKE_CURRENT_SOURCE_DIR}/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.swift") +file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") - add_library(openVulkanoCpp STATIC main.m ${resources} ${GENERATED_SHADER_SOURCES}) -else() - file(GLOB_RECURSE sources CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.h" "${CMAKE_CURRENT_SOURCE_DIR}/*.c" "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp") - file(GLOB SHADER_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Shader/*) - list(FILTER SHADER_SRC_FILES EXCLUDE REGEX ".*\\.(hpp|cpp)$") - add_library(openVulkanoCpp STATIC main.cpp ${SHADER_SRC_FILES} ${GENERATED_SHADER_SOURCES}) - if (MSVC) - set_property(GLOBAL PROPERTY USE_FOLDERS ON) - source_group("Shaders" FILES ${SHADER_SRC_FILES}) - endif() -endif() +if (APPLE) + file(GLOB_RECURSE sources_obj CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.mm" "${CMAKE_CURRENT_SOURCE_DIR}/*.m") + list(APPEND sources ${sources_obj}) +endif () + +file(GLOB SHADER_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/Shader/*) +list(FILTER SHADER_SRC_FILES EXCLUDE REGEX ".*\\.(hpp|cpp)$") + +add_library(openVulkanoCpp ${MAIN_FILE} ${SHADER_SRC_FILES} ${GENERATED_SHADER_SOURCES}) +set_property(TARGET openVulkanoCpp PROPERTY CXX_STANDARD 20) +source_group("Shaders" FILES ${SHADER_SRC_FILES}) FilterPlatformPaths(sources) SetWarningSettings(openVulkanoCpp) @@ -39,25 +36,12 @@ SetGlmDefines(openVulkanoCpp) target_sources(openVulkanoCpp PRIVATE ${sources}) target_include_directories(openVulkanoCpp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${SHADER_OUTPUT_DEST}) -# Setup IOS -if(IOS) - set(APP_BUNDLE_IDENTIFIER "eu.georgh93.openVulkano") - set(MACOSX_BUNDLE_INFO_STRING ${APP_BUNDLE_IDENTIFIER}) - set(MACOSX_BUNDLE_GUI_IDENTIFIER ${APP_BUNDLE_IDENTIFIER}) - set(MACOSX_BUNDLE_BUNDLE_NAME ${APP_BUNDLE_IDENTIFIER}) - - set(CMAKE_OSX_DEPLOYMENT_TARGET "14.1") # The used ARKit features are only available starting with iOS 14 - +if(APPLE) LinkAppleFrameworks(openVulkanoCpp) endif () if (WIN32) - # Ws2 target_link_libraries(openVulkanoCpp PRIVATE Ws2_32) - - set(CURL_STATIC_LIBS ${CMAKE_BINARY_DIR}/deps_curl/deps_curl) - file(GLOB_RECURSE LIBS "${CURL_STATIC_LIBS}/*.lib") - target_link_libraries(openVulkanoCpp PRIVATE ${LIBS}) endif () SetupVulkan(openVulkanoCpp) @@ -68,22 +52,15 @@ SetShaderDependency(openVulkanoCpp if (NOT ANDROID AND NOT IOS) target_link_libraries(openVulkanoCpp PUBLIC glfw pugixml) target_link_libraries(openVulkanoCpp PUBLIC ftxui::screen ftxui::dom ftxui::component) + LinkCurl(openVulkanoCpp) endif() -list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/deps/INSTALL) - -target_link_libraries(openVulkanoCpp PUBLIC magic_enum yaml-cpp fmt spdlog glm pugixml stb eigen utf8cpp imgui_internal TracyClient stud-uuid ryml unordered_dense Boost::regex) -LinkCurl(openVulkanoCpp) - -add_compile_definitions(LIBARCHIVE_STATIC) -add_compile_definitions(NOMINMAX) - -add_compile_definitions("DEBUG=$") - -SetGlmDefines(openVulkanoCpp) - +target_link_libraries(openVulkanoCpp PUBLIC magic_enum yaml-cpp fmt spdlog glm pugixml stb eigen utf8cpp imgui_internal TracyClient stud-uuid ryml unordered_dense units) LinkAssimp(openVulkanoCpp) LinkLibArchive(openVulkanoCpp) LinkLibJpegTurbo(openVulkanoCpp) -set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT openVulkanoCpp) +SetGlmDefines(openVulkanoCpp) +add_compile_definitions(LIBARCHIVE_STATIC) +add_compile_definitions(NOMINMAX) +add_compile_definitions("DEBUG=$") diff --git a/openVulkanoCpp/Controller/ArcballCameraController.cpp b/openVulkanoCpp/Controller/ArcballCameraController.cpp index a2054dd..3fb67b9 100644 --- a/openVulkanoCpp/Controller/ArcballCameraController.cpp +++ b/openVulkanoCpp/Controller/ArcballCameraController.cpp @@ -62,8 +62,8 @@ namespace OpenVulkano if (vec != Math::Vector3f_SIMD (0)) { if (Math::Utils::length2(vec) > 1.0f) - { - vec = Math::Utils::normalize(vec); + { //TODO only do this for keyboards + //vec = Math::Utils::normalize(vec); } const float timeScale = CURRENT_FRAME.frameTime; //TODO vec = vec * timeScale * 3.0f; // scale vector @@ -149,12 +149,12 @@ namespace OpenVulkano { m_actionForward->BindKey(Input::InputKey::Controller::AXIS_LEFT_Y); m_actionForward->BindAxisButtons(Input::InputKey::Keyboard::KEY_W, Input::InputKey::Keyboard::KEY_S); - m_actionForward->BindKey(Input::InputKey::Touch::AXIS_PINCH, 0.2f); + m_actionForward->BindKey(Input::InputKey::Touch::AXIS_PINCH, 0.3f); m_actionSide->BindKey(Input::InputKey::Controller::AXIS_LEFT_X); m_actionSide->BindAxisButtons(Input::InputKey::Keyboard::KEY_D, Input::InputKey::Keyboard::KEY_A); - m_actionSide->BindKey(Input::InputKey::Touch::AXIS_PAN_TWO_FINGERS_X, -0.03f); + m_actionSide->BindKey(Input::InputKey::Touch::AXIS_PAN_TWO_FINGERS_X, -0.05f); m_actionUp->BindAxisButtons(Input::InputKey::Keyboard::KEY_SPACE, Input::InputKey::Keyboard::KEY_LEFT_CONTROL); - m_actionUp->BindKey(Input::InputKey::Touch::AXIS_PAN_TWO_FINGERS_Y, 0.03f); + m_actionUp->BindKey(Input::InputKey::Touch::AXIS_PAN_TWO_FINGERS_Y, 0.05f); m_actionLookUp->BindKey(Input::InputKey::Controller::AXIS_RIGHT_Y); m_actionLookUp->BindAxisButtons(Input::InputKey::Keyboard::KEY_DOWN, Input::InputKey::Keyboard::KEY_UP); m_actionLookUp->BindKey(Input::InputKey::Touch::AXIS_PAN_Y, -0.001f); diff --git a/openVulkanoCpp/Controller/FreeCamCameraController.cpp b/openVulkanoCpp/Controller/FreeCamCameraController.cpp index 393514f..71da9cc 100644 --- a/openVulkanoCpp/Controller/FreeCamCameraController.cpp +++ b/openVulkanoCpp/Controller/FreeCamCameraController.cpp @@ -48,6 +48,7 @@ namespace OpenVulkano Math::Matrix4f camTransformation = Math::Utils::toMat4(rot); camTransformation[3] = Math::Vector4f(m_position, 1); GetCamera()->SetMatrix(camTransformation); + CURRENT_FRAME.needsRedraw = true; } void FreeCamCameraController::SetDefaultKeybindings() diff --git a/openVulkanoCpp/Host/iOS/BundledResoureLoaderIos.h b/openVulkanoCpp/Host/Apple/BundledResoureLoaderIos.h similarity index 100% rename from openVulkanoCpp/Host/iOS/BundledResoureLoaderIos.h rename to openVulkanoCpp/Host/Apple/BundledResoureLoaderIos.h diff --git a/openVulkanoCpp/Host/iOS/BundledResoureLoaderIos.mm b/openVulkanoCpp/Host/Apple/BundledResoureLoaderIos.mm similarity index 90% rename from openVulkanoCpp/Host/iOS/BundledResoureLoaderIos.mm rename to openVulkanoCpp/Host/Apple/BundledResoureLoaderIos.mm index a6e04ec..603dacb 100644 --- a/openVulkanoCpp/Host/iOS/BundledResoureLoaderIos.mm +++ b/openVulkanoCpp/Host/Apple/BundledResoureLoaderIos.mm @@ -22,9 +22,10 @@ namespace OpenVulkano { auto [fileName, fileType] = Utils::SplitAtLastOccurrence(resourceName, '.'); NSString* filePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithUTF8String:fileName.c_str()] ofType:[NSString stringWithUTF8String:fileType.c_str()]]; - return Utils::ReadFile(std::string([filePath UTF8String])); + if (filePath) + return Utils::ReadFile(std::string([filePath UTF8String])); } Logger::FILESYS->warn("Failed to find resource: '{}' in bundle", resourceName); - return {0}; + return {}; } } diff --git a/openVulkanoCpp/Host/iOS/MetalViewWindow.h b/openVulkanoCpp/Host/Apple/MetalViewWindow.h similarity index 86% rename from openVulkanoCpp/Host/iOS/MetalViewWindow.h rename to openVulkanoCpp/Host/Apple/MetalViewWindow.h index 94c1613..1925c35 100644 --- a/openVulkanoCpp/Host/iOS/MetalViewWindow.h +++ b/openVulkanoCpp/Host/Apple/MetalViewWindow.h @@ -16,6 +16,8 @@ namespace OpenVulkano IWindowHandler* handler = nullptr; void* caMetalLayer = nullptr; bool tickHandler = true; + float contentScale = 1; + float orientation = 0; public: void Init(RenderAPI::RenderApi renderApi) override {} @@ -82,6 +84,14 @@ namespace OpenVulkano void Close() override {} void OnResize(uint32_t width, uint32_t height); + + virtual float GetContentScale() const override { return contentScale; } + + virtual float GetInterfaceOrientation() const override { return orientation; } + + void SetContentScale(float scale) { contentScale = scale; } + + void SetOrientation(float orientation) { this->orientation = orientation; } void TickHandler(); }; diff --git a/openVulkanoCpp/Host/iOS/MetalViewWindow.mm b/openVulkanoCpp/Host/Apple/MetalViewWindow.mm similarity index 100% rename from openVulkanoCpp/Host/iOS/MetalViewWindow.mm rename to openVulkanoCpp/Host/Apple/MetalViewWindow.mm diff --git a/openVulkanoCpp/Host/iOS/NamedEventProcessor.h b/openVulkanoCpp/Host/Apple/NamedEventProcessor.h similarity index 100% rename from openVulkanoCpp/Host/iOS/NamedEventProcessor.h rename to openVulkanoCpp/Host/Apple/NamedEventProcessor.h diff --git a/openVulkanoCpp/Host/iOS/NamedEventProcessor.mm b/openVulkanoCpp/Host/Apple/NamedEventProcessor.mm similarity index 99% rename from openVulkanoCpp/Host/iOS/NamedEventProcessor.mm rename to openVulkanoCpp/Host/Apple/NamedEventProcessor.mm index 6e6227f..3a6bdea 100644 --- a/openVulkanoCpp/Host/iOS/NamedEventProcessor.mm +++ b/openVulkanoCpp/Host/Apple/NamedEventProcessor.mm @@ -159,12 +159,12 @@ namespace OpenVulkano } else { - Logger::MANAGER->error("Cannot find constructor for named event %s", eventName); + Logger::MANAGER->error("Cannot find constructor for named event {}", eventName); } } else { - Logger::MANAGER->debug("Cannot find implementation for named event %s", eventName); + Logger::MANAGER->debug("Cannot find implementation for named event {}", eventName); } } } diff --git a/openVulkanoCpp/Host/ImGuiImplOpenVulkano.cpp b/openVulkanoCpp/Host/ImGuiImplOpenVulkano.cpp index e89ef03..361d4b8 100644 --- a/openVulkanoCpp/Host/ImGuiImplOpenVulkano.cpp +++ b/openVulkanoCpp/Host/ImGuiImplOpenVulkano.cpp @@ -45,7 +45,7 @@ namespace OpenVulkano if (w > 0 && h > 0) io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);*/ io.DisplaySize = { static_cast(m_window->GetWidth()), static_cast(m_window->GetHeight()) }; - io.DisplayFramebufferScale = { 1, 1 }; + io.DisplayFramebufferScale = { m_window->GetContentScale(), m_window->GetContentScale() }; //if (bd->WantUpdateMonitors) //ImGui_ImplGlfw_UpdateMonitors(); @@ -68,4 +68,4 @@ namespace OpenVulkano io.BackendPlatformUserData = nullptr; io.BackendFlags = ImGuiBackendFlags_None; } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/Host/MacOS/SystemInfo.mm b/openVulkanoCpp/Host/MacOS/SystemInfo.mm new file mode 100644 index 0000000..4e37d0f --- /dev/null +++ b/openVulkanoCpp/Host/MacOS/SystemInfo.mm @@ -0,0 +1,183 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "Host/SystemInfo.hpp" +#include "Base/Logger.hpp" +#include + +#include +#include + +#import +#import + +namespace OpenVulkano +{ + Event<> SystemInfo::OnLowPowerModeChanged; + Event<> SystemInfo::OnBatteryStateChanged; + Event<> SystemInfo::OnBatteryLevelChanged; + Event<> SystemInfo::OnDeviceOrientationChanged; + + size_t SystemInfo::GetSystemRam() + { + return [NSProcessInfo processInfo].physicalMemory; + } + + size_t SystemInfo::GetSystemRamAvailable() + { + return 0; //TODO + } + + size_t SystemInfo::GetAppRamMax() + { + return GetAppRamAvailable() + GetAppRamUsed(); + } + + size_t SystemInfo::GetAppVirtualMemoryMax() + { + return INT64_MAX; + } + + size_t SystemInfo::GetAppRamAvailable() + { + return 0; //TODO + } + + size_t SystemInfo::GetAppRamUsed() + { + struct task_basic_info info; + mach_msg_type_number_t size = sizeof(info); + kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size); + if( kerr == KERN_SUCCESS ) + { + return info.resident_size; + } + Logger::PERF->error("Failed to read memory consumption: {}", mach_error_string(kerr)); + return 0; + } + + std::string SystemInfo::GetUserName() + { + return ""; + } + + std::string SystemInfo::GetHostName() + { + return [[NSProcessInfo processInfo].hostName UTF8String]; + } + + std::string SystemInfo::GetDeviceName() + { + return "Mac"; //TODO + } + + std::string SystemInfo::GetDeviceVendorName() + { + return "Apple"; + } + + std::string SystemInfo::GetDeviceModelName() + { + return ""; //TODO + } + + std::string SystemInfo::GetOsName() + { + return ""; //TODO + } + + OsVersion SystemInfo::GetOsVersion() + { + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + return { static_cast(osVersion.majorVersion), static_cast(osVersion.minorVersion), static_cast(osVersion.patchVersion), 0 }; + } + + std::string SystemInfo::GetOsNameHumanReadable() + { + std::stringstream name; + name << GetOsName() << ' ' << GetOsVersion().major; + return name.str(); + } + + DeviceType SystemInfo::GetDeviceType() + { + return DeviceType::PC; + } + + size_t SystemInfo::GetCpuCoreCount() + { + return [NSProcessInfo processInfo].processorCount; + } + + size_t SystemInfo::GetCpuThreadCount() + { + return [NSProcessInfo processInfo].activeProcessorCount; + } + + int32_t SystemInfo::GetCpuTemperature() + { + switch([NSProcessInfo processInfo].thermalState) + { + case NSProcessInfoThermalStateNominal: return 20; + case NSProcessInfoThermalStateFair: return 50; + case NSProcessInfoThermalStateSerious: return 80; + case NSProcessInfoThermalStateCritical: return 100; + } + return -1; + } + + CpuThermalState SystemInfo::GetCpuThermalState() + { + switch([NSProcessInfo processInfo].thermalState) + { + case NSProcessInfoThermalStateNominal: return CpuThermalState::Normal; + case NSProcessInfoThermalStateFair: return CpuThermalState::Fair; + case NSProcessInfoThermalStateSerious: return CpuThermalState::Serious; + case NSProcessInfoThermalStateCritical: return CpuThermalState::Critical; + } + return CpuThermalState::Normal; + } + + bool SystemInfo::IsDeviceInLowPowerMode() + { + return [NSProcessInfo processInfo].lowPowerModeEnabled; + } + + void SystemInfo::EnableEnergyEvents() + { + //TODO + } + + BatteryState SystemInfo::GetDeviceBatteryState() + { + return BatteryState::Unavailable; //TODO + } + + float SystemInfo::GetDeviceBatteryLevel() + { + return 0; //TODO + } + + bool SystemInfo::IsMultitaskingSupported() + { + return true; + } + + DeviceOrientation SystemInfo::GetDeviceOrientation() + { + return DeviceOrientation::LandscapeRight; + } + + void SystemInfo::EnableDeviceOrientationEvents() + { + //TODO? + } + + InterfaceOrientation SystemInfo::GetInterfaceOrientation() + { + return InterfaceOrientation::Landscape; //TODO? + } +} diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoOrientationLockableViewController.mm b/openVulkanoCpp/Host/iOS/OpenVulkanoOrientationLockableViewController.mm index 7fb3a4b..c598971 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoOrientationLockableViewController.mm +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoOrientationLockableViewController.mm @@ -11,7 +11,7 @@ @implementation OpenVulkanoOrientationLockableViewController -(id)init { - [super init]; + self = [super init]; _rotationLockedView = nil; return self; } diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoView.h b/openVulkanoCpp/Host/iOS/OpenVulkanoView.h index 0783328..bc82044 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoView.h +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoView.h @@ -21,4 +21,6 @@ -(void)WillDisappear; -(void)DidDisappear; -(void)DidUnload; + +-(void)SetInterfaceOrientation:(float)orientation; @end diff --git a/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm b/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm index cd47b8a..76f1dec 100644 --- a/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm +++ b/openVulkanoCpp/Host/iOS/OpenVulkanoView.mm @@ -9,7 +9,7 @@ #include "Base/Logger.hpp" #include "Input/Touch/InputDeviceTouch.hpp" #include "Input/InputManager.hpp" -#include "MetalViewWindow.h" +#include "Host/Apple/MetalViewWindow.h" #include #import @@ -35,6 +35,7 @@ using namespace OpenVulkano; - (void) mtkView:(MTKView *) view drawableSizeWillChange:(CGSize) size { + window->SetContentScale(UIScreen.mainScreen.nativeScale); window->OnResize(size.width, size.height); } @@ -82,9 +83,8 @@ using namespace OpenVulkano; - (void)commonInit { [self setMultipleTouchEnabled:YES]; - - self.contentScaleFactor = UIScreen.mainScreen.nativeScale / 1.5f; - + + self.contentScaleFactor = UIScreen.mainScreen.nativeScale; auto size = self.bounds.size; auto sizeX = size.width * self.contentScaleFactor; auto sizeY = size.height * self.contentScaleFactor; @@ -126,10 +126,17 @@ using namespace OpenVulkano; auto size = self.bounds.size; auto sizeX = size.width * self.contentScaleFactor; auto sizeY = size.height * self.contentScaleFactor; + m_window.SetContentScale(self.contentScaleFactor); m_window.OnResize(sizeX, sizeY); } } + +- (void)SetInterfaceOrientation:(float)orientation +{ + m_window.SetOrientation(orientation); +} + - (Math::Vector2f)getTouchPosition:(UITouch*)touch { CGPoint uitouchLocation = [touch locationInView:touch.view]; diff --git a/openVulkanoCpp/Scene/Camera.hpp b/openVulkanoCpp/Scene/Camera.hpp index 229f48c..08dfac3 100644 --- a/openVulkanoCpp/Scene/Camera.hpp +++ b/openVulkanoCpp/Scene/Camera.hpp @@ -17,7 +17,7 @@ namespace OpenVulkano::Scene { public: ICloseable* renderCamera = nullptr; - static constexpr inline size_t SIZE = sizeof(Math::Matrix4f) * 3 + sizeof(Math::Vector4f) + sizeof(float) * 8 + 16; + static constexpr inline size_t SIZE = sizeof(Math::Matrix4f) * 3 + sizeof(Math::Vector4f) + sizeof(float) * 12; static constexpr inline DescriptorSetLayoutBinding DESCRIPTOR_SET_LAYOUT_BINDING = { 0, DescriptorSetLayoutBinding::Type::TYPE_UNIFORM_BUFFER_DYNAMIC, 1, ShaderProgramType::ALL_GRAPHICS }; protected: @@ -26,7 +26,8 @@ namespace OpenVulkano::Scene float m_nearPlane, m_farPlane, m_width, m_height; float m_fov = 0, m_aspect = 0, m_scaleFactor = 0, m_perPixelScaleFactor = 0; float m_contentScaleFactor = 1, m_zoom = 1; // For use with ortho camera - std::array m_userData{}; + float m_interfaceOrientation = 0; + float m_padding = 0; //Unused Camera() : m_nearPlane(0), m_farPlane(0), m_width(0), m_height(0) {} @@ -55,32 +56,19 @@ namespace OpenVulkano::Scene virtual void SetSize(const float width, const float height) { - if (m_width == width && m_height == height) return; + if (m_width == width && m_height == height) [[likely]] return; m_width = width; m_height = height; UpdateProjectionMatrix(); } - void SetNearPlane(float nearPlane) - { - m_nearPlane = nearPlane; - } + void SetNearPlane(float nearPlane) { m_nearPlane = nearPlane; } - void SetFarPlane(float farPlane) - { - m_farPlane = farPlane; - } + void SetFarPlane(float farPlane) { m_farPlane = farPlane; } + [[nodiscard]] float NearPlane() const { return m_nearPlane; } - [[nodiscard]] float NearPlane() const - { - return m_nearPlane; - } - - [[nodiscard]] float FarPlane() const - { - return m_farPlane; - } + [[nodiscard]] float FarPlane() const { return m_farPlane; } void SetContentScaleFactor(float contentScale = 1) { @@ -88,6 +76,10 @@ namespace OpenVulkano::Scene } [[nodiscard]] float GetContentScaleFactor() const { return 1.0f / m_contentScaleFactor; } + + void SetInterfaceOrientation(float orientation) { m_interfaceOrientation = orientation; } + + float GetInterfaceOrientation() const { return m_interfaceOrientation; } void SetZoom(float zoom) { m_zoom = 1.0f / zoom; } @@ -126,10 +118,7 @@ namespace OpenVulkano::Scene return m_viewProjection; } - [[nodiscard]] const Math::Vector4f& GetPosition() const - { - return m_camPosition; - } + [[nodiscard]] const Math::Vector4f& GetPosition() const { return m_camPosition; } [[nodiscard]] Math::Vector3f GetRightVector() const { @@ -149,23 +138,20 @@ namespace OpenVulkano::Scene [[nodiscard]] auto GetForward() const { return GetViewDirection(); } [[nodiscard]] const Math::Matrix4f& GetViewMatrix() const { return m_view; } - - [[nodiscard]] Math::Frustum GetFrustum() const - { - return {m_viewProjection}; - } - /** - * The 16 byte of user data can be used to transmit additional data about the camera to the shader. - * @return reference to the custom data array - */ - [[nodiscard]] std::array& GetUserData() { return m_userData; } + [[nodiscard]] const Math::Matrix4f& GetProjectionMatrix() const { return m_projection; } + + [[nodiscard]] Math::Frustum GetFrustum() const { return {m_viewProjection}; } [[nodiscard]] float GetScaleFactor() const { return m_scaleFactor; } [[nodiscard]] float GetPixelScaleFactor() const { return m_perPixelScaleFactor; } [[nodiscard]] virtual bool IsPerspective() const { return false; } [[nodiscard]] virtual bool IsOrtho() const { return false; } + + float GetWidth() const { return m_width; } + float GetHeight() const { return m_height; } + Math::Vector2f GetSize() const { return { m_width, m_height }; } }; class PerspectiveCamera : public Camera @@ -202,6 +188,7 @@ namespace OpenVulkano::Scene void SetSize(const float width, const float height) override { + if (m_width == width && m_height == height) [[likely]] return; m_aspect = width / height; Camera::SetSize(width, height); m_perPixelScaleFactor = m_height / m_scaleFactor; @@ -235,20 +222,14 @@ namespace OpenVulkano::Scene m_perPixelScaleFactor = m_height / m_scaleFactor; } - [[nodiscard]] float GetFov() const - { - return Math::Utils::degrees(m_fov); - } + [[nodiscard]] float GetFov() const { return Math::Utils::degrees(m_fov); } [[nodiscard]] float GetFovX() const { return 2.0f * atanf(tanf(GetFov() * 0.5f) * m_aspect); } - [[nodiscard]] float GetFovRad() const - { - return m_fov; - } + [[nodiscard]] float GetFovRad() const { return m_fov; } [[nodiscard]] float GetFovXRad() const { diff --git a/openVulkanoCpp/Scene/GeometryFactory.cpp b/openVulkanoCpp/Scene/GeometryFactory.cpp index c015c51..137e97f 100644 --- a/openVulkanoCpp/Scene/GeometryFactory.cpp +++ b/openVulkanoCpp/Scene/GeometryFactory.cpp @@ -307,4 +307,48 @@ namespace OpenVulkano::Scene return result; } -} \ No newline at end of file + + Geometry GeometryFactory::MakeArchStrip(float radius, float width, float endRadius, int segments, const Math::Vector4f& color, float endVCoord, bool indexBuffer) + { + Geometry result; + segments = std::max(2, segments); + result.Init(2 * segments, indexBuffer ? 6 * segments : 0); + const float segmentAngle = endRadius / static_cast(segments - 1); + width /= 2; + const float segmentV = endVCoord / (segments - 1); + float segV = 0; + for(int i = 0, seg = 0; seg < segments; seg++) + { + float angle = seg * segmentAngle; + float z = std::cos(angle) * radius; + float y = std::sin(angle) * radius; + + //TODO normals + result.vertices[i].color = color; + result.vertices[i++].Set(width, y, z, +0, +0, +1, +1, +segV); + result.vertices[i].color = color; + result.vertices[i++].Set(-width, y, z, +0, +0, +1, +0, +segV); + segV += segmentV; + } + if (indexBuffer) + { + uint32_t* indices = new uint32_t[result.GetIndexCount()]; + for (uint32_t i = 0, segment = 0; segment < segments; ++segment) + { + uint32_t first = segment * 2; + uint32_t second = first + 1; + + indices[i++] = first; + indices[i++] = second; + indices[i++] = first + 2; + + indices[i++] = first + 2; + indices[i++] = second; + indices[i++] = second + 2; + } + result.SetIndices(indices, result.GetIndexCount()); + } + + return result; + } +} diff --git a/openVulkanoCpp/Scene/GeometryFactory.hpp b/openVulkanoCpp/Scene/GeometryFactory.hpp index cd5e478..45e383d 100644 --- a/openVulkanoCpp/Scene/GeometryFactory.hpp +++ b/openVulkanoCpp/Scene/GeometryFactory.hpp @@ -20,5 +20,6 @@ namespace OpenVulkano::Scene static Geometry MakeTriangle(const Math::Vector3f& p1, const Math::Vector3f& p2, const Math::Vector3f& p3, const Math::Vector4f& color = Math::Vector4f(1)); static Geometry MakeCylinder(float radius, float height, uint32_t segments, const Math::Vector4f& color = Math::Vector4f(1)); static Geometry MakePyramid(float baseLength = 1, float height = 1, const Math::Vector4f& color = Math::Vector4f(1)); + static Geometry MakeArchStrip(float radius = 1, float width = 0.2, float endRadius = std::numbers::pi, int segments = 16, const Math::Vector4f& color = Math::Vector4f(1), float endVCoord = 1, bool indexBuffer = true); }; } diff --git a/openVulkanoCpp/Scene/Prefabs/ArBackgroundDrawable.cpp b/openVulkanoCpp/Scene/Prefabs/ArBackgroundDrawable.cpp index 7772469..32c75e8 100644 --- a/openVulkanoCpp/Scene/Prefabs/ArBackgroundDrawable.cpp +++ b/openVulkanoCpp/Scene/Prefabs/ArBackgroundDrawable.cpp @@ -25,6 +25,7 @@ namespace OpenVulkano::Scene m_shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/background"); m_shader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING); m_shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); + m_shader.depthCompareOp = CompareOp::LESS_OR_EQUAL; SetShader(&m_shader); m_intrinsicsBuffer.Init(sizeof(Math::CameraIntrinsicWithResolution), &FALLBACK_INTRINSICS); m_intrinsicsBuffer.updateFrequency = UpdateFrequency::Always; diff --git a/openVulkanoCpp/Scene/Prefabs/GridDrawable.cpp b/openVulkanoCpp/Scene/Prefabs/GridDrawable.cpp index 4bac9fc..e804b2d 100644 --- a/openVulkanoCpp/Scene/Prefabs/GridDrawable.cpp +++ b/openVulkanoCpp/Scene/Prefabs/GridDrawable.cpp @@ -16,7 +16,9 @@ namespace OpenVulkano::Scene m_shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/grid"); m_shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/grid"); m_shader.alphaBlend = true; + m_shader.depthTest = true; + m_shader.depthWrite = false; SetShader(&m_shader); } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/Scene/SamplerConfig.cpp b/openVulkanoCpp/Scene/SamplerConfig.cpp new file mode 100644 index 0000000..ef11576 --- /dev/null +++ b/openVulkanoCpp/Scene/SamplerConfig.cpp @@ -0,0 +1,19 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "SamplerConfig.hpp" + +namespace OpenVulkano::Scene +{ + const SamplerConfig SamplerConfig::DEFAULT; + const SamplerConfig SamplerConfig::NEAREST(TextureSamplerFilter::NEAREST, TextureSamplerFilter::NEAREST); + const SamplerConfig SamplerConfig::LINEAR(TextureSamplerFilter::LINEAR, TextureSamplerFilter::NEAREST); + const SamplerConfig SamplerConfig::BILINEAR(TextureSamplerFilter::LINEAR, TextureSamplerFilter::LINEAR); + const SamplerConfig SamplerConfig::TIRILINEAR(TextureSamplerFilter::LINEAR, TextureSamplerFilter::LINEAR, TextureSamplerMipmapMode::LINEAR); + const SamplerConfig SamplerConfig::ANISOTROPIC_LOW(TextureSamplerFilter::LINEAR, TextureSamplerFilter::LINEAR, TextureSamplerMipmapMode::LINEAR, true, 4); + const SamplerConfig SamplerConfig::ANISOTROPIC_HIGH(TextureSamplerFilter::LINEAR, TextureSamplerFilter::LINEAR, TextureSamplerMipmapMode::LINEAR, true, 16); + const SamplerConfig SamplerConfig::ANISOTROPIC_PRO(TextureSamplerFilter::LINEAR, TextureSamplerFilter::LINEAR, TextureSamplerMipmapMode::LINEAR, true, 32); +} diff --git a/openVulkanoCpp/Scene/SamplerConfig.hpp b/openVulkanoCpp/Scene/SamplerConfig.hpp new file mode 100644 index 0000000..7953abb --- /dev/null +++ b/openVulkanoCpp/Scene/SamplerConfig.hpp @@ -0,0 +1,104 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include + +namespace OpenVulkano::Scene +{ + enum class TextureSamplerFilter : int + { + NEAREST = 0, + LINEAR = 1, + CUBIC = 1000015000 + }; + + enum class TextureSamplerEdgeMode : int + { + REPEAT = 0, + MIRRORED_REPEAT = 1, + CLAMP_TO_EDGE = 2, + CLAMP_TO_BORDER = 3, + MIRROR_CLAMP_TO_EDGE = 4 + }; + + enum class TextureSamplerMipmapMode : int + { + NEAREST = 0, + LINEAR = 1 + }; + + class SamplerConfig final + { + public: + using bool32_t = uint32_t; + + private: + uint32_t type = 31; // To allow casting to vulkan struct + const void* next = nullptr; // To allow casting to vulkan struct + + public: + uint32_t flags = 0; + TextureSamplerFilter magFilter = TextureSamplerFilter::NEAREST; + TextureSamplerFilter minFilter = TextureSamplerFilter::NEAREST; + TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST; + TextureSamplerEdgeMode edgeModeU = TextureSamplerEdgeMode::REPEAT; + TextureSamplerEdgeMode edgeModeV = TextureSamplerEdgeMode::REPEAT; + TextureSamplerEdgeMode edgeModeW = TextureSamplerEdgeMode::REPEAT; + float mipLoadBias = 0; + bool32_t anisotropyEnabled = false; + float maxAnisotropy = 0; + bool32_t compareEnabled = false; + uint32_t compareOp = 0; //TODO + float minLod = 0, maxLod = 0; + uint32_t borderColor = 0; + bool32_t unnormalizedCoordinates = false; + + SamplerConfig(TextureSamplerEdgeMode edgeMode, TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST, + TextureSamplerFilter magFilter = TextureSamplerFilter::NEAREST, TextureSamplerFilter minFilter = TextureSamplerFilter::NEAREST) + : magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode), edgeModeU(edgeMode), edgeModeV(edgeMode), edgeModeW(edgeMode) + {} + + SamplerConfig(uint32_t flags = 0, TextureSamplerFilter magFilter = TextureSamplerFilter::LINEAR, + TextureSamplerFilter minFilter = TextureSamplerFilter::LINEAR, + TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST, + TextureSamplerEdgeMode edgeModeU = TextureSamplerEdgeMode::REPEAT, + TextureSamplerEdgeMode edgeModeV = TextureSamplerEdgeMode::REPEAT, + TextureSamplerEdgeMode edgeModeW = TextureSamplerEdgeMode::REPEAT, + float mipLoadBias = 0, bool32_t anisotropyEnabled = false, float maxAnisotropy = 0, + bool32_t compareEnabled = false, uint32_t compareOp = 0, //TODO + float minLod = 0, float maxLod = 0, uint32_t borderColor = 0, bool32_t unnormalizedCoordinates = false) + : flags(flags), magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode) + , edgeModeU(edgeModeU), edgeModeV(edgeModeV), edgeModeW(edgeModeW) + , mipLoadBias(mipLoadBias), anisotropyEnabled(anisotropyEnabled), maxAnisotropy(maxAnisotropy) + , compareEnabled(compareEnabled), compareOp(compareOp) + , minLod(minLod), maxLod(maxLod), borderColor(borderColor), unnormalizedCoordinates(unnormalizedCoordinates) + {} + + SamplerConfig(TextureSamplerFilter magFilter, TextureSamplerFilter minFilter = TextureSamplerFilter::LINEAR, + TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST, + bool32_t anisotropyEnabled = false, float maxAnisotropy = 0) + : magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode), anisotropyEnabled(anisotropyEnabled), maxAnisotropy(maxAnisotropy) + {} + + auto operator <=>(const SamplerConfig& other) const = default; + + public: + // Default configs + static const SamplerConfig DEFAULT; + static const SamplerConfig NEAREST; + static const SamplerConfig LINEAR; + static const SamplerConfig BILINEAR; + static const SamplerConfig TIRILINEAR; + static const SamplerConfig ANISOTROPIC_LOW; + static const SamplerConfig ANISOTROPIC_HIGH; + + // Not supported on most consumer grphics cards! + static const SamplerConfig ANISOTROPIC_PRO; + }; +} diff --git a/openVulkanoCpp/Scene/Shader/Shader.hpp b/openVulkanoCpp/Scene/Shader/Shader.hpp index 484165d..ed1da7d 100644 --- a/openVulkanoCpp/Scene/Shader/Shader.hpp +++ b/openVulkanoCpp/Scene/Shader/Shader.hpp @@ -40,6 +40,18 @@ namespace OpenVulkano::Scene PATCH_LIST }; + enum class CompareOp : uint32_t + { + NEVER = 0, + LESS = 1, + EQUAL = 2, + LESS_OR_EQUAL = 3, + GREATER = 4, + NOT_EQUAL = 5, + GREATER_OR_EQUAL = 6, + ALWAYS = 7 + }; + struct ShaderProgram { ShaderProgramType type; @@ -77,12 +89,14 @@ namespace OpenVulkano::Scene Topology topology = Topology::TRIANGLE_LIST; CullMode cullMode = CullMode::BACK; ICloseable* renderShader = nullptr; + CompareOp depthCompareOp = CompareOp::LESS; bool alphaBlend = false; // TODO allow fine control over blending bool depthTest = true; bool depthWrite = true; + bool dynamicViewport = true; // If disabled the swapchains fullscreen viewport will always be used, regardless of framebuffer or viewport Shader() = default; - ~Shader() override { /*if (renderShader) Shader::Close();*/ } + ~Shader() override { if (renderShader) Shader::Close(); } Shader& AddShaderProgram(const ShaderProgram& shaderProgram) { diff --git a/openVulkanoCpp/Scene/Textrue.cpp b/openVulkanoCpp/Scene/Textrue.cpp index 4c1052c..389e328 100644 --- a/openVulkanoCpp/Scene/Textrue.cpp +++ b/openVulkanoCpp/Scene/Textrue.cpp @@ -8,7 +8,7 @@ namespace OpenVulkano::Scene { - Texture Texture::PLACEHOLDER = Texture(true); + Texture Texture::PLACEHOLDER = Texture(&SamplerConfig::NEAREST, true); void Texture::MakePlaceholder(uint32_t width, uint32_t height, Math::Vector4uc color1, Math::Vector4uc color2) { @@ -25,5 +25,6 @@ namespace OpenVulkano::Scene resolution = {width, height, 1}; size = sizeof(Math::Vector4uc) * width * height; format = DataFormat::B8G8R8A8_UNORM; + m_samplerConfig = &SamplerConfig::NEAREST; } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/Scene/Texture.hpp b/openVulkanoCpp/Scene/Texture.hpp index ab3d30c..e65a1ce 100644 --- a/openVulkanoCpp/Scene/Texture.hpp +++ b/openVulkanoCpp/Scene/Texture.hpp @@ -7,6 +7,7 @@ #pragma once #include "UpdateFrequency.hpp" +#include "SamplerConfig.hpp" #include "Base/ICloseable.hpp" #include "Math/Math.hpp" #include "DataFormat.hpp" @@ -32,10 +33,13 @@ namespace OpenVulkano::Scene size_t size = 0; Math::Vector3ui resolution = {0,0,0}; DataFormat format = DataFormat::B8G8R8A8_UNORM; - bool updated = true; UpdateFrequency updateFrequency = UpdateFrequency::Never; + const SamplerConfig* m_samplerConfig; + bool updated = true; - Texture(bool placeholder = false) { if (placeholder) MakePlaceholder(); } + Texture(const SamplerConfig* samplerConfig = &SamplerConfig::DEFAULT, bool placeholder = false) + : m_samplerConfig(samplerConfig) + { if (placeholder) MakePlaceholder(); } ~Texture() { diff --git a/openVulkanoCpp/Shader/background.vert b/openVulkanoCpp/Shader/background.vert index f6a52ae..5ccb9c3 100644 --- a/openVulkanoCpp/Shader/background.vert +++ b/openVulkanoCpp/Shader/background.vert @@ -27,10 +27,9 @@ layout(set = 2, binding = 0) uniform RealCameraData layout(location = 0) out vec2 textureCoordinates; layout(location = 1) out float scaleOut; -const float FLOAT_MAX_LESS_THAN_1 = 0.999999940395355224609; // Background plane positions are in clipped space const vec4 PLANE[4] = vec4[]( - vec4(1, -1, FLOAT_MAX_LESS_THAN_1, 1), vec4(-1, -1, FLOAT_MAX_LESS_THAN_1, 1), vec4(1, 1, FLOAT_MAX_LESS_THAN_1, 1), vec4(-1, 1, FLOAT_MAX_LESS_THAN_1, 1) + vec4(1, -1, 1, 1), vec4(-1, -1, 1, 1), vec4(1, 1, 1, 1), vec4(-1, 1, 1, 1) ); const vec2 TEX_COORDS[4] = vec2[]( vec2(1, 0), vec2(0, 0), vec2(1, 1), vec2(0, 1) diff --git a/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp b/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp new file mode 100644 index 0000000..98e200e --- /dev/null +++ b/openVulkanoCpp/Vulkan/DepthBufferQuery.cpp @@ -0,0 +1,96 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#include "DepthBufferQuery.hpp" +#include "Renderer.hpp" +#include + +//TODO resize + +namespace OpenVulkano::Vulkan +{ + void DepthBufferQuery::Init() + { + auto device = renderer.GetContext().device->device; + + vk::BufferCreateInfo bufferInfo = { {}, 25 * sizeof(float), vk::BufferUsageFlagBits::eTransferDst }; + bufferDepth = device.createBuffer(bufferInfo); + const vk::MemoryRequirements memRequirements = device.getBufferMemoryRequirements(bufferDepth); + size_t size = memRequirements.size; + const vk::MemoryAllocateInfo memAllocInfo = { size, renderer.GetContext().device->GetMemoryType(memRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible) }; + + memory = device.allocateMemory(memAllocInfo); + cpuDepthBuffer = static_cast(device.mapMemory(memory, 0, VK_WHOLE_SIZE, {})); + + device.bindBufferMemory(bufferDepth, memory, 0); + } + + void DepthBufferQuery::Close() + { + auto device = renderer.GetContext().device->device; + device.destroy(bufferDepth); + device.unmapMemory(memory); + device.free(memory); + cpuDepthBuffer = nullptr; + } + + void DepthBufferQuery::Resize(uint32_t width, uint32_t height) + { + //TODO + } + + float DepthBufferQuery::GetQueriedValue() const + { + if (cpuDepthBuffer[0] == -2) return -2; + if (cpuDepthBuffer[12] > 0 && cpuDepthBuffer[12] < 1) return cpuDepthBuffer[12]; + double val = 0; + int validCount = 0; + for (int i = 0; i < 25; i++) + { + float f = cpuDepthBuffer[i]; + if (f > 0 && f < 1) + { + val += f; + validCount++; + } + } + if (validCount == 0) return 1; // Prevent divide by 0 + return val / validCount; + } + + vk::Offset3D DepthBufferQuery::GetCopyOffset() const + { + vk::Extent3D depthExtent = renderer.GetContext().swapChain.GetCurrentDepthBuffer().extent; + + int32_t x = static_cast(depthQueryCoordinates.x * depthExtent.width); + x = std::min(depthExtent.width - 5, std::max(0, x)); + + int32_t y = static_cast(depthQueryCoordinates.y * depthExtent.height); + y = std::min(depthExtent.height - 5, std::max(0, y)); + + return { x, y, 0 }; + } + + void DepthBufferQuery::Encode(vk::CommandBuffer& commandBuffer) + { + if (!copyDepthBuffer) return; + copyDepthBuffer = false; + std::fill(cpuDepthBuffer, cpuDepthBuffer + 25, -2.0f); // Invalidate data in buffer to allow detecting if copy is done + const vk::ImageAspectFlags aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil; + const Image& depthBufferImage = renderer.GetContext().swapChain.GetCurrentDepthBuffer(); + + constexpr vk::Extent3D copySize = { 5, 5, 1 }; + const vk::ImageSubresourceLayers layout = { vk::ImageAspectFlagBits::eDepth, 0, 0, 1 }; + vk::BufferImageCopy imgCopy = { 0, 5, 5, layout, GetCopyOffset(), copySize }; + + const vk::ImageMemoryBarrier imgMemBarrier({}, vk::AccessFlagBits::eTransferRead, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal, 0, 0, depthBufferImage.image, vk::ImageSubresourceRange(aspectMask, 0, 1, 0, 1)); + commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, imgMemBarrier); + + commandBuffer.copyImageToBuffer(depthBufferImage.image, vk::ImageLayout::eTransferSrcOptimal, bufferDepth, 1, &imgCopy); + + depthBufferImage.SetLayout(commandBuffer, aspectMask, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eTransferSrcOptimal); + } +} diff --git a/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp b/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp new file mode 100644 index 0000000..167912d --- /dev/null +++ b/openVulkanoCpp/Vulkan/DepthBufferQuery.hpp @@ -0,0 +1,48 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include "Math/Math.hpp" +#include "Vulkan/Image.hpp" + +namespace OpenVulkano::Vulkan +{ + class Renderer; + + class DepthBufferQuery final + { + Renderer& renderer; + vk::DeviceMemory memory; + vk::Buffer bufferDepth; + float* cpuDepthBuffer = nullptr; + Math::Vector2f depthQueryCoordinates = { 0.5f, 0.5f }; + bool copyDepthBuffer = true; + + vk::Offset3D GetCopyOffset() const; + + public: + DepthBufferQuery(Renderer& renderer): renderer(renderer) {} + + ~DepthBufferQuery() { if (cpuDepthBuffer != nullptr) Close(); } + + void Init(); + + void Close(); + + void Encode(vk::CommandBuffer& commandBuffer); + + void Resize(uint32_t width, uint32_t height); + + float GetQueriedValue() const; + + void SetQueryCoordinates(const Math::Vector2f& coords) + { + copyDepthBuffer = true; + depthQueryCoordinates = coords; + } + }; +} diff --git a/openVulkanoCpp/Vulkan/FrameBuffer.cpp b/openVulkanoCpp/Vulkan/FrameBuffer.cpp index 3790955..e422736 100644 --- a/openVulkanoCpp/Vulkan/FrameBuffer.cpp +++ b/openVulkanoCpp/Vulkan/FrameBuffer.cpp @@ -18,6 +18,8 @@ void OpenVulkano::Vulkan::FrameBuffer::Init(Device* device, vk::Extent3D size, b depthBufferFormat = FindDepthFormat(); CreateDepthStencil(); } + fullscreenViewport = vk::Viewport{ 0, 0, (float)size.width, (float)size.height, 0, 1 }; + fullscreenScissor = vk::Rect2D{ { 0, 0 }, { size.width, size.height } }; } void OpenVulkano::Vulkan::FrameBuffer::RegisterRenderPass(RenderPass* renderPass) @@ -44,6 +46,8 @@ void OpenVulkano::Vulkan::FrameBuffer::Resize(vk::Extent3D size) { renderPass->Resize(size); } + fullscreenViewport = vk::Viewport{ 0, 0, (float)size.width, (float)size.height, 0, 1 }; + fullscreenScissor = vk::Rect2D{ { 0, 0 }, { size.width, size.height } }; } void OpenVulkano::Vulkan::FrameBuffer::CreateDepthStencil() diff --git a/openVulkanoCpp/Vulkan/FrameBuffer.hpp b/openVulkanoCpp/Vulkan/FrameBuffer.hpp index 9b78bf6..e9d68ca 100644 --- a/openVulkanoCpp/Vulkan/FrameBuffer.hpp +++ b/openVulkanoCpp/Vulkan/FrameBuffer.hpp @@ -24,8 +24,10 @@ namespace OpenVulkano::Vulkan vk::Format depthBufferFormat = vk::Format::eUndefined, colorFormat = vk::Format::eUndefined; vk::Extent3D size; std::vector renderPasses; - bool useDepthBuffer; + vk::Viewport fullscreenViewport; + vk::Rect2D fullscreenScissor; Device* device = nullptr; + bool useDepthBuffer; protected: uint32_t currentFrameBufferId = 0; @@ -38,15 +40,9 @@ namespace OpenVulkano::Vulkan void Init(Device* device, vk::Extent3D size, bool useDepthBuffer = true); - void SetCurrentFrameId(uint32_t id) - { - currentFrameBufferId = id; - } + void SetCurrentFrameId(uint32_t id) { currentFrameBufferId = id; } - uint32_t GetCurrentFrameId() const - { - return currentFrameBufferId; - } + [[nodiscard]] uint32_t GetCurrentFrameId() const { return currentFrameBufferId; } public: void RegisterRenderPass(RenderPass* renderPass); @@ -69,44 +65,32 @@ namespace OpenVulkano::Vulkan void DestroyFrameBuffer(); - virtual vk::Format FindColorFormat() = 0; + [[nodiscard]] virtual vk::Format FindColorFormat() = 0; - virtual vk::Format FindDepthFormat() + [[nodiscard]] virtual vk::Format FindDepthFormat() { return device->GetSupportedDepthFormat(); } public: - virtual vk::Format GetColorFormat() - { - return colorFormat; - } + [[nodiscard]] vk::Format GetColorFormat() const { return colorFormat; } - virtual vk::Format GetDepthFormat() - { - return depthBufferFormat; - } + [[nodiscard]] vk::Format GetDepthFormat() const { return depthBufferFormat; } - virtual std::vector GetImages() = 0; + [[nodiscard]] virtual std::vector GetImages() = 0; - bool UseDepthBuffer() const - { - return useDepthBuffer; - } + [[nodiscard]] bool UseDepthBuffer() const { return useDepthBuffer; } - vk::Extent3D GetSize3D() const - { - return size; - } + [[nodiscard]] const vk::Extent3D& GetSize3D() const { return size; } - vk::Extent2D GetSize2D() const - { - return { size.width, size.height }; - } + [[nodiscard]] vk::Extent2D GetSize2D() const { return { size.width, size.height }; } - vk::Framebuffer& GetCurrentFrameBuffer() - { - return frameBuffers[currentFrameBufferId]; - } + [[nodiscard]] vk::Framebuffer& GetCurrentFrameBuffer() { return frameBuffers[currentFrameBufferId]; } + + [[nodiscard]] const vk::Viewport& GetFullscreenViewport() const { return fullscreenViewport; } + + [[nodiscard]] const vk::Rect2D& GetFullscreenScissor() const { return fullscreenScissor; } + + [[nodiscard]] const Image& GetCurrentDepthBuffer() { return depthBuffer; } }; } diff --git a/openVulkanoCpp/Vulkan/Metal/MetalBackedTexture.mm b/openVulkanoCpp/Vulkan/Metal/MetalBackedTexture.mm index 75995a4..f3ffc79 100644 --- a/openVulkanoCpp/Vulkan/Metal/MetalBackedTexture.mm +++ b/openVulkanoCpp/Vulkan/Metal/MetalBackedTexture.mm @@ -54,7 +54,7 @@ namespace OpenVulkano::Vulkan } m_vulkanTexture.view = m_vulkanTexture.device.createImageView(imgViewCreateInfo); - m_vulkanTexture.m_sampler = resManager->CreateSampler(VulkanTexture::DEFAULT_SAMPLER_CONFIG); + m_vulkanTexture.m_sampler = resManager->CreateSampler(reinterpret_cast(Scene::SamplerConfig::DEFAULT)); m_vulkanTexture.SetDescriptorSet(resManager, resManager->GetDescriptorLayoutSet(binding), binding); renderTexture = &m_vulkanTexture; diff --git a/openVulkanoCpp/Vulkan/RenderPass.cpp b/openVulkanoCpp/Vulkan/RenderPass.cpp index b7afa50..979ed5f 100644 --- a/openVulkanoCpp/Vulkan/RenderPass.cpp +++ b/openVulkanoCpp/Vulkan/RenderPass.cpp @@ -57,7 +57,7 @@ namespace OpenVulkano::Vulkan if (m_frameBuffer->UseDepthBuffer()) { // Depth attachment attachments.emplace_back(vk::AttachmentDescriptionFlags(), m_frameBuffer->GetDepthFormat(), vk::SampleCountFlagBits::e1, - m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eDontCare, m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, + m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eStore, m_useClearDepth ? vk::AttachmentLoadOp::eClear : vk::AttachmentLoadOp::eLoad, vk::AttachmentStoreOp::eDontCare, vk::ImageLayout::eDepthStencilAttachmentOptimal, vk::ImageLayout::eDepthStencilAttachmentOptimal); depthReference = new vk::AttachmentReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal); } @@ -87,4 +87,4 @@ namespace OpenVulkano::Vulkan { renderPass = m_device.createRenderPass(renderPassCreateInfo); } -} \ No newline at end of file +} diff --git a/openVulkanoCpp/Vulkan/Renderer.cpp b/openVulkanoCpp/Vulkan/Renderer.cpp index 1bae3df..a6f4a7b 100644 --- a/openVulkanoCpp/Vulkan/Renderer.cpp +++ b/openVulkanoCpp/Vulkan/Renderer.cpp @@ -18,6 +18,11 @@ namespace OpenVulkano::Vulkan { + Renderer::Renderer() + : depthBufferQuery(*this) + { + } + void Renderer::Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) { logger = Logger::RENDER; @@ -62,6 +67,8 @@ namespace OpenVulkano::Vulkan } } + depthBufferQuery.Init(); + logger->info("Vulkan renderer initialized"); } @@ -69,6 +76,8 @@ namespace OpenVulkano::Vulkan { currentImageId = context.swapChain.AcquireNextImage(); scene->GetCamera()->SetSize(context.window->GetWidth(), context.window->GetHeight()); + scene->GetCamera()->SetContentScaleFactor(context.window->GetContentScale()); + scene->GetCamera()->SetInterfaceOrientation(context.window->GetInterfaceOrientation()); Render(); } @@ -85,6 +94,7 @@ namespace OpenVulkano::Vulkan closeables.pop_back(); closeable->Close(); } + depthBufferQuery.Close(); uiRenderer.Close(); resourceManager.Close(); commands.clear(); @@ -104,7 +114,7 @@ namespace OpenVulkano::Vulkan resourceManager.Resize(); } - CommandHelper* Renderer::GetCommandData(uint32_t poolId) + CommandHelper* Renderer::GetCommandData(size_t poolId) { return &commands[poolId][currentImageId]; } @@ -136,6 +146,7 @@ namespace OpenVulkano::Vulkan CommandHelper* cmdHelper = GetCommandData(commands.size() - 1); cmdHelper->cmdBuffer.executeCommands(submitBuffers[currentImageId].size(), submitBuffers[currentImageId].data()); context.swapChainRenderPass.End(cmdHelper->cmdBuffer); + depthBufferQuery.Encode(cmdHelper->cmdBuffer); uiRenderer.DrawUiFrame(cmdHelper->cmdBuffer); cmdHelper->cmdBuffer.end(); std::array stateFlags = { vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput), vk::PipelineStageFlags(vk::PipelineStageFlagBits::eColorAttachmentOutput) }; @@ -162,12 +173,14 @@ namespace OpenVulkano::Vulkan Submit(); } - void Renderer::RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId) + void Renderer::RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, size_t poolId) { CommandHelper* cmdHelper = GetCommandData(poolId); cmdHelper->Reset(); vk::CommandBufferInheritanceInfo inheritance = { context.swapChainRenderPass.renderPass, 0, context.swapChainRenderPass.GetFrameBuffer()->GetCurrentFrameBuffer() }; cmdHelper->cmdBuffer.begin(vk::CommandBufferBeginInfo{ vk::CommandBufferUsageFlagBits::eOneTimeSubmit | vk::CommandBufferUsageFlagBits::eRenderPassContinue, &inheritance }); + cmdHelper->cmdBuffer.setViewport(0, 1, &context.swapChainRenderPass.GetFrameBuffer()->GetFullscreenViewport()); + cmdHelper->cmdBuffer.setScissor(0, 1, &context.swapChainRenderPass.GetFrameBuffer()->GetFullscreenScissor()); Scene::Drawable** drawablePointer; VulkanDrawContext drawContext { poolId, currentImageId, cmdHelper->cmdBuffer, this }; diff --git a/openVulkanoCpp/Vulkan/Renderer.hpp b/openVulkanoCpp/Vulkan/Renderer.hpp index 5740256..718356d 100644 --- a/openVulkanoCpp/Vulkan/Renderer.hpp +++ b/openVulkanoCpp/Vulkan/Renderer.hpp @@ -16,6 +16,7 @@ #include "CommandHelper.hpp" #include "Base/EngineConfiguration.hpp" #include "Resources/ResourceManager.hpp" +#include "DepthBufferQuery.hpp" #include #include @@ -40,9 +41,10 @@ namespace OpenVulkano::Vulkan std::vector> submitBuffers; UiRenderer uiRenderer; std::vector closeables; + DepthBufferQuery depthBufferQuery; public: - Renderer() = default; + Renderer(); ~Renderer() override = default; void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) override; @@ -63,7 +65,7 @@ namespace OpenVulkano::Vulkan Scene::UI::Ui* GetActiveUi() override { return uiRenderer.GetActiveUi(); } - CommandHelper* GetCommandData(uint32_t poolId); + CommandHelper* GetCommandData(size_t poolId); static void RunThread(Renderer* renderer, Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t id); @@ -75,7 +77,7 @@ namespace OpenVulkano::Vulkan void Render(); - void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, uint32_t poolId); + void RecordSecondaryBuffer(Data::ReadOnlyAtomicArrayQueue* jobQueue, size_t poolId); ResourceManager& GetResourceManager() { return resourceManager; } @@ -86,5 +88,9 @@ namespace OpenVulkano::Vulkan void UnregisterCloseable(ICloseable* closeable) { Utils::Remove(closeables, closeable); } IResourceManager* GetIResourceManager() override { return &resourceManager; } + + + float GetLastQueriedDepthValue() override { return depthBufferQuery.GetQueriedValue(); } + void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) override { depthBufferQuery.SetQueryCoordinates(depthCoordinates); } }; } diff --git a/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp b/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp index 998a7fc..7689741 100644 --- a/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp +++ b/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp @@ -55,7 +55,7 @@ namespace OpenVulkano::Vulkan * \return The pointer to the mapped buffer. */ template - T* Map(size_t offset = 0, vk::DeviceSize size = VK_WHOLE_SIZE, bool longTermMapping = true) + T* Map(vk::DeviceSize offset = 0, vk::DeviceSize size = VK_WHOLE_SIZE, bool longTermMapping = true) { if (!mapped) { @@ -106,7 +106,7 @@ namespace OpenVulkano::Vulkan } } - void Copy(const void* data, uint32_t size, uint32_t offset) + void Copy(const void* data, vk::DeviceSize size, vk::DeviceSize offset) { if(mapped) memcpy(static_cast(mapped) + offset, data, size); else diff --git a/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp b/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp index 721d7e3..69e29f5 100644 --- a/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp +++ b/openVulkanoCpp/Vulkan/Resources/ResourceManager.cpp @@ -53,6 +53,7 @@ namespace OpenVulkano::Vulkan ResourceManager::ResourceManager() { static_assert(sizeof(DescriptorSetLayoutBinding) == sizeof(vk::DescriptorSetLayoutBinding)); + static_assert(sizeof(Scene::SamplerConfig) == sizeof(vk::SamplerCreateInfo)); } ResourceManager::~ResourceManager() noexcept diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp index 91fa821..fc851aa 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanShader.cpp @@ -17,8 +17,15 @@ namespace OpenVulkano::Vulkan VulkanShader::~VulkanShader() { - if (!shader) return; - Close(); + if (shader) Close(); + device.destroyPipeline(pipeline); + for(auto& shaderModule : shaderModules) + { + device.destroyShaderModule(shaderModule); + } + device.destroyPipelineLayout(pipelineLayout); + for(auto& descriptorSetLayout : descriptorSetLayouts) + device.destroyDescriptorSetLayout(descriptorSetLayout); } void VulkanShader::Init(Context* context, Scene::Shader* shader, IShaderOwner* owner) @@ -63,12 +70,12 @@ namespace OpenVulkano::Vulkan if (shader->vertexInputDescriptions.size() == 1) { // Reuse already existing vertex attribute description static_assert(sizeof(VertexInputParameter) == sizeof(vk::VertexInputAttributeDescription)); - attributeDescriptionsSize = shader->vertexInputDescriptions[0].inputParameters.size(); + attributeDescriptionsSize = static_cast(shader->vertexInputDescriptions[0].inputParameters.size()); attributeDescriptionsData = reinterpret_cast(shader->vertexInputDescriptions[0].inputParameters.data()); } else { - attributeDescriptionsSize = attributeDescriptions.size(); + attributeDescriptionsSize = static_cast(attributeDescriptions.size()); attributeDescriptionsData = attributeDescriptions.data(); } @@ -80,7 +87,7 @@ namespace OpenVulkano::Vulkan vk::PipelineRasterizationStateCreateInfo rasterizer = {}; rasterizer.cullMode = static_cast(shader->cullMode); vk::PipelineMultisampleStateCreateInfo msaa = {}; - vk::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, vk::CompareOp::eLess }; + vk::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, static_cast(shader->depthCompareOp) }; depth.maxDepthBounds = 1; vk::PipelineColorBlendAttachmentState colorBlendAttachment = {}; colorBlendAttachment.colorWriteMask = vk::ColorComponentFlagBits::eA | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eR; @@ -100,8 +107,14 @@ namespace OpenVulkano::Vulkan CreatePipelineLayout(); - vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfo.size()), shaderStageCreateInfo.data(), &pipelineVertexInputStateCreateInfo, &inputAssembly, - nullptr, &viewportStateCreateInfo, &rasterizer, &msaa, &depth, &colorInfo, nullptr, pipelineLayout, context->swapChainRenderPass.renderPass }; + const auto dynSates = Utils::MakeStdArray( vk::DynamicState::eViewport, vk::DynamicState::eScissor ); + vk::PipelineDynamicStateCreateInfo dynStateInfo { {}, dynSates.size(), dynSates.data() }; + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { {}, static_cast(shaderStageCreateInfo.size()), + shaderStageCreateInfo.data(), &pipelineVertexInputStateCreateInfo, + &inputAssembly, nullptr, &viewportStateCreateInfo, &rasterizer, + &msaa, &depth, &colorInfo, shader->dynamicViewport ? &dynStateInfo : nullptr, pipelineLayout, + context->swapChainRenderPass.renderPass }; pipeline = this->device.createGraphicsPipeline({}, pipelineCreateInfo).value; } @@ -119,16 +132,9 @@ namespace OpenVulkano::Vulkan void VulkanShader::Close() { shader->renderShader = nullptr; - device.destroyPipeline(pipeline); - for(auto& shaderModule : shaderModules) - { - device.destroyShaderModule(shaderModule); - } - device.destroyPipelineLayout(pipelineLayout); - for(auto& descriptorSetLayout : descriptorSetLayouts) - device.destroyDescriptorSetLayout(descriptorSetLayout); shader = nullptr; if (owner) owner->RemoveShader(this); + owner = nullptr; } void VulkanShader::CreatePipelineLayout() diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanTexture.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanTexture.hpp index a7c50c4..d38ba22 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanTexture.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanTexture.hpp @@ -19,7 +19,6 @@ namespace OpenVulkano::Vulkan class VulkanTexture : public Scene::RenderTexture, public IRecordable, public Image { public: - static inline vk::SamplerCreateInfo DEFAULT_SAMPLER_CONFIG {}; vk::Sampler m_sampler; vk::DescriptorSet m_descriptorSet; @@ -30,7 +29,7 @@ namespace OpenVulkano::Vulkan resManager->CopyDataToImage(m_texture->size, m_texture->textureBuffer, this); texture->updated = false; - m_sampler = resManager->CreateSampler(DEFAULT_SAMPLER_CONFIG); + m_sampler = resManager->CreateSampler(reinterpret_cast(texture->m_samplerConfig)); SetDescriptorSet(resManager, descriptorSetLayout, binding); texture->renderTexture = this; @@ -43,7 +42,7 @@ namespace OpenVulkano::Vulkan texture->updated = false; texture->textureBuffer = Map(); - m_sampler = resManager->CreateSampler(DEFAULT_SAMPLER_CONFIG); + m_sampler = resManager->CreateSampler(reinterpret_cast(texture->m_samplerConfig)); SetDescriptorSet(resManager, descriptorSetLayout, binding); texture->renderTexture = this; diff --git a/openVulkanoCpp/Vulkan/Scene/VulkanUniformBuffer.hpp b/openVulkanoCpp/Vulkan/Scene/VulkanUniformBuffer.hpp index f7dd260..2d50c9a 100644 --- a/openVulkanoCpp/Vulkan/Scene/VulkanUniformBuffer.hpp +++ b/openVulkanoCpp/Vulkan/Scene/VulkanUniformBuffer.hpp @@ -59,7 +59,7 @@ namespace OpenVulkano::Vulkan { if(uBuffer->updated) //TODO fix { - //uBuffer->updated = false; + uBuffer->updated = false; buffer->Update(uBuffer->data, uBuffer->size, context->currentImageId); } buffer->Record(context); diff --git a/openVulkanoCpp/Vulkan/SwapChain.cpp b/openVulkanoCpp/Vulkan/SwapChain.cpp index 8d102b4..f3a4df6 100644 --- a/openVulkanoCpp/Vulkan/SwapChain.cpp +++ b/openVulkanoCpp/Vulkan/SwapChain.cpp @@ -118,8 +118,6 @@ namespace OpenVulkano::Vulkan for (size_t i = 0; i < images.size() + 1; i++) imageAvailableSemaphores.emplace_back(device->device.createSemaphore({})); - fullscreenViewport = vk::Viewport{ 0, 0, (float)size.width, (float)size.height, 0, 1 }; - fullscreenScissor = vk::Rect2D{ {0,0}, size }; Logger::RENDER->debug("Swap chain for window {0} created", window->GetWindowId()); } diff --git a/openVulkanoCpp/Vulkan/SwapChain.hpp b/openVulkanoCpp/Vulkan/SwapChain.hpp index 738205b..934b705 100644 --- a/openVulkanoCpp/Vulkan/SwapChain.hpp +++ b/openVulkanoCpp/Vulkan/SwapChain.hpp @@ -43,11 +43,9 @@ namespace OpenVulkano IVulkanWindow* window = nullptr; vk::SurfaceFormatKHR surfaceFormat; vk::PresentModeKHR presentMode; - vk::Viewport fullscreenViewport; - vk::Rect2D fullscreenScissor; std::vector imageAvailableSemaphores; uint32_t currentSemaphoreId = 0; - vk::Extent2D size{0,0}; + vk::Extent2D size{ 0, 0 }; public: vk::SwapchainKHR swapChain; @@ -61,20 +59,7 @@ namespace OpenVulkano void Resize(uint32_t newWidth, uint32_t newHeight); - [[nodiscard]] vk::Extent2D GetSize() const - { - return size; - } - - [[nodiscard]] const vk::Viewport& GetFullscreenViewport() const - { - return fullscreenViewport; - } - - [[nodiscard]] const vk::Rect2D& GetFullscreenScissor() const - { - return fullscreenScissor; - } + [[nodiscard]] vk::Extent2D GetSize() const { return size; } uint32_t AcquireNextImage(const vk::Fence& fence = vk::Fence()); @@ -93,10 +78,7 @@ namespace OpenVulkano } } - [[nodiscard]] uint32_t GetImageCount() const - { - return images.size(); - } + [[nodiscard]] uint32_t GetImageCount() const { return images.size(); } vk::Semaphore& GetCurrentSemaphore() { return imageAvailableSemaphores[currentSemaphoreId]; } @@ -108,10 +90,7 @@ namespace OpenVulkano void DestroySwapChain(); protected: - vk::Format FindColorFormat() override - { - return surfaceFormat.format; - } + [[nodiscard]] vk::Format FindColorFormat() override { return surfaceFormat.format; } virtual vk::PresentModeKHR ChosePresentMode(); diff --git a/tests/placeholder.cpp b/tests/placeholder.cpp new file mode 100644 index 0000000..e69de29