diff --git a/.gitignore b/.gitignore index 79926da2..dc29054b 100644 --- a/.gitignore +++ b/.gitignore @@ -31,7 +31,9 @@ *.out *.app /.vs* +/.idea /out +/cmake-build* /build /enc_temp_folder /cpm-cache diff --git a/CMakeLists.txt b/CMakeLists.txt index 2111ebb7..a3b68704 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,8 @@ endif() option(FASTNOISE2_TOOLS "Build \"Node Editor\" executable" ${FASTNOISE2_STANDALONE_PROJECT}) option(FASTNOISE2_TESTS "Build tests" OFF) +option(FASTNOISE2_STRICT_FP "Enable strict floating point calculations to ensure output from different SIMD feature sets match EXACTLY" OFF) + if(MSVC) #setup pdb target location set(pdb_output_dir "${CMAKE_CURRENT_BINARY_DIR}/pdb-files") diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index 9ae66399..1b4cfcca 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -5,7 +5,7 @@ # MIT License # ----------- #[[ - Copyright (c) 2021 Lars Melchior and additional contributors + Copyright (c) 2019-2023 Lars Melchior and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -28,10 +28,25 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -set(CURRENT_CPM_VERSION 0.32.2) +# Initialize logging prefix +if(NOT CPM_INDENT) + set(CPM_INDENT + "CPM:" + CACHE INTERNAL "" + ) +endif() + +if(NOT COMMAND cpm_message) + function(cpm_message) + message(${ARGV}) + endfunction() +endif() +set(CURRENT_CPM_VERSION 0.39.0) + +get_filename_component(CPM_CURRENT_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" REALPATH) if(CPM_DIRECTORY) - if(NOT CPM_DIRECTORY STREQUAL CMAKE_CURRENT_LIST_DIR) + if(NOT CPM_DIRECTORY STREQUAL CPM_CURRENT_DIRECTORY) if(CPM_VERSION VERSION_LESS CURRENT_CPM_VERSION) message( AUTHOR_WARNING @@ -57,8 +72,42 @@ See https://github.com/cpm-cmake/CPM.cmake for more information." endif() endif() +if(CURRENT_CPM_VERSION MATCHES "development-version") + message( + WARNING "${CPM_INDENT} Your project is using an unstable development version of CPM.cmake. \ +Please update to a recent release if possible. \ +See https://github.com/cpm-cmake/CPM.cmake for details." + ) +endif() + set_property(GLOBAL PROPERTY CPM_INITIALIZED true) +macro(cpm_set_policies) + # the policy allows us to change options without caching + cmake_policy(SET CMP0077 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) + + # the policy allows us to change set(CACHE) without caching + if(POLICY CMP0126) + cmake_policy(SET CMP0126 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0126 NEW) + endif() + + # The policy uses the download time for timestamp, instead of the timestamp in the archive. This + # allows for proper rebuilds when a projects url changes + if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0135 NEW) + endif() + + # treat relative git repository paths as being relative to the parent project's remote + if(POLICY CMP0150) + cmake_policy(SET CMP0150 NEW) + set(CMAKE_POLICY_DEFAULT_CMP0150 NEW) + endif() +endmacro() +cpm_set_policies() + option(CPM_USE_LOCAL_PACKAGES "Always try to use `find_package` to get dependencies" $ENV{CPM_USE_LOCAL_PACKAGES} ) @@ -76,13 +125,17 @@ option(CPM_INCLUDE_ALL_IN_PACKAGE_LOCK "Add all packages added through CPM.cmake to the package lock" $ENV{CPM_INCLUDE_ALL_IN_PACKAGE_LOCK} ) +option(CPM_USE_NAMED_CACHE_DIRECTORIES + "Use additional directory of package name in cache on the most nested level." + $ENV{CPM_USE_NAMED_CACHE_DIRECTORIES} +) set(CPM_VERSION ${CURRENT_CPM_VERSION} CACHE INTERNAL "" ) set(CPM_DIRECTORY - ${CMAKE_CURRENT_LIST_DIR} + ${CPM_CURRENT_DIRECTORY} CACHE INTERNAL "" ) set(CPM_FILE @@ -191,19 +244,14 @@ function(cpm_package_name_and_ver_from_url url outName outVer) endif() endfunction() -# Initialize logging prefix -if(NOT CPM_INDENT) - set(CPM_INDENT - "CPM:" - CACHE INTERNAL "" - ) -endif() - function(cpm_find_package NAME VERSION) string(REPLACE " " ";" EXTRA_ARGS "${ARGN}") find_package(${NAME} ${VERSION} ${EXTRA_ARGS} QUIET) if(${CPM_ARGS_NAME}_FOUND) - message(STATUS "${CPM_INDENT} using local package ${CPM_ARGS_NAME}@${VERSION}") + if(DEFINED ${CPM_ARGS_NAME}_VERSION) + set(VERSION ${${CPM_ARGS_NAME}_VERSION}) + endif() + cpm_message(STATUS "${CPM_INDENT} Using local package ${CPM_ARGS_NAME}@${VERSION}") CPMRegisterPackage(${CPM_ARGS_NAME} "${VERSION}") set(CPM_PACKAGE_FOUND YES @@ -223,7 +271,7 @@ function(cpm_create_module_file Name) if(NOT CPM_DONT_UPDATE_MODULE_PATH) # erase any previous modules file(WRITE ${CPM_MODULE_PATH}/Find${Name}.cmake - "include(${CPM_FILE})\n${ARGN}\nset(${Name}_FOUND TRUE)" + "include(\"${CPM_FILE}\")\n${ARGN}\nset(${Name}_FOUND TRUE)" ) endif() endfunction() @@ -240,14 +288,14 @@ function(CPMFindPackage) endif() endif() - if(CPM_DOWNLOAD_ALL) - CPMAddPackage(${ARGN}) - cpm_export_variables(${CPM_ARGS_NAME}) - return() + set(downloadPackage ${CPM_DOWNLOAD_ALL}) + if(DEFINED CPM_DOWNLOAD_${CPM_ARGS_NAME}) + set(downloadPackage ${CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + elseif(DEFINED ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) + set(downloadPackage $ENV{CPM_DOWNLOAD_${CPM_ARGS_NAME}}) endif() - - cpm_check_if_package_already_added(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}") - if(CPM_PACKAGE_ALREADY_ADDED) + if(downloadPackage) + CPMAddPackage(${ARGN}) cpm_export_variables(${CPM_ARGS_NAME}) return() endif() @@ -268,7 +316,7 @@ function(cpm_check_if_package_already_added CPM_ARGS_NAME CPM_ARGS_VERSION) if("${CPM_PACKAGE_VERSION}" VERSION_LESS "${CPM_ARGS_VERSION}") message( WARNING - "${CPM_INDENT} requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." + "${CPM_INDENT} Requires a newer version of ${CPM_ARGS_NAME} (${CPM_ARGS_VERSION}) than currently included (${CPM_PACKAGE_VERSION})." ) endif() cpm_get_fetch_properties(${CPM_ARGS_NAME}) @@ -325,11 +373,11 @@ function(cpm_parse_add_package_single_arg arg outArgs) set(packageType "git") else() # Give up - message(FATAL_ERROR "CPM: Can't determine package type of '${arg}'") + message(FATAL_ERROR "${CPM_INDENT} Can't determine package type of '${arg}'") endif() endif() - # For all packages we interpret @... as version. Only replace the last occurence. Thus URIs + # For all packages we interpret @... as version. Only replace the last occurrence. Thus URIs # containing '@' can be used string(REGEX REPLACE "@([^@]+)$" ";VERSION;\\1" out "${out}") @@ -345,7 +393,7 @@ function(cpm_parse_add_package_single_arg arg outArgs) else() # We should never get here. This is an assertion and hitting it means there's a bug in the code # above. A packageType was set, but not handled by this if-else. - message(FATAL_ERROR "CPM: Unsupported package type '${packageType}' of '${arg}'") + message(FATAL_ERROR "${CPM_INDENT} Unsupported package type '${packageType}' of '${arg}'") endif() set(${outArgs} @@ -354,14 +402,119 @@ function(cpm_parse_add_package_single_arg arg outArgs) ) endfunction() +# Check that the working directory for a git repo is clean +function(cpm_check_git_working_dir_is_clean repoPath gitTag isClean) + + find_package(Git REQUIRED) + + if(NOT GIT_EXECUTABLE) + # No git executable, assume directory is clean + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + # check for uncommitted changes + execute_process( + COMMAND ${GIT_EXECUTABLE} status --porcelain + RESULT_VARIABLE resultGitStatus + OUTPUT_VARIABLE repoStatus + OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET + WORKING_DIRECTORY ${repoPath} + ) + if(resultGitStatus) + # not supposed to happen, assume clean anyway + message(WARNING "${CPM_INDENT} Calling git status on folder ${repoPath} failed") + set(${isClean} + TRUE + PARENT_SCOPE + ) + return() + endif() + + if(NOT "${repoStatus}" STREQUAL "") + set(${isClean} + FALSE + PARENT_SCOPE + ) + return() + endif() + + # check for committed changes + execute_process( + COMMAND ${GIT_EXECUTABLE} diff -s --exit-code ${gitTag} + RESULT_VARIABLE resultGitDiff + OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_QUIET + WORKING_DIRECTORY ${repoPath} + ) + + if(${resultGitDiff} EQUAL 0) + set(${isClean} + TRUE + PARENT_SCOPE + ) + else() + set(${isClean} + FALSE + PARENT_SCOPE + ) + endif() + +endfunction() + +# method to overwrite internal FetchContent properties, to allow using CPM.cmake to overload +# FetchContent calls. As these are internal cmake properties, this method should be used carefully +# and may need modification in future CMake versions. Source: +# https://github.com/Kitware/CMake/blob/dc3d0b5a0a7d26d43d6cfeb511e224533b5d188f/Modules/FetchContent.cmake#L1152 +function(cpm_override_fetchcontent contentName) + cmake_parse_arguments(PARSE_ARGV 1 arg "" "SOURCE_DIR;BINARY_DIR" "") + if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "") + message(FATAL_ERROR "${CPM_INDENT} Unsupported arguments: ${arg_UNPARSED_ARGUMENTS}") + endif() + + string(TOLOWER ${contentName} contentNameLower) + set(prefix "_FetchContent_${contentNameLower}") + + set(propertyName "${prefix}_sourceDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_SOURCE_DIR}") + + set(propertyName "${prefix}_binaryDir") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} "${arg_BINARY_DIR}") + + set(propertyName "${prefix}_populated") + define_property( + GLOBAL + PROPERTY ${propertyName} + BRIEF_DOCS "Internal implementation detail of FetchContent_Populate()" + FULL_DOCS "Details used by FetchContent_Populate() for ${contentName}" + ) + set_property(GLOBAL PROPERTY ${propertyName} TRUE) +endfunction() + # Download and add a package from source function(CPMAddPackage) + cpm_set_policies() + list(LENGTH ARGN argnLength) if(argnLength EQUAL 1) cpm_parse_add_package_single_arg("${ARGN}" ARGN) - # The shorthand syntax implies EXCLUDE_FROM_ALL - set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES") + # The shorthand syntax implies EXCLUDE_FROM_ALL and SYSTEM + set(ARGN "${ARGN};EXCLUDE_FROM_ALL;YES;SYSTEM;YES;") endif() set(oneValueArgs @@ -375,15 +528,16 @@ function(CPMAddPackage) BITBUCKET_REPOSITORY GIT_REPOSITORY SOURCE_DIR - DOWNLOAD_COMMAND FIND_PACKAGE_ARGUMENTS NO_CACHE + SYSTEM GIT_SHALLOW EXCLUDE_FROM_ALL SOURCE_SUBDIR + CUSTOM_CACHE_KEY ) - set(multiValueArgs URL OPTIONS) + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" "${ARGN}") @@ -454,7 +608,7 @@ function(CPMAddPackage) if(NOT DEFINED CPM_ARGS_NAME) message( FATAL_ERROR - "CPM: 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" + "${CPM_INDENT} 'NAME' was not provided and couldn't be automatically inferred for package added with arguments: '${ARGN}'" ) endif() @@ -473,8 +627,10 @@ function(CPMAddPackage) NAME "${CPM_ARGS_NAME}" SOURCE_DIR "${PACKAGE_SOURCE}" EXCLUDE_FROM_ALL "${CPM_ARGS_EXCLUDE_FROM_ALL}" + SYSTEM "${CPM_ARGS_SYSTEM}" OPTIONS "${CPM_ARGS_OPTIONS}" SOURCE_SUBDIR "${CPM_ARGS_SOURCE_SUBDIR}" + DOWNLOAD_ONLY "${DOWNLOAD_ONLY}" FORCE True ) cpm_export_variables(${CPM_ARGS_NAME}) @@ -492,19 +648,21 @@ function(CPMAddPackage) return() endif() - if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) - cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) + if(NOT CPM_ARGS_FORCE) + if(CPM_USE_LOCAL_PACKAGES OR CPM_LOCAL_PACKAGES_ONLY) + cpm_find_package(${CPM_ARGS_NAME} "${CPM_ARGS_VERSION}" ${CPM_ARGS_FIND_PACKAGE_ARGUMENTS}) - if(CPM_PACKAGE_FOUND) - cpm_export_variables(${CPM_ARGS_NAME}) - return() - endif() + if(CPM_PACKAGE_FOUND) + cpm_export_variables(${CPM_ARGS_NAME}) + return() + endif() - if(CPM_LOCAL_PACKAGES_ONLY) - message( - SEND_ERROR - "CPM: ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" - ) + if(CPM_LOCAL_PACKAGES_ONLY) + message( + SEND_ERROR + "${CPM_INDENT} ${CPM_ARGS_NAME} not found via find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION})" + ) + endif() endif() endif() @@ -529,28 +687,82 @@ function(CPMAddPackage) list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS DOWNLOAD_COMMAND ${CPM_ARGS_DOWNLOAD_COMMAND}) elseif(DEFINED CPM_ARGS_SOURCE_DIR) list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${CPM_ARGS_SOURCE_DIR}) + if(NOT IS_ABSOLUTE ${CPM_ARGS_SOURCE_DIR}) + # Expand `CPM_ARGS_SOURCE_DIR` relative path. This is important because EXISTS doesn't work + # for relative paths. + get_filename_component( + source_directory ${CPM_ARGS_SOURCE_DIR} REALPATH BASE_DIR ${CMAKE_CURRENT_BINARY_DIR} + ) + else() + set(source_directory ${CPM_ARGS_SOURCE_DIR}) + endif() + if(NOT EXISTS ${source_directory}) + string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) + # remove timestamps so CMake will re-download the dependency + file(REMOVE_RECURSE "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-subbuild") + endif() elseif(CPM_SOURCE_CACHE AND NOT CPM_ARGS_NO_CACHE) string(TOLOWER ${CPM_ARGS_NAME} lower_case_name) set(origin_parameters ${CPM_ARGS_UNPARSED_ARGUMENTS}) list(SORT origin_parameters) - string(SHA1 origin_hash "${origin_parameters}") - set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) + if(CPM_ARGS_CUSTOM_CACHE_KEY) + # Application set a custom unique directory name + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${CPM_ARGS_CUSTOM_CACHE_KEY}) + elseif(CPM_USE_NAMED_CACHE_DIRECTORIES) + string(SHA1 origin_hash "${origin_parameters};NEW_CACHE_STRUCTURE_TAG") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}/${CPM_ARGS_NAME}) + else() + string(SHA1 origin_hash "${origin_parameters}") + set(download_directory ${CPM_SOURCE_CACHE}/${lower_case_name}/${origin_hash}) + endif() # Expand `download_directory` relative path. This is important because EXISTS doesn't work for # relative paths. get_filename_component(download_directory ${download_directory} ABSOLUTE) list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS SOURCE_DIR ${download_directory}) + + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock) + endif() + if(EXISTS ${download_directory}) - # avoid FetchContent modules to improve performance - set(${CPM_ARGS_NAME}_BINARY_DIR ${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build) - set(${CPM_ARGS_NAME}_ADDED YES) - set(${CPM_ARGS_NAME}_SOURCE_DIR ${download_directory}) + if(CPM_SOURCE_CACHE) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} "${download_directory}" + "${CPM_FETCHCONTENT_BASE_DIR}/${lower_case_name}-build" + ) + cpm_get_fetch_properties("${CPM_ARGS_NAME}") + + if(DEFINED CPM_ARGS_GIT_TAG AND NOT (PATCH_COMMAND IN_LIST CPM_ARGS_UNPARSED_ARGUMENTS)) + # warn if cache has been changed since checkout + cpm_check_git_working_dir_is_clean(${download_directory} ${CPM_ARGS_GIT_TAG} IS_CLEAN) + if(NOT ${IS_CLEAN}) + message( + WARNING "${CPM_INDENT} Cache for ${CPM_ARGS_NAME} (${download_directory}) is dirty" + ) + endif() + endif() + cpm_add_subdirectory( - "${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}" - "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}" - "${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}" + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" ) - set(CPM_SKIP_FETCH TRUE) set(PACKAGE_INFO "${PACKAGE_INFO} at ${download_directory}") + + # As the source dir is already cached/populated, we override the call to FetchContent. + set(CPM_SKIP_FETCH TRUE) + cpm_override_fetchcontent( + "${lower_case_name}" SOURCE_DIR "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + BINARY_DIR "${${CPM_ARGS_NAME}_BINARY_DIR}" + ) + else() # Enable shallow clone when GIT_TAG is not a commit hash. Our guess may not be accurate, but # it should guarantee no commit hash get mis-detected. @@ -567,7 +779,7 @@ function(CPMAddPackage) endif() endif() - cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(${ARGN})") + cpm_create_module_file(${CPM_ARGS_NAME} "CPMAddPackage(\"${ARGN}\")") if(CPM_PACKAGE_LOCK_ENABLED) if((CPM_ARGS_VERSION AND NOT CPM_ARGS_SOURCE_DIR) OR CPM_INCLUDE_ALL_IN_PACKAGE_LOCK) @@ -579,20 +791,29 @@ function(CPMAddPackage) endif() endif() - message( - STATUS "${CPM_INDENT} adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" + cpm_message( + STATUS "${CPM_INDENT} Adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION} (${PACKAGE_INFO})" ) if(NOT CPM_SKIP_FETCH) cpm_declare_fetch( "${CPM_ARGS_NAME}" "${CPM_ARGS_VERSION}" "${PACKAGE_INFO}" "${CPM_ARGS_UNPARSED_ARGUMENTS}" ) - cpm_fetch_package("${CPM_ARGS_NAME}") - cpm_add_subdirectory( - "${CPM_ARGS_NAME}" "${DOWNLOAD_ONLY}" - "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" "${${CPM_ARGS_NAME}_BINARY_DIR}" - "${CPM_ARGS_EXCLUDE_FROM_ALL}" "${CPM_ARGS_OPTIONS}" - ) + cpm_fetch_package("${CPM_ARGS_NAME}" populated) + if(CPM_SOURCE_CACHE AND download_directory) + file(LOCK ${download_directory}/../cmake.lock RELEASE) + endif() + if(${populated}) + cpm_add_subdirectory( + "${CPM_ARGS_NAME}" + "${DOWNLOAD_ONLY}" + "${${CPM_ARGS_NAME}_SOURCE_DIR}/${CPM_ARGS_SOURCE_SUBDIR}" + "${${CPM_ARGS_NAME}_BINARY_DIR}" + "${CPM_ARGS_EXCLUDE_FROM_ALL}" + "${CPM_ARGS_SYSTEM}" + "${CPM_ARGS_OPTIONS}" + ) + endif() cpm_get_fetch_properties("${CPM_ARGS_NAME}") endif() @@ -605,7 +826,7 @@ macro(CPMGetPackage Name) if(DEFINED "CPM_DECLARATION_${Name}") CPMAddPackage(NAME ${Name}) else() - message(SEND_ERROR "Cannot retrieve package ${Name}: no declaration available") + message(SEND_ERROR "${CPM_INDENT} Cannot retrieve package ${Name}: no declaration available") endif() endmacro() @@ -623,10 +844,14 @@ macro(cpm_export_variables name) "${${name}_ADDED}" PARENT_SCOPE ) + set(CPM_LAST_PACKAGE_NAME + "${name}" + PARENT_SCOPE + ) endmacro() # declares a package, so that any call to CPMAddPackage for the package name will use these -# arguments instead. Previous declarations will not be overriden. +# arguments instead. Previous declarations will not be overridden. macro(CPMDeclarePackage Name) if(NOT DEFINED "CPM_DECLARATION_${Name}") set("CPM_DECLARATION_${Name}" "${ARGN}") @@ -649,7 +874,7 @@ function(cpm_add_comment_to_package_lock Name) endif() endfunction() -# includes the package lock file if it exists and creates a target `cpm-write-package-lock` to +# includes the package lock file if it exists and creates a target `cpm-update-package-lock` to # update it macro(CPMUsePackageLock file) if(NOT CPM_DONT_CREATE_PACKAGE_LOCK) @@ -691,7 +916,7 @@ endfunction() # declares a package in FetchContent_Declare function(cpm_declare_fetch PACKAGE VERSION INFO) if(${CPM_DRY_RUN}) - message(STATUS "${CPM_INDENT} package not declared (dry run)") + cpm_message(STATUS "${CPM_INDENT} Package not declared (dry run)") return() endif() @@ -703,18 +928,32 @@ function(cpm_get_fetch_properties PACKAGE) if(${CPM_DRY_RUN}) return() endif() - FetchContent_GetProperties(${PACKAGE}) - string(TOLOWER ${PACKAGE} lpackage) + set(${PACKAGE}_SOURCE_DIR - "${${lpackage}_SOURCE_DIR}" + "${CPM_PACKAGE_${PACKAGE}_SOURCE_DIR}" PARENT_SCOPE ) set(${PACKAGE}_BINARY_DIR - "${${lpackage}_BINARY_DIR}" + "${CPM_PACKAGE_${PACKAGE}_BINARY_DIR}" PARENT_SCOPE ) endfunction() +function(cpm_store_fetch_properties PACKAGE source_dir binary_dir) + if(${CPM_DRY_RUN}) + return() + endif() + + set(CPM_PACKAGE_${PACKAGE}_SOURCE_DIR + "${source_dir}" + CACHE INTERNAL "" + ) + set(CPM_PACKAGE_${PACKAGE}_BINARY_DIR + "${binary_dir}" + CACHE INTERNAL "" + ) +endfunction() + # adds a package as a subdirectory if viable, according to provided options function( cpm_add_subdirectory @@ -723,22 +962,23 @@ function( SOURCE_DIR BINARY_DIR EXCLUDE + SYSTEM OPTIONS ) + if(NOT DOWNLOAD_ONLY AND EXISTS ${SOURCE_DIR}/CMakeLists.txt) + set(addSubdirectoryExtraArgs "") if(EXCLUDE) - set(addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) - else() - set(addSubdirectoryExtraArgs "") + list(APPEND addSubdirectoryExtraArgs EXCLUDE_FROM_ALL) + endif() + if("${SYSTEM}" AND "${CMAKE_VERSION}" VERSION_GREATER_EQUAL "3.25") + # https://cmake.org/cmake/help/latest/prop_dir/SYSTEM.html#prop_dir:SYSTEM + list(APPEND addSubdirectoryExtraArgs SYSTEM) endif() if(OPTIONS) - # the policy allows us to change options without caching - cmake_policy(SET CMP0077 NEW) - set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - foreach(OPTION ${OPTIONS}) - cpm_parse_option(${OPTION}) - set(${OPTION_KEY} ${OPTION_VALUE}) + cpm_parse_option("${OPTION}") + set(${OPTION_KEY} "${OPTION_VALUE}") endforeach() endif() set(CPM_OLD_INDENT "${CPM_INDENT}") @@ -750,19 +990,32 @@ endfunction() # downloads a previously declared package via FetchContent and exports the variables # `${PACKAGE}_SOURCE_DIR` and `${PACKAGE}_BINARY_DIR` to the parent scope -function(cpm_fetch_package PACKAGE) +function(cpm_fetch_package PACKAGE populated) + set(${populated} + FALSE + PARENT_SCOPE + ) if(${CPM_DRY_RUN}) - message(STATUS "${CPM_INDENT} package ${PACKAGE} not fetched (dry run)") + cpm_message(STATUS "${CPM_INDENT} Package ${PACKAGE} not fetched (dry run)") return() endif() FetchContent_GetProperties(${PACKAGE}) + string(TOLOWER "${PACKAGE}" lower_case_name) + if(NOT ${lower_case_name}_POPULATED) FetchContent_Populate(${PACKAGE}) + set(${populated} + TRUE + PARENT_SCOPE + ) endif() - string(TOLOWER "${PACKAGE}" lower_case_name) + cpm_store_fetch_properties( + ${CPM_ARGS_NAME} ${${lower_case_name}_SOURCE_DIR} ${${lower_case_name}_BINARY_DIR} + ) + set(${PACKAGE}_SOURCE_DIR ${${lower_case_name}_SOURCE_DIR} PARENT_SCOPE @@ -775,15 +1028,15 @@ endfunction() # splits a package option function(cpm_parse_option OPTION) - string(REGEX MATCH "^[^ ]+" OPTION_KEY ${OPTION}) - string(LENGTH ${OPTION} OPTION_LENGTH) - string(LENGTH ${OPTION_KEY} OPTION_KEY_LENGTH) + string(REGEX MATCH "^[^ ]+" OPTION_KEY "${OPTION}") + string(LENGTH "${OPTION}" OPTION_LENGTH) + string(LENGTH "${OPTION_KEY}" OPTION_KEY_LENGTH) if(OPTION_KEY_LENGTH STREQUAL OPTION_LENGTH) # no value for key provided, assume user wants to set option to "ON" set(OPTION_VALUE "ON") else() math(EXPR OPTION_KEY_LENGTH "${OPTION_KEY_LENGTH}+1") - string(SUBSTRING ${OPTION} "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) + string(SUBSTRING "${OPTION}" "${OPTION_KEY_LENGTH}" "-1" OPTION_VALUE) endif() set(OPTION_KEY "${OPTION_KEY}" @@ -813,7 +1066,7 @@ function(cpm_get_version_from_git_tag GIT_TAG RESULT) endif() endfunction() -# guesses if the git tag is a commit hash or an actual tag or a branch nane. +# guesses if the git tag is a commit hash or an actual tag or a branch name. function(cpm_is_git_tag_commit_hash GIT_TAG RESULT) string(LENGTH "${GIT_TAG}" length) # full hash has 40 characters, and short hash has at least 7 characters. @@ -846,14 +1099,17 @@ function(cpm_prettify_package_arguments OUT_VAR IS_IN_COMMENT) DOWNLOAD_ONLY GITHUB_REPOSITORY GITLAB_REPOSITORY + BITBUCKET_REPOSITORY GIT_REPOSITORY SOURCE_DIR - DOWNLOAD_COMMAND FIND_PACKAGE_ARGUMENTS NO_CACHE + SYSTEM GIT_SHALLOW + EXCLUDE_FROM_ALL + SOURCE_SUBDIR ) - set(multiValueArgs OPTIONS) + set(multiValueArgs URL OPTIONS DOWNLOAD_COMMAND) cmake_parse_arguments(CPM_ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) foreach(oneArgName ${oneValueArgs}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1112aaa6..e13b7520 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ CPMAddPackage( NAME FastSIMD GITHUB_REPOSITORY Auburn/FastSIMD - GIT_TAG 5bcddffbefa144138f572fe32e4e1d50a1d32deb + GIT_TAG 504e54fe5ec580e933ede0fb70a11bbc25dff714 ) set(install_targets ${install_targets} @@ -54,7 +54,11 @@ set_target_properties(FastNoise PROPERTIES DEBUG_POSTFIX D COMPILE_PDB_NAME_DEBUG FastNoiseD) -fastsimd_create_dispatch_library(FastSIMD_FastNoise SOURCES "FastNoise/FastSIMD_Build.inl") +if(NOT FASTNOISE2_STRICT_FP) + set(FASTSIMD_RELAXED RELAXED) +endif() + +fastsimd_create_dispatch_library(FastSIMD_FastNoise ${FASTSIMD_RELAXED} SOURCES "FastNoise/FastSIMD_Build.inl") target_include_directories(FastSIMD_FastNoise PRIVATE "../include/") @@ -65,13 +69,13 @@ endif() target_link_libraries(FastNoise PUBLIC FastSIMD FastSIMD_FastNoise) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") - target_compile_options(FastSIMD_FastNoise PRIVATE /GL- /GS- /fp:fast /wd4251 /d2vzeroupper-) + target_compile_options(FastSIMD_FastNoise PRIVATE /GL- /GS- /wd4251 /d2vzeroupper-) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") if(MSVC) - target_compile_options(FastSIMD_FastNoise PRIVATE /GS- /fp:fast) + target_compile_options(FastSIMD_FastNoise PRIVATE /GS-) else() - target_compile_options(FastSIMD_FastNoise PRIVATE -ffast-math -fno-stack-protector) + target_compile_options(FastSIMD_FastNoise PRIVATE -fno-stack-protector) endif() if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") @@ -79,6 +83,12 @@ elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" else() target_compile_options(FastSIMD_FastNoise PRIVATE -mllvm -x86-use-vzeroupper=0) endif() - endif() +if(NOT FASTNOISE2_STRICT_FP) + if(MSVC) + target_compile_options(FastSIMD_FastNoise PRIVATE /fp:fast) + else() + target_compile_options(FastSIMD_FastNoise PRIVATE -ffast-math) + endif() +endif() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 91c4ce3c..7dd7ad95 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -12,34 +12,43 @@ CPMAddPackage( "CORRADE_WITH_TESTSUITE OFF" ) -CPMAddPackage( - NAME GLFW - GITHUB_REPOSITORY glfw/glfw - GIT_TAG 3.3.9 - EXCLUDE_FROM_ALL YES - OPTIONS - "BUILD_SHARED_LIBS OFF" - "GLFW_INSTALL OFF" - "GLFW_BUILD_TESTS OFF" - "GLFW_BUILD_EXAMPLES OFF" - "GLFW_BUILD_DOCS OFF" -) +if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(NODE_EDITOR_APP_TYPE_CAPS "EMSCRIPTEN") + set(NODE_EDITOR_APP_TYPE "Emscripten") +else() + set(NODE_EDITOR_APP_TYPE_CAPS "GLFW") + set(NODE_EDITOR_APP_TYPE "Glfw") + + CPMAddPackage( + NAME GLFW + GITHUB_REPOSITORY glfw/glfw + GIT_TAG 3.3.9 + EXCLUDE_FROM_ALL YES + OPTIONS + "BUILD_SHARED_LIBS OFF" + "GLFW_INSTALL OFF" + "GLFW_BUILD_TESTS OFF" + "GLFW_BUILD_EXAMPLES OFF" + "GLFW_BUILD_DOCS OFF" + ) +endif() CPMAddPackage( NAME magnum GITHUB_REPOSITORY mosra/magnum - GIT_TAG b1419017650c83538d8fe4681de6f0bca524cf49 + GIT_TAG c9a884938c606b7d4555da6d278d1f3e09588c3e GIT_SUBMODULES "src" EXCLUDE_FROM_ALL YES OPTIONS "MAGNUM_BUILD_STATIC ON" "MAGNUM_BUILD_PLUGINS_STATIC ON" "MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS OFF" - "MAGNUM_WITH_GLFWAPPLICATION ON" + "MAGNUM_WITH_${NODE_EDITOR_APP_TYPE_CAPS}APPLICATION ON" "MAGNUM_WITH_MESHTOOLS OFF" "MAGNUM_WITH_TRADE OFF" "MAGNUM_WITH_TEXT OFF" "MAGNUM_WITH_TEXTURETOOLS OFF" + "MAGNUM_TARGET_GLES2 OFF" ) CPMAddPackage( @@ -66,7 +75,7 @@ CPMAddPackage( # Use modules from magnum-integration since it has everything we need set(CMAKE_MODULE_PATH "${magnum-integration_SOURCE_DIR}/modules" ${CMAKE_MODULE_PATH}) -find_package(Magnum REQUIRED GL GlfwApplication) +find_package(Magnum REQUIRED GL ${NODE_EDITOR_APP_TYPE}Application) find_package(MagnumIntegration REQUIRED ImGui) find_package(ImGui REQUIRED SourcesMiscCpp) @@ -130,7 +139,23 @@ if(CORRADE_TARGET_WINDOWS) target_sources(NodeEditor PRIVATE WindowsHiDPI.manifest) endif() -if (UNIX) +if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(CMAKE_EXECUTABLE_SUFFIX ".html") + target_compile_options(NodeEditor PRIVATE -pthread -msimd128) + target_link_options(NodeEditor PRIVATE + "-sPTHREAD_POOL_SIZE=Math.max(2,navigator.hardwareConcurrency)+3-navigator.hardwareConcurrency/4" + -pthread -sALLOW_MEMORY_GROWTH=1 -lidbfs.js -s FORCE_FILESYSTEM + --shell-file "${CMAKE_CURRENT_SOURCE_DIR}/emscripten_shell.html" + --pre-js "${CMAKE_CURRENT_SOURCE_DIR}/emscripten_pre.js" + -Wl,-u,_emscripten_run_callback_on_thread + ) + add_custom_command(TARGET NodeEditor POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_SOURCE_DIR}/emscripten_enable_shared_array_buffer.js" + $ + ) + +elseif (UNIX) target_link_options(NodeEditor PRIVATE -pthread) if(APPLE) diff --git a/tools/FastNoiseNodeEditor.cpp b/tools/FastNoiseNodeEditor.cpp index e9bad670..a2451bd4 100644 --- a/tools/FastNoiseNodeEditor.cpp +++ b/tools/FastNoiseNodeEditor.cpp @@ -22,7 +22,7 @@ using namespace Magnum; #include "SharedMemoryIpc.inl" -static constexpr const char* kNodeGraphSettingsFile = "NodeGraph.ini"; +static constexpr const char* kNodeGraphSettingsFile = FILESYSTEM_ROOT "NodeGraph.ini"; void FastNoiseNodeEditor::OpenStandaloneNodeGraph() { @@ -67,7 +67,7 @@ void FastNoiseNodeEditor::OpenStandaloneNodeGraph() CloseHandle( pi.hThread ); } else -#else +#elif !defined( __EMSCRIPTEN__ ) pid_t pid = fork(); // Duplicate current process if( pid == 0 ) @@ -678,6 +678,7 @@ FastNoiseNodeEditor::~FastNoiseNodeEditor() ImGuiContext* currentContext = ImGui::GetCurrentContext(); ImGui::SetCurrentContext( ImNodes::GetNodeEditorImGuiContext() ); ImGui::SaveIniSettingsToDisk( kNodeGraphSettingsFile ); + NodeEditorApp::SyncFileSystem(); ImGui::SetCurrentContext( currentContext ); ImNodes::DestroyContext(); @@ -715,7 +716,7 @@ void FastNoiseNodeEditor::DoNodeBenchmarks() void FastNoiseNodeEditor::Draw( const Matrix4& transformation, const Matrix4& projection, const Vector3& cameraPosition ) { -#ifndef WIN32 +#if !defined( WIN32 ) && !defined( __EMSCRIPTEN__ ) static pid_t parentPid = getppid(); if( getppid() != parentPid ) @@ -829,6 +830,7 @@ void FastNoiseNodeEditor::Draw( const Matrix4& transformation, const Matrix4& pr { ImGui::SaveIniSettingsToDisk( kNodeGraphSettingsFile ); ImGui::GetIO().WantSaveIniSettings = false; + NodeEditorApp::SyncFileSystem(); } // Open this after saving settings diff --git a/tools/MeshNoisePreview.cpp b/tools/MeshNoisePreview.cpp index ab52e3c3..ce44f4c8 100644 --- a/tools/MeshNoisePreview.cpp +++ b/tools/MeshNoisePreview.cpp @@ -47,6 +47,8 @@ MeshNoisePreview::MeshNoisePreview() mThreads.emplace_back( GenerateLoopThread, std::ref( mGenerateQueue ), std::ref( mCompleteQueue ) ); } + Debug{} << "Mesh generator thread count: " << mThreads.size(); + SetupSettingsHandlers(); } @@ -172,7 +174,7 @@ void MeshNoisePreview::Draw( const Matrix4& transformation, const Matrix4& proje } ImGui::Text( "Triangle Count: %0.1fM (%0.1fM)", mTriCount / 1000000.0f, drawnTriCount / 3000000.0f ); - ImGui::Text( "Voxel Count: %0.1fM", ( mChunks.size() * Chunk::SIZE * Chunk::SIZE * Chunk::SIZE ) / 1000000.0 ); + ImGui::Text( "Voxel Count: %0.1fM", mChunks.size() * ( Chunk::SIZE * Chunk::SIZE * Chunk::SIZE / 1000000.0f ) ); ImGui::Text( "Loaded Chunks: %zu (%d)", mChunks.size(), mMeshesCount ); size_t generateCount = mGenerateQueue.Count(); diff --git a/tools/NodeEditorApp.cpp b/tools/NodeEditorApp.cpp index 3bb9d323..a78d346f 100644 --- a/tools/NodeEditorApp.cpp +++ b/tools/NodeEditorApp.cpp @@ -8,12 +8,18 @@ #include #include +#ifdef __EMSCRIPTEN__ +#include +#endif + #include "NodeEditorApp.h" #include "ImGuiExtra.h" #include "FastSIMD/FastSIMD_FastNoise_config.h" using namespace Magnum; +static constexpr const char* kAppSettingsFile = FILESYSTEM_ROOT "NodeEditor.ini"; + void InitResources() { #ifdef MAGNUM_BUILD_STATIC @@ -30,10 +36,14 @@ NodeEditorApp::NodeEditorApp( const Arguments& arguments ) : Platform::Application{ arguments, Configuration{} .setTitle( IsDetached( arguments ) ? "FastNoise2 Node Graph" : "FastNoise2 Node Editor" ) +#ifdef __EMSCRIPTEN__ + .setWindowFlags( Configuration::WindowFlag::Resizable ) +#else .setSize( Vector2i( 1280, 720 ) ) .setWindowFlags( Configuration::WindowFlag::Resizable | ( IsDetached( arguments ) ? (Configuration::WindowFlag)0 : Configuration::WindowFlag::Maximized ) ), GLConfiguration{} .setSampleCount( 4 ) +#endif }, mIsDetachedNodeGraph( IsDetached( arguments ) ), mExecutablePath( arguments.argv[0] ), @@ -54,13 +64,18 @@ NodeEditorApp::NodeEditorApp( const Arguments& arguments ) : ImGui::GetIO().Fonts->AddFontFromMemoryTTF( const_cast( font.data() ), (int)font.size(), 14.0f * framebufferSize().x() / size.x(), &fontConfig ); } - ImGui::GetIO().IniFilename = "NodeEditor.ini"; + // We manually save so we can sync the filesystem on emscripten + ImGui::GetIO().IniFilename = nullptr; + ImGui::LoadIniSettingsFromDisk( kAppSettingsFile ); + ImGui::GetIO().ConfigDragClickToInputText = true; mImGuiIntegrationContext = ImGuiIntegration::Context( *mImGuiContext, size, windowSize(), framebufferSize() ); GL::Renderer::enable( GL::Renderer::Feature::DepthTest ); +#ifndef __EMSCRIPTEN__ setSwapInterval( 1 ); +#endif mFrameTime.start(); @@ -95,12 +110,31 @@ NodeEditorApp::~NodeEditorApp() FastNoiseNodeEditor::ReleaseSharedMemoryIpc(); } +void NodeEditorApp::SyncFileSystem() +{ +#ifdef __EMSCRIPTEN__ + // Don't forget to sync to make sure you store it to IndexedDB + EM_ASM( + FS.syncfs( false, function( err ) { + if (err) { + console.warn("Error saving:", err); + } } ); ); +#endif +} + void NodeEditorApp::drawEvent() { GL::defaultFramebuffer.clear( GL::FramebufferClear::Color | GL::FramebufferClear::Depth ); mImGuiIntegrationContext.newFrame(); + if( ImGui::GetIO().WantSaveIniSettings ) + { + ImGui::SaveIniSettingsToDisk( kAppSettingsFile ); + ImGui::GetIO().WantSaveIniSettings = false; + SyncFileSystem(); + } + /* Enable text input, if needed */ if( ImGui::GetIO().WantTextInput && !isTextInputActive() ) startTextInput(); diff --git a/tools/NodeEditorApp.h b/tools/NodeEditorApp.h index be9839cf..f5be0746 100644 --- a/tools/NodeEditorApp.h +++ b/tools/NodeEditorApp.h @@ -1,8 +1,16 @@ #pragma once #include -#include + +#ifdef __EMSCRIPTEN__ +#define FILESYSTEM_ROOT "/fastnoise2/" +#include +#else +#define FILESYSTEM_ROOT #include +#endif + +#include #include #include #include @@ -33,6 +41,8 @@ namespace Magnum return mExecutablePath; } + static void SyncFileSystem(); + private: void drawEvent() override; void viewportEvent( ViewportEvent& event ) override; diff --git a/tools/NoiseTexture.cpp b/tools/NoiseTexture.cpp index fe962823..dded0ad4 100644 --- a/tools/NoiseTexture.cpp +++ b/tools/NoiseTexture.cpp @@ -36,6 +36,8 @@ NoiseTexture::NoiseTexture() mThreads.emplace_back( GenerateLoopThread, std::ref( mGenerateQueue ), std::ref( mCompleteQueue ) ); } + Debug{} << "Texture generator thread count: " << mThreads.size(); + SetupSettingsHandlers(); } @@ -61,7 +63,7 @@ void NoiseTexture::Draw() if( mCurrentIteration < texData.iteration ) { mCurrentIteration = texData.iteration; - ImageView2D noiseImage( PixelFormat::RGBA8Srgb, texData.size, texData.textureData ); + ImageView2D noiseImage( PixelFormat::RGBA8Unorm, texData.size, texData.textureData ); SetPreviewTexture( noiseImage ); } texData.Free(); @@ -131,7 +133,7 @@ void NoiseTexture::Draw() ImGui::PushStyleColor( ImGuiCol_Button, 0 ); ImGui::PushStyleColor( ImGuiCol_ButtonActive, 0 ); ImGui::PushStyleColor( ImGuiCol_ButtonHovered, 0 ); - ImGuiIntegration::imageButton( mNoiseTexture, Vector2( mNoiseTexture.imageSize( 0 ) ), {{},Vector2{1}}, 0 ); + ImGuiIntegration::imageButton( mNoiseTexture, Vector2( mBuildData.size ), { {}, Vector2 { 1 } }, 0 ); ImGui::PopStyleColor( 3 ); if( ImGui::IsItemHovered() ) diff --git a/tools/SharedMemoryIpc.inl b/tools/SharedMemoryIpc.inl index 0f213f4f..380c0d5b 100644 --- a/tools/SharedMemoryIpc.inl +++ b/tools/SharedMemoryIpc.inl @@ -1,3 +1,4 @@ +#ifndef __EMSCRIPTEN__ #ifdef _WIN32 #define NOMINMAX #define WIN32_LEAN_AND_MEAN @@ -8,6 +9,7 @@ #include // For mode constants #include #endif +#endif static constexpr const char* kSharedMemoryName = "/FastNoise2NodeEditor"; static constexpr unsigned int kSharedMemorySize = 64 * 1024; @@ -15,7 +17,9 @@ static constexpr unsigned int kSharedMemorySize = 64 * 1024; // Setup shared memory for IPC selected node ENT updates void* FastNoiseNodeEditor::SetupSharedMemoryIpc() { -#ifdef WIN32 +#ifdef __EMSCRIPTEN__ + return nullptr; +#elif defined( WIN32 ) // Create a shared memory file mapping HANDLE hMapFile = CreateFileMapping( INVALID_HANDLE_VALUE, // Use paging file - shared memory @@ -76,7 +80,7 @@ void* FastNoiseNodeEditor::SetupSharedMemoryIpc() void FastNoiseNodeEditor::ReleaseSharedMemoryIpc() { -#ifndef WIN32 +#if !defined( WIN32 ) && !defined( __EMSCRIPTEN__ ) shm_unlink( kSharedMemoryName ); #endif } diff --git a/tools/emscripten_enable_shared_array_buffer.js b/tools/emscripten_enable_shared_array_buffer.js new file mode 100644 index 00000000..83bf5d94 --- /dev/null +++ b/tools/emscripten_enable_shared_array_buffer.js @@ -0,0 +1,75 @@ +// NOTE: This file creates a service worker that cross-origin-isolates the page (read more here: https://web.dev/coop-coep/) which allows us to use wasm threads. +// Normally you would set the COOP and COEP headers on the server to do this, but Github Pages doesn't allow this, so this is a hack to do that. + +/* Edited version of: coi-serviceworker v0.1.6 - Guido Zuidhof, licensed under MIT */ +// From here: https://github.com/gzuidhof/coi-serviceworker +if(typeof window === 'undefined') { + self.addEventListener("install", () => self.skipWaiting()); + self.addEventListener("activate", e => e.waitUntil(self.clients.claim())); + + async function handleFetch(request) { + if(request.cache === "only-if-cached" && request.mode !== "same-origin") { + return; + } + + if(request.mode === "no-cors") { // We need to set `credentials` to "omit" for no-cors requests, per this comment: https://bugs.chromium.org/p/chromium/issues/detail?id=1309901#c7 + request = new Request(request.url, { + cache: request.cache, + credentials: "omit", + headers: request.headers, + integrity: request.integrity, + destination: request.destination, + keepalive: request.keepalive, + method: request.method, + mode: request.mode, + redirect: request.redirect, + referrer: request.referrer, + referrerPolicy: request.referrerPolicy, + signal: request.signal, + }); + } + + let r = await fetch(request).catch(e => console.error(e)); + + if(r.status === 0) { + return r; + } + + const headers = new Headers(r.headers); + headers.set("Cross-Origin-Embedder-Policy", "require-corp"); // or: credentialless + headers.set("Cross-Origin-Opener-Policy", "same-origin"); + + return new Response(r.body, { status: r.status, statusText: r.statusText, headers }); + } + + self.addEventListener("fetch", function(e) { + e.respondWith(handleFetch(e.request)); // respondWith must be executed synchonously (but can be passed a Promise) + }); + +} else { + (async function() { + if(window.crossOriginIsolated !== false) return; + + let registration = await navigator.serviceWorker.register(window.document.currentScript.src).catch(e => console.error("COOP/COEP Service Worker failed to register:", e)); + if(registration) { + console.log("COOP/COEP Service Worker registered", registration.scope); + + registration.addEventListener("updatefound", () => { + console.log("Reloading page to make use of updated COOP/COEP Service Worker."); + window.location.reload(); + }); + + // If the registration is active, but it's not controlling the page + if(registration.active && !navigator.serviceWorker.controller) { + console.log("Reloading page to make use of COOP/COEP Service Worker."); + window.location.reload(); + } + } + })(); +} + +// Code to deregister: +// let registrations = await navigator.serviceWorker.getRegistrations(); +// for(let registration of registrations) { +// await registration.unregister(); +// } diff --git a/tools/emscripten_pre.js b/tools/emscripten_pre.js new file mode 100644 index 00000000..f01af27c --- /dev/null +++ b/tools/emscripten_pre.js @@ -0,0 +1,11 @@ +(Module["preRun"] = Module["preRun"] || []).push(function () { + addRunDependency('syncfs') + + FS.mkdir('/fastnoise2') + FS.mount(IDBFS, {}, '/fastnoise2') + FS.syncfs(true, function (err) { + if (err) throw err + removeRunDependency('syncfs') + console.log("FS Synced") + }) +}); \ No newline at end of file diff --git a/tools/emscripten_shell.html b/tools/emscripten_shell.html new file mode 100644 index 00000000..14282b11 --- /dev/null +++ b/tools/emscripten_shell.html @@ -0,0 +1,76 @@ + + + + + + + + + + FastNoise 2 Node Editor + + + + + + + + + + + {{{ SCRIPT }}} + + + +