diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-05-27 12:06:29 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-05-27 12:06:29 +0300 |
commit | 9a74b603670cc3fab14d9fcd7be7b3c17731a8ee (patch) | |
tree | 0611021c1450e586308d58223353793dcc137afe | |
parent | 474971f3d84e5eacde7e92fc86ef4e10a5e0786c (diff) | |
parent | bc3727a94374d9c56745c943a1e6574627a88510 (diff) |
Merge branch 'master' into blender2.8
69 files changed, 1862 insertions, 373 deletions
diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index 7e978a71ad4..606e4e59571 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -119,6 +119,8 @@ set(CMAKE_INSTALL_OPENMP_LIBRARIES ${WITH_OPENMP}) set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION .) include(InstallRequiredSystemLibraries) +remove_cc_flag("/MDd" "/MD") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /nologo /J /Gd /MP /EHsc") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /nologo /J /Gd /MP") diff --git a/build_files/windows/autodetect_msvc.cmd b/build_files/windows/autodetect_msvc.cmd new file mode 100644 index 00000000000..6fce3829e7b --- /dev/null +++ b/build_files/windows/autodetect_msvc.cmd @@ -0,0 +1,17 @@ +echo No explicit msvc version requested, autodetecting version. + +call "%~dp0\detect_msvc2013.cmd" +if %ERRORLEVEL% EQU 0 goto DetectionComplete + +call "%~dp0\detect_msvc2015.cmd" +if %ERRORLEVEL% EQU 0 goto DetectionComplete + +call "%~dp0\detect_msvc2017.cmd" +if %ERRORLEVEL% EQU 0 goto DetectionComplete + +echo Compiler Detection failed. Use verbose switch for more information. +exit /b 1 + +:DetectionComplete +echo Compiler Detection successfull, detected VS%BUILD_VS_YEAR% +exit /b 0
\ No newline at end of file diff --git a/build_files/windows/build_msbuild.cmd b/build_files/windows/build_msbuild.cmd new file mode 100644 index 00000000000..6ca5f1b0df8 --- /dev/null +++ b/build_files/windows/build_msbuild.cmd @@ -0,0 +1,26 @@ +if "%NOBUILD%"=="1" goto EOF +echo %TIME% > %BUILD_DIR%\buildtime.txt +msbuild ^ + %BUILD_DIR%\Blender.sln ^ + /target:build ^ + /property:Configuration=%BUILD_TYPE% ^ + /maxcpucount:2 ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% ^ + /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log + if errorlevel 1 ( + echo Error during build, see %BUILD_DIR%\Build.log for details + exit /b 1 + ) + +msbuild ^ + %BUILD_DIR%\INSTALL.vcxproj ^ + /property:Configuration=%BUILD_TYPE% ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% + if errorlevel 1 ( + echo Error during install phase + exit /b 1 + ) +echo %TIME% >> %BUILD_DIR%\buildtime.txt +:EOF
\ No newline at end of file diff --git a/build_files/windows/build_ninja.cmd b/build_files/windows/build_ninja.cmd new file mode 100644 index 00000000000..f6b266e206d --- /dev/null +++ b/build_files/windows/build_ninja.cmd @@ -0,0 +1,16 @@ +if "%NOBUILD%"=="1" goto EOF +set HAS_ERROR= +cd %BUILD_DIR% +echo %TIME% > buildtime.txt +ninja install +if errorlevel 1 ( + set HAS_ERROR=1 + ) +echo %TIME% >>buildtime.txt +cd %BLENDER_DIR% + +if "%HAS_ERROR%" == "1" ( + echo Error during build, see %BUILD_DIR%\Build.log for details + exit /b 1 +) +:EOF
\ No newline at end of file diff --git a/build_files/windows/check_libraries.cmd b/build_files/windows/check_libraries.cmd new file mode 100644 index 00000000000..c8aad7c9adb --- /dev/null +++ b/build_files/windows/check_libraries.cmd @@ -0,0 +1,54 @@ +if "%BUILD_VS_YEAR%"=="2013" set BUILD_VS_LIBDIRPOST=vc12 +if "%BUILD_VS_YEAR%"=="2015" set BUILD_VS_LIBDIRPOST=vc14 +if "%BUILD_VS_YEAR%"=="2017" set BUILD_VS_LIBDIRPOST=vc14 + +if "%BUILD_ARCH%"=="x64" ( + set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST% +) else if "%BUILD_ARCH%"=="x86" ( + set BUILD_VS_SVNDIR=windows_%BUILD_VS_LIBDIRPOST% +) +set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%" + +if NOT "%verbose%" == "" ( + echo Library Directory = "%BUILD_VS_LIBDIR%" +) +if NOT EXIST %BUILD_VS_LIBDIR% ( + rem libs not found, but svn is on the system + echo + if not "%SVN%"=="" ( + echo. + echo The required external libraries in %BUILD_VS_LIBDIR% are missing + echo. + set /p GetLibs= "Would you like to download them? (y/n)" + if /I "!GetLibs!"=="Y" ( + echo. + echo Downloading %BUILD_VS_SVNDIR% libraries, please wait. + echo. +:RETRY + "%SVN%" checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/%BUILD_VS_SVNDIR% %BUILD_VS_LIBDIR% + if errorlevel 1 ( + set /p LibRetry= "Error during donwload, retry? y/n" + if /I "!LibRetry!"=="Y" ( + cd %BUILD_VS_LIBDIR% + "%SVN%" cleanup + cd %BLENDER_DIR% + goto RETRY + ) + echo. + echo Error: Download of external libraries failed. + echo This is needed for building, please manually run 'svn cleanup' and 'svn update' in + echo %BUILD_VS_LIBDIR% , until this is resolved you CANNOT make a successfull blender build + echo. + exit /b 1 + ) + ) + ) +) + +if NOT EXIST %BUILD_VS_LIBDIR% ( + echo. + echo Error: Required libraries not found at "%BUILD_VS_LIBDIR%" + echo This is needed for building, aborting! + echo. + exit /b 1 +)
\ No newline at end of file diff --git a/build_files/windows/check_spaces_in_path.cmd b/build_files/windows/check_spaces_in_path.cmd new file mode 100644 index 00000000000..2e9300ae6d5 --- /dev/null +++ b/build_files/windows/check_spaces_in_path.cmd @@ -0,0 +1,6 @@ +set BLENDER_DIR_NOSPACES=%BLENDER_DIR: =% + +if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( + echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... + exit /b 1 +)
\ No newline at end of file diff --git a/build_files/windows/check_submodules.cmd b/build_files/windows/check_submodules.cmd new file mode 100644 index 00000000000..c0c64148dd7 --- /dev/null +++ b/build_files/windows/check_submodules.cmd @@ -0,0 +1,20 @@ +if NOT exist "%BLENDER_DIR%/source/tools" ( + echo Checking out sub-modules + if not "%GIT%" == "" ( + "%GIT%" submodule update --init --recursive --progress + if errorlevel 1 goto FAIL + "%GIT%" submodule foreach git checkout master + if errorlevel 1 goto FAIL + "%GIT%" submodule foreach git pull --rebase origin master + if errorlevel 1 goto FAIL + goto EOF + ) else ( + echo Blender submodules not found, and git not found in path to retrieve them. + goto FAIL + ) +) +goto EOF + +:FAIL +exit /b 1 +:EOF
\ No newline at end of file diff --git a/build_files/windows/configure_msbuild.cmd b/build_files/windows/configure_msbuild.cmd new file mode 100644 index 00000000000..135b7933ab2 --- /dev/null +++ b/build_files/windows/configure_msbuild.cmd @@ -0,0 +1,59 @@ +set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS% + +if "%BUILD_ARCH%"=="x64" ( + set MSBUILD_PLATFORM=x64 +) else if "%BUILD_ARCH%"=="x86" ( + set MSBUILD_PLATFORM=win32 +) + +if NOT EXIST %BUILD_DIR%\nul ( + mkdir %BUILD_DIR% +) + +if "%MUST_CLEAN%"=="1" ( + echo Cleaning %BUILD_DIR% + msbuild ^ + %BUILD_DIR%\Blender.sln ^ + /target:clean ^ + /property:Configuration=%BUILD_TYPE% ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% +) + +if NOT EXIST %BUILD_DIR%\Blender.sln set MUST_CONFIGURE=1 +if "%NOBUILD%"=="1" set MUST_CONFIGURE=1 + +if "%MUST_CONFIGURE%"=="1" ( + + if NOT "%verbose%" == "" ( + echo %CMAKE% %BUILD_CMAKE_ARGS% -H%BLENDER_DIR% -B%BUILD_DIR% + ) + + cmake ^ + %BUILD_CMAKE_ARGS% ^ + -H%BLENDER_DIR% ^ + -B%BUILD_DIR% + + if %ERRORLEVEL% NEQ 0 ( + echo "Configuration Failed" + exit /b 1 + ) +) + +echo call "%VCVARS%" %BUILD_ARCH% > %BUILD_DIR%\rebuild.cmd +echo "%CMAKE%" . >> %BUILD_DIR%\rebuild.cmd +echo echo %%TIME%% ^> buildtime.txt >> %BUILD_DIR%\rebuild.cmd +echo msbuild ^ + %BUILD_DIR%\Blender.sln ^ + /target:build ^ + /property:Configuration=%BUILD_TYPE% ^ + /maxcpucount:2 ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% ^ + /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log >> %BUILD_DIR%\rebuild.cmd +echo msbuild ^ + %BUILD_DIR%\INSTALL.vcxproj ^ + /property:Configuration=%BUILD_TYPE% ^ + /verbosity:minimal ^ + /p:platform=%MSBUILD_PLATFORM% >> %BUILD_DIR%\rebuild.cmd +echo echo %%TIME%% ^>^> buildtime.txt >> %BUILD_DIR%\rebuild.cmd
\ No newline at end of file diff --git a/build_files/windows/configure_ninja.cmd b/build_files/windows/configure_ninja.cmd new file mode 100644 index 00000000000..13797543bcc --- /dev/null +++ b/build_files/windows/configure_ninja.cmd @@ -0,0 +1,35 @@ +set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Ninja" %TESTS_CMAKE_ARGS% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% +:DetectionComplete +if NOT "%verbose%" == "" ( + echo BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% +) + +if NOT EXIST %BUILD_DIR%\nul ( + mkdir %BUILD_DIR% +) + +if "%MUST_CLEAN%"=="1" ( + echo Cleaning %BUILD_DIR% + cd %BUILD_DIR% + %CMAKE% cmake --build . --config Clean +) + +if NOT EXIST %BUILD_DIR%\Blender.sln set MUST_CONFIGURE=1 +if "%NOBUILD%"=="1" set MUST_CONFIGURE=1 + +if "%MUST_CONFIGURE%"=="1" ( + cmake ^ + %BUILD_CMAKE_ARGS% ^ + -H%BLENDER_DIR% ^ + -B%BUILD_DIR% + + if %ERRORLEVEL% NEQ 0 ( + echo "Configuration Failed" + exit /b 1 + ) +) + +echo call "%VCVARS%" %BUILD_ARCH% > %BUILD_DIR%\rebuild.cmd +echo echo %%TIME%% ^> buildtime.txt >> %BUILD_DIR%\rebuild.cmd +echo ninja install >> %BUILD_DIR%\rebuild.cmd +echo echo %%TIME%% ^>^> buildtime.txt >> %BUILD_DIR%\rebuild.cmd
\ No newline at end of file diff --git a/build_files/windows/detect_architecture.cmd b/build_files/windows/detect_architecture.cmd new file mode 100644 index 00000000000..cd211668b7f --- /dev/null +++ b/build_files/windows/detect_architecture.cmd @@ -0,0 +1,16 @@ +if "%BUILD_ARCH%"=="" ( + if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( + set WINDOWS_ARCH= Win64 + set BUILD_ARCH=x64 + ) else if "%PROCESSOR_ARCHITEW6432%" == "AMD64" ( + set WINDOWS_ARCH= Win64 + set BUILD_ARCH=x64 + ) else ( + set WINDOWS_ARCH= + set BUILD_ARCH=x86 + ) +) else if "%BUILD_ARCH%"=="x64" ( + set WINDOWS_ARCH= Win64 +) else if "%BUILD_ARCH%"=="x86" ( + set WINDOWS_ARCH= +) diff --git a/build_files/windows/detect_msvc2013.cmd b/build_files/windows/detect_msvc2013.cmd new file mode 100644 index 00000000000..5688d31c4b6 --- /dev/null +++ b/build_files/windows/detect_msvc2013.cmd @@ -0,0 +1,3 @@ +set BUILD_VS_VER=12 +set BUILD_VS_YEAR=2013 +call "%~dp0\detect_msvc_classic.cmd"
\ No newline at end of file diff --git a/build_files/windows/detect_msvc2015.cmd b/build_files/windows/detect_msvc2015.cmd new file mode 100644 index 00000000000..0818d1dfffc --- /dev/null +++ b/build_files/windows/detect_msvc2015.cmd @@ -0,0 +1,3 @@ +set BUILD_VS_VER=14 +set BUILD_VS_YEAR=2015 +call "%~dp0\detect_msvc_classic.cmd"
\ No newline at end of file diff --git a/build_files/windows/detect_msvc2017.cmd b/build_files/windows/detect_msvc2017.cmd new file mode 100644 index 00000000000..6a82adb5a4d --- /dev/null +++ b/build_files/windows/detect_msvc2017.cmd @@ -0,0 +1,70 @@ +if NOT "%verbose%" == "" ( + echo Detecting msvc 2017 +) +set BUILD_VS_VER=15 +set ProgramFilesX86=%ProgramFiles(x86)% +if not exist "%ProgramFilesX86%" set ProgramFilesX86=%ProgramFiles% + +set vs_where=%ProgramFilesX86%\Microsoft Visual Studio\Installer\vswhere.exe +if not exist "%vs_where%" ( + if NOT "%verbose%" == "" ( + echo Visual Studio 2017 ^(15.2 or newer^) is not detected + goto FAIL + ) +) +for /f "usebackq tokens=1* delims=: " %%i in (`"%vs_where%" -latest %VSWHERE_ARGS% -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64`) do ( + if /i "%%i"=="installationPath" set VS_InstallDir=%%j +) + +if "%VS_InstallDir%"=="" ( + if NOT "%verbose%" == "" ( + echo Visual Studio is detected but the "Desktop development with C++" workload has not been instlled + goto FAIL + ) +) + +set VCVARS=%VS_InstallDir%\VC\Auxiliary\Build\vcvarsall.bat +if exist "%VCVARS%" ( + call "%VCVARS%" %BUILD_ARCH% +) else ( + if NOT "%verbose%" == "" ( + echo "%VCVARS%" not found + ) + goto FAIL +) + +rem try msbuild +msbuild /version > NUL +if errorlevel 1 ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% msbuild not found + ) + goto FAIL +) + +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% msbuild found +) + +REM try the c++ compiler +cl 2> NUL 1>&2 +if errorlevel 1 ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% C/C++ Compiler not found + ) + goto FAIL +) + +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% C/C++ Compiler found +) + +if NOT "%verbose%" == "" ( + echo Visual Studio 2017 is detected successfully +) +goto EOF + +:FAIL +exit /b 1 + +:EOF diff --git a/build_files/windows/detect_msvc_classic.cmd b/build_files/windows/detect_msvc_classic.cmd new file mode 100644 index 00000000000..61bfcf92ddf --- /dev/null +++ b/build_files/windows/detect_msvc_classic.cmd @@ -0,0 +1,69 @@ +if NOT "%verbose%" == "" ( + echo Detecting msvc %BUILD_VS_YEAR% +) +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v ProductDir 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% on Win64 detected at "%MSVC_VC_DIR%" + ) + goto msvc_detect_finally +) + +REM Check 32 bits +set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC" +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v ProductDir 2^>nul`) DO set MSVC_VC_DIR=%%C +if DEFINED MSVC_VC_DIR ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% on Win32 detected at "%MSVC_VC_DIR%" + ) + goto msvc_detect_finally +) +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% not found. +) +goto FAIL +:msvc_detect_finally +set VCVARS=%MSVC_VC_DIR%\vcvarsall.bat +if not exist "%VCVARS%" ( + echo "%VCVARS%" not found. + goto FAIL +) + +call "%vcvars%" %BUILD_ARCH% + +rem try msbuild +msbuild /version > NUL +if errorlevel 1 ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% msbuild not found + ) + goto FAIL +) + +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% msbuild found +) + +REM try the c++ compiler +cl 2> NUL 1>&2 +if errorlevel 1 ( + if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% C/C++ Compiler not found + ) + goto FAIL +) + +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% C/C++ Compiler found +) +goto DetectionComplete + +:FAIL +exit /b 1 + +:DetectionComplete +if NOT "%verbose%" == "" ( + echo Visual Studio %BUILD_VS_YEAR% Detected successfuly +) +exit /b 0 diff --git a/build_files/windows/find_dependencies.cmd b/build_files/windows/find_dependencies.cmd new file mode 100644 index 00000000000..219e9801831 --- /dev/null +++ b/build_files/windows/find_dependencies.cmd @@ -0,0 +1,13 @@ +REM find all dependencies and set the corresponding environement variables. +for %%X in (svn.exe) do (set SVN=%%~$PATH:X) +for %%X in (cmake.exe) do (set CMAKE=%%~$PATH:X) +for %%X in (git.exe) do (set GIT=%%~$PATH:X) +if NOT "%verbose%" == "" ( + echo svn : %SVN% + echo cmake : %CMAKE% + echo git : %GIT% +) +if "%CMAKE%" == "" ( + echo Cmake not found in path, required for building, exiting... + exit /b 1 +)
\ No newline at end of file diff --git a/build_files/windows/parse_arguments.cmd b/build_files/windows/parse_arguments.cmd new file mode 100644 index 00000000000..5a82bf3cf04 --- /dev/null +++ b/build_files/windows/parse_arguments.cmd @@ -0,0 +1,78 @@ +set BUILD_DIR=%BLENDER_DIR%..\build_windows +set BUILD_TYPE=Release +:argv_loop +if NOT "%1" == "" ( + + REM Help Message + if "%1" == "help" ( + set SHOW_HELP=1 + goto EOF + ) + REM Build Types + if "%1" == "debug" ( + set BUILD_TYPE=Debug + REM Build Configurations + ) else if "%1" == "noge" ( + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_GAMEENGINE=OFF -DWITH_PLAYER=OFF + set BUILD_NGE=_noge + ) else if "%1" == "builddir" ( + set BUILD_DIR_OVERRRIDE="%BLENDER_DIR%..\%2" + shift /1 + ) else if "%1" == "with_tests" ( + set TESTS_CMAKE_ARGS=-DWITH_GTESTS=On + ) else if "%1" == "full" ( + set TARGET=Full + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ + -C"%BLENDER_DIR%\build_files\cmake\config\blender_full.cmake" + ) else if "%1" == "lite" ( + set TARGET=Lite + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -C"%BLENDER_DIR%\build_files\cmake\config\blender_lite.cmake" + ) else if "%1" == "cycles" ( + set TARGET=Cycles + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -C"%BLENDER_DIR%\build_files\cmake\config\cycles_standalone.cmake" + ) else if "%1" == "headless" ( + set TARGET=Headless + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -C"%BLENDER_DIR%\build_files\cmake\config\blender_headless.cmake" + ) else if "%1" == "bpy" ( + set TARGET=Bpy + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -C"%BLENDER_DIR%\build_files\cmake\config\bpy_module.cmake" + ) else if "%1" == "release" ( + set TARGET=Release + ) else if "%1" == "x86" ( + set BUILD_ARCH=x86 + ) else if "%1" == "x64" ( + set BUILD_ARCH=x64 + ) else if "%1" == "2017" ( + set BUILD_VS_YEAR=2017 + ) else if "%1" == "2017pre" ( + set BUILD_VS_YEAR=2017 + set VSWHERE_ARGS=-prerelease + ) else if "%1" == "2015" ( + set BUILD_VS_YEAR=2015 + ) else if "%1" == "2013" ( + set BUILD_VS_YEAR=2013 + ) else if "%1" == "packagename" ( + set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2" + shift /1 + ) else if "%1" == "nobuild" ( + set NOBUILD=1 + ) else if "%1" == "showhash" ( + SET BUILD_SHOW_HASHES=1 + REM Non-Build Commands + ) else if "%1" == "update" ( + SET BUILD_UPDATE=1 + ) else if "%1" == "ninja" ( + SET BUILD_WITH_NINJA=1 + ) else if "%1" == "clean" ( + set MUST_CLEAN=1 + ) else if "%1" == "verbose" ( + set VERBOSE=1 + ) else ( + echo Command "%1" unknown, aborting! + exit /b 1 + ) + shift /1 + goto argv_loop +) +:EOF +exit /b 0
\ No newline at end of file diff --git a/build_files/windows/reset_variables.cmd b/build_files/windows/reset_variables.cmd new file mode 100644 index 00000000000..34af3ff9389 --- /dev/null +++ b/build_files/windows/reset_variables.cmd @@ -0,0 +1,23 @@ +rem reset all variables so they do not get accidentally get carried over from previous builds +set BUILD_DIR_OVERRRIDE= +set BUILD_CMAKE_ARGS= +set BUILD_ARCH= +set BUILD_VS_VER= +set BUILD_VS_YEAR= +set BUILD_VS_LIBDIRPOST= +set BUILD_VS_LIBDIR= +set BUILD_VS_SVNDIR= +set BUILD_NGE= +set KEY_NAME= +set MSBUILD_PLATFORM= +set MUST_CLEAN= +set NOBUILD= +set TARGET= +set VERBOSE= +set WINDOWS_ARCH= +set TESTS_CMAKE_ARGS= +set VSWHERE_ARGS= +set BUILD_UPDATE= +set BUILD_SHOW_HASHES= +set SHOW_HELP= +set BUILD_WITH_NINJA= diff --git a/build_files/windows/set_build_dir.cmd b/build_files/windows/set_build_dir.cmd new file mode 100644 index 00000000000..8842a52eb5b --- /dev/null +++ b/build_files/windows/set_build_dir.cmd @@ -0,0 +1,4 @@ +set BUILD_DIR=%BUILD_DIR%_%TARGET%%BUILD_NGE%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE% +if NOT "%BUILD_DIR_OVERRRIDE%"=="" ( + set BUILD_DIR=%BUILD_DIR_OVERRRIDE% +)
\ No newline at end of file diff --git a/build_files/windows/show_hashes.cmd b/build_files/windows/show_hashes.cmd new file mode 100644 index 00000000000..ff036733946 --- /dev/null +++ b/build_files/windows/show_hashes.cmd @@ -0,0 +1,12 @@ +if "%GIT%" == "" ( + echo Git not found, cannot show hashes. + goto EOF +) +cd "%BLENDER_DIR%" +for /f "delims=" %%i in ('%GIT% rev-parse HEAD') do echo Branch_hash=%%i +cd "%BLENDER_DIR%/release/datafiles/locale" +for /f "delims=" %%i in ('%GIT% rev-parse HEAD') do echo Locale_hash=%%i +cd "%BLENDER_DIR%/release/scripts/addons" +for /f "delims=" %%i in ('%GIT% rev-parse HEAD') do echo Addons_Hash=%%i +cd "%BLENDER_DIR%" +:EOF
\ No newline at end of file diff --git a/build_files/windows/show_help.cmd b/build_files/windows/show_help.cmd new file mode 100644 index 00000000000..0524e8a84fc --- /dev/null +++ b/build_files/windows/show_help.cmd @@ -0,0 +1,29 @@ +echo. +echo Convenience targets +echo - release ^(identical to the official blender.org builds^) +echo - full ^(same as release minus the cuda kernels^) +echo - lite +echo - headless +echo - cycles +echo - bpy +echo. +echo Utilities ^(not associated with building^) +echo - clean ^(Target must be set^) +echo - update +echo - nobuild ^(only generate project files^) +echo - showhash ^(Show git hashes of source tree^) +echo. +echo Configuration options +echo - verbose ^(enable diagnostic output during configuration^) +echo - with_tests ^(enable building unit tests^) +echo - noge ^(disable building game enginge and player^) +echo - debug ^(Build an unoptimized debuggable build^) +echo - packagename [newname] ^(override default cpack package name^) +echo - buildir [newdir] ^(override default build folder^) +echo - x86 ^(override host auto-detect and build 32 bit code^) +echo - x64 ^(override host auto-detect and build 64 bit code^) +echo - 2013 ^(build with visual studio 2013^) +echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] +echo - 2017 ^(build with visual studio 2017^) [EXPERIMENTAL] +echo - 2017pre ^(build with visual studio 2017 pre-release^) [EXPERIMENTAL] +echo. diff --git a/build_files/windows/update_sources.cmd b/build_files/windows/update_sources.cmd new file mode 100644 index 00000000000..22d93fabb95 --- /dev/null +++ b/build_files/windows/update_sources.cmd @@ -0,0 +1,16 @@ +if "%SVN%" == "" ( + echo svn not found, cannot update libraries + goto UPDATE_GIT +) +"%SVN%" up "%BLENDER_DIR%/../lib/*" + +:UPDATE_GIT + +if "%GIT%" == "" ( + echo Git not found, cannot update code + goto EOF +) +"%GIT%" pull --rebase +"%GIT%" submodule foreach git pull --rebase origin master + +:EOF
\ No newline at end of file diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index cc2a6824190..15d633b5c9a 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -811,6 +811,19 @@ static ShaderNode *add_node(Scene *scene, get_tex_mapping(&sky->tex_mapping, b_texture_mapping); node = sky; } + else if(b_node.is_a(&RNA_ShaderNodeTexIES)) { + BL::ShaderNodeTexIES b_ies_node(b_node); + IESLightNode *ies = new IESLightNode(); + switch(b_ies_node.mode()) { + case BL::ShaderNodeTexIES::mode_EXTERNAL: + ies->filename = blender_absolute_path(b_data, b_ntree, b_ies_node.filepath()); + break; + case BL::ShaderNodeTexIES::mode_INTERNAL: + ies->ies = get_text_datablock_content(b_ies_node.ies().ptr); + break; + } + node = ies; + } else if(b_node.is_a(&RNA_ShaderNodeNormalMap)) { BL::ShaderNodeNormalMap b_normal_map_node(b_node); NormalMapNode *nmap = new NormalMapNode(); diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index a8379914b83..983988f4e36 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -468,6 +468,21 @@ static inline string blender_absolute_path(BL::BlendData& b_data, return path; } +static inline string get_text_datablock_content(const PointerRNA&& ptr) +{ + if(ptr.data == NULL) { + return ""; + } + + string content; + BL::Text::lines_iterator iter; + for(iter.begin(ptr); iter; ++iter) { + content += iter->body() + "\n"; + } + + return content; +} + /* Texture Space */ static inline void mesh_texture_space(BL::Mesh& b_mesh, diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 7d46e31ce24..15d34a79bb8 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -73,12 +73,13 @@ struct SocketType INTERNAL = (1 << 2) | (1 << 3), LINK_TEXTURE_GENERATED = (1 << 4), - LINK_TEXTURE_UV = (1 << 5), - LINK_INCOMING = (1 << 6), - LINK_NORMAL = (1 << 7), - LINK_POSITION = (1 << 8), - LINK_TANGENT = (1 << 9), - DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) + LINK_TEXTURE_NORMAL = (1 << 5), + LINK_TEXTURE_UV = (1 << 6), + LINK_INCOMING = (1 << 7), + LINK_NORMAL = (1 << 8), + LINK_POSITION = (1 << 9), + LINK_TANGENT = (1 << 10), + DEFAULT_LINK_MASK = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9) | (1 << 10) }; ustring name; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 9b7f4e00084..457602ae4e7 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -178,6 +178,7 @@ set(SRC_SVM_HEADERS svm/svm_geometry.h svm/svm_gradient.h svm/svm_hsv.h + svm/svm_ies.h svm/svm_image.h svm/svm_invert.h svm/svm_light_path.h diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index cd879e27e72..b1be0b2155a 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -224,7 +224,7 @@ float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res); /* importance-sampled V direction */ - float dv = (randv - cdf_v.y) / (cdf_next_v.y - cdf_v.y); + float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv); float v = (index_v + dv) / res; /* this is basically std::lower_bound as used by pbrt */ @@ -250,7 +250,7 @@ float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res); /* importance-sampled U direction */ - float du = (randu - cdf_u.y) / (cdf_next_u.y - cdf_u.y); + float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu); float u = (index_u + du) / res; /* compute pdf */ diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 9047b93a0b2..a7b8c492ee9 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -81,5 +81,8 @@ KERNEL_TEX(uint, __sobol_directions) /* image textures */ KERNEL_TEX(TextureInfo, __texture_info) +/* ies lights */ +KERNEL_TEX(float, __ies) + #undef KERNEL_TEX diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 0c5e5e30e47..32d86b7192a 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -956,9 +956,15 @@ bool OSLRenderServices::texture(ustring filename, status = true; } } + else if(filename[1] == 'l') { + /* IES light. */ + int slot = atoi(filename.c_str() + 2); + result[0] = kernel_ies_interp(kg, slot, s, t); + status = true; + } else { /* Packed texture. */ - int slot = atoi(filename.c_str() + 1); + int slot = atoi(filename.c_str() + 2); float4 rgba = kernel_tex_image_interp(kg, slot, s, 1.0f - t); result[0] = rgba[0]; diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 6ec651a96d8..b28d017c1c2 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -39,6 +39,7 @@ set(SRC_OSL node_principled_volume.osl node_holdout.osl node_hsv.osl + node_ies_light.osl node_image_texture.osl node_invert.osl node_layer_weight.osl diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl new file mode 100644 index 00000000000..a0954e3a444 --- /dev/null +++ b/intern/cycles/kernel/shaders/node_ies_light.osl @@ -0,0 +1,42 @@ +/* + * Copyright 2011-2015 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "stdosl.h" +#include "node_texture.h" + +/* IES Light */ + +shader node_ies_light( + int use_mapping = 0, + matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), + int slot = 0, + float Strength = 1.0, + point Vector = I, + output float Fac = 0.0) +{ + point p = Vector; + + if (use_mapping) { + p = transform(mapping, p); + } + + p = normalize(p); + + float v_angle = acos(-p[2]); + float h_angle = atan2(p[0], p[1]) + M_PI; + + Fac = Strength * texture(format("@l%d", slot), h_angle, v_angle); +} diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 39cd5da7b12..bfa146f2d93 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -157,6 +157,7 @@ CCL_NAMESPACE_END #include "kernel/svm/svm_camera.h" #include "kernel/svm/svm_geometry.h" #include "kernel/svm/svm_hsv.h" +#include "kernel/svm/svm_ies.h" #include "kernel/svm/svm_image.h" #include "kernel/svm/svm_gamma.h" #include "kernel/svm/svm_brightness.h" @@ -421,6 +422,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a case NODE_LIGHT_FALLOFF: svm_node_light_falloff(sd, stack, node); break; + case NODE_IES: + svm_node_ies(kg, sd, stack, node, &offset); + break; # endif /* __EXTRA_NODES__ */ #endif /* NODES_GROUP(NODE_GROUP_LEVEL_2) */ diff --git a/intern/cycles/kernel/svm/svm_ies.h b/intern/cycles/kernel/svm/svm_ies.h new file mode 100644 index 00000000000..6130c3348b0 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_ies.h @@ -0,0 +1,110 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* IES Light */ + +ccl_device_inline float interpolate_ies_vertical(KernelGlobals *kg, int ofs, int v, int v_num, float v_frac, int h) +{ + /* Since lookups are performed in spherical coordinates, clamping the coordinates at the low end of v + * (corresponding to the north pole) would result in artifacts. + * The proper way of dealing with this would be to lookup the corresponding value on the other side of the pole, + * but since the horizontal coordinates might be nonuniform, this would require yet another interpolation. + * Therefore, the assumtion is made that the light is going to be symmetrical, which means that we can just take + * the corresponding value at the current horizontal coordinate. */ + +#define IES_LOOKUP(v) kernel_tex_fetch(__ies, ofs+h*v_num+(v)) + /* If v is zero, assume symmetry and read at v=1 instead of v=-1. */ + float a = IES_LOOKUP((v == 0)? 1 : v-1); + float b = IES_LOOKUP(v); + float c = IES_LOOKUP(v+1); + float d = IES_LOOKUP(min(v+2, v_num-1)); +#undef IES_LOOKUP + + return cubic_interp(a, b, c, d, v_frac); +} + +ccl_device_inline float kernel_ies_interp(KernelGlobals *kg, int slot, float h_angle, float v_angle) +{ + /* Find offset of the IES data in the table. */ + int ofs = __float_as_int(kernel_tex_fetch(__ies, slot)); + if(ofs == -1) { + return 100.0f; + } + + int h_num = __float_as_int(kernel_tex_fetch(__ies, ofs++)); + int v_num = __float_as_int(kernel_tex_fetch(__ies, ofs++)); + +#define IES_LOOKUP_ANGLE_H(h) kernel_tex_fetch(__ies, ofs+(h)) +#define IES_LOOKUP_ANGLE_V(v) kernel_tex_fetch(__ies, ofs+h_num+(v)) + + /* Check whether the angle is within the bounds of the IES texture. */ + if(v_angle >= IES_LOOKUP_ANGLE_V(v_num-1)) { + return 0.0f; + } + kernel_assert(v_angle >= IES_LOOKUP_ANGLE_V(0)); + kernel_assert(h_angle >= IES_LOOKUP_ANGLE_H(0)); + kernel_assert(h_angle <= IES_LOOKUP_ANGLE_H(h_num-1)); + + /* Lookup the angles to find the table position. */ + int h_i, v_i; + /* TODO(lukas): Consider using bisection. Probably not worth it for the vast majority of IES files. */ + for(h_i = 0; IES_LOOKUP_ANGLE_H(h_i+1) < h_angle; h_i++); + for(v_i = 0; IES_LOOKUP_ANGLE_V(v_i+1) < v_angle; v_i++); + + float h_frac = inverse_lerp(IES_LOOKUP_ANGLE_H(h_i), IES_LOOKUP_ANGLE_H(h_i+1), h_angle); + float v_frac = inverse_lerp(IES_LOOKUP_ANGLE_V(v_i), IES_LOOKUP_ANGLE_V(v_i+1), v_angle); + +#undef IES_LOOKUP_ANGLE_H +#undef IES_LOOKUP_ANGLE_V + + /* Skip forward to the actual intensity data. */ + ofs += h_num+v_num; + + /* Perform cubic interpolation along the horizontal coordinate to get the intensity value. + * If h_i is zero, just wrap around since the horizontal angles always go over the full circle. + * However, the last entry (360°) equals the first one, so we need to wrap around to the one before that. */ + float a = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, (h_i == 0)? h_num-2 : h_i-1); + float b = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i); + float c = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, h_i+1); + /* Same logic here, wrap around to the second element if necessary. */ + float d = interpolate_ies_vertical(kg, ofs, v_i, v_num, v_frac, (h_i+2 == h_num)? 1 : h_i+2); + + /* Cubic interpolation can result in negative values, so get rid of them. */ + return max(cubic_interp(a, b, c, d, h_frac), 0.0f); +} + +ccl_device void svm_node_ies(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +{ + uint vector_offset, strength_offset, fac_offset, dummy, slot = node.z; + decode_node_uchar4(node.y, &strength_offset, &vector_offset, &fac_offset, &dummy); + + float3 vector = stack_load_float3(stack, vector_offset); + float strength = stack_load_float_default(stack, strength_offset, node.w); + + vector = normalize(vector); + float v_angle = safe_acosf(-vector.z); + float h_angle = atan2f(vector.x, vector.y) + M_PI_F; + + float fac = strength * kernel_ies_interp(kg, slot, h_angle, v_angle); + + if(stack_valid(fac_offset)) { + stack_store_float(stack, fac_offset, fac); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index dc62e25b340..ac24d23ecd2 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -136,6 +136,7 @@ typedef enum ShaderNodeType { NODE_DISPLACEMENT, NODE_VECTOR_DISPLACEMENT, NODE_PRINCIPLED_VOLUME, + NODE_IES, } ShaderNodeType; typedef enum NodeAttributeType { diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 096de878e51..59e1a12c3a1 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -774,6 +774,12 @@ void ShaderGraph::default_inputs(bool do_osl) connect(texco->output("Generated"), input); } + if(input->flags() & SocketType::LINK_TEXTURE_NORMAL) { + if(!texco) + texco = new TextureCoordinateNode(); + + connect(texco->output("Normal"), input); + } else if(input->flags() & SocketType::LINK_TEXTURE_UV) { if(!texco) texco = new TextureCoordinateNode(); diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 01a8b50cb21..91f9b4e3bec 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -25,6 +25,8 @@ #include "render/shader.h" #include "util/util_foreach.h" +#include "util/util_hash.h" +#include "util/util_path.h" #include "util/util_progress.h" #include "util/util_logging.h" @@ -176,6 +178,9 @@ LightManager::LightManager() LightManager::~LightManager() { + foreach(IESSlot *slot, ies_slots) { + delete slot; + } } bool LightManager::has_background_light(Scene *scene) @@ -865,6 +870,9 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce device_update_background(device, dscene, scene, progress); if(progress.get_cancel()) return; + device_update_ies(dscene); + if(progress.get_cancel()) return; + if(use_light_visibility != scene->film->use_light_visibility) { scene->film->use_light_visibility = use_light_visibility; scene->film->tag_update(scene); @@ -879,6 +887,7 @@ void LightManager::device_free(Device *, DeviceScene *dscene) dscene->lights.free(); dscene->light_background_marginal_cdf.free(); dscene->light_background_conditional_cdf.free(); + dscene->ies_lights.free(); } void LightManager::tag_update(Scene * /*scene*/) @@ -886,5 +895,118 @@ void LightManager::tag_update(Scene * /*scene*/) need_update = true; } +int LightManager::add_ies_from_file(ustring filename) +{ + string content; + /* If the file can't be opened, call with an empty string */ + path_read_text(filename.c_str(), content); + + return add_ies(ustring(content)); +} + +int LightManager::add_ies(ustring content) +{ + uint hash = hash_string(content.c_str()); + + thread_scoped_lock ies_lock(ies_mutex); + + /* Check whether this IES already has a slot. */ + size_t slot; + for(slot = 0; slot < ies_slots.size(); slot++) { + if(ies_slots[slot]->hash == hash) { + ies_slots[slot]->users++; + return slot; + } + } + + /* Try to find an empty slot for the new IES. */ + for(slot = 0; slot < ies_slots.size(); slot++) { + if(ies_slots[slot]->users == 0 && ies_slots[slot]->hash == 0) { + break; + } + } + + /* If there's no free slot, add one. */ + if(slot == ies_slots.size()) { + ies_slots.push_back(new IESSlot()); + } + + ies_slots[slot]->ies.load(content); + ies_slots[slot]->users = 1; + ies_slots[slot]->hash = hash; + + need_update = true; + + return slot; +} + +void LightManager::remove_ies(int slot) +{ + thread_scoped_lock ies_lock(ies_mutex); + + if(slot < 0 || slot >= ies_slots.size()) { + assert(false); + return; + } + + assert(ies_slots[slot]->users > 0); + ies_slots[slot]->users--; + + /* If the slot has no more users, update the device to remove it. */ + need_update |= (ies_slots[slot]->users == 0); +} + +void LightManager::device_update_ies(DeviceScene *dscene) +{ + /* Clear empty slots. */ + foreach(IESSlot *slot, ies_slots) { + if(slot->users == 0) { + slot->hash = 0; + slot->ies.clear(); + } + } + + /* Shrink the slot table by removing empty slots at the end. */ + int slot_end; + for(slot_end = ies_slots.size(); slot_end; slot_end--) { + if(ies_slots[slot_end-1]->users > 0) { + /* If the preceding slot has users, we found the new end of the table. */ + break; + } + else { + /* The slot will be past the new end of the table, so free it. */ + delete ies_slots[slot_end-1]; + } + } + ies_slots.resize(slot_end); + + if(ies_slots.size() > 0) { + int packed_size = 0; + foreach(IESSlot *slot, ies_slots) { + packed_size += slot->ies.packed_size(); + } + + /* ies_lights starts with an offset table that contains the offset of every slot, + * or -1 if the slot is invalid. + * Following that table, the packed valid IES lights are stored. */ + float *data = dscene->ies_lights.alloc(ies_slots.size() + packed_size); + + int offset = ies_slots.size(); + for(int i = 0; i < ies_slots.size(); i++) { + int size = ies_slots[i]->ies.packed_size(); + if(size > 0) { + data[i] = __int_as_float(offset); + ies_slots[i]->ies.pack(data + offset); + offset += size; + } + else { + data[i] = __int_as_float(-1); + } + } + + dscene->ies_lights.copy_to_device(); + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index 539a33f4e41..acbbdd15ddf 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -21,6 +21,8 @@ #include "graph/node.h" +#include "util/util_ies.h" +#include "util/util_thread.h" #include "util/util_types.h" #include "util/util_vector.h" @@ -87,6 +89,11 @@ public: LightManager(); ~LightManager(); + /* IES texture management */ + int add_ies(ustring ies); + int add_ies_from_file(ustring filename); + void remove_ies(int slot); + void device_update(Device *device, DeviceScene *dscene, Scene *scene, @@ -116,9 +123,19 @@ protected: DeviceScene *dscene, Scene *scene, Progress& progress); + void device_update_ies(DeviceScene *dscene); /* Check whether light manager can use the object as a light-emissive. */ bool object_usable_as_light(Object *object); + + struct IESSlot { + IESFile ies; + uint hash; + int users; + }; + + vector<IESSlot*> ies_slots; + thread_mutex ies_mutex; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index c468924fa66..3dad4d1a346 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -16,6 +16,7 @@ #include "render/image.h" #include "render/integrator.h" +#include "render/light.h" #include "render/nodes.h" #include "render/scene.h" #include "render/svm.h" @@ -384,10 +385,10 @@ void ImageTextureNode::compile(OSLCompiler& compiler) /* TODO(sergey): It's not so simple to pass custom attribute * to the texture() function in order to make builtin images * support more clear. So we use special file name which is - * "@<slot_number>" and check whether file name matches this + * "@i<slot_number>" and check whether file name matches this * mask in the OSLRenderServices::texture(). */ - compiler.parameter("filename", string_printf("@%d", slot).c_str()); + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); } if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) compiler.parameter("color_space", "linear"); @@ -567,7 +568,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) compiler.parameter(this, "filename"); } else { - compiler.parameter("filename", string_printf("@%d", slot).c_str()); + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); } compiler.parameter(this, "projection"); if(is_linear || color_space != NODE_COLOR_SPACE_COLOR) @@ -954,6 +955,97 @@ void VoronoiTextureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_voronoi_texture"); } +/* IES Light */ + +NODE_DEFINE(IESLightNode) +{ + NodeType* type = NodeType::add("ies_light", create, NodeType::SHADER); + + TEXTURE_MAPPING_DEFINE(IESLightNode); + + SOCKET_STRING(ies, "IES", ustring()); + SOCKET_STRING(filename, "File Name", ustring()); + + SOCKET_IN_FLOAT(strength, "Strength", 1.0f); + SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_NORMAL); + + SOCKET_OUT_FLOAT(fac, "Fac"); + + return type; +} + +IESLightNode::IESLightNode() +: TextureNode(node_type) +{ + light_manager = NULL; + slot = -1; +} + +ShaderNode *IESLightNode::clone() const +{ + IESLightNode *node = new IESLightNode(*this); + + node->light_manager = NULL; + node->slot = -1; + + return node; +} + +IESLightNode::~IESLightNode() +{ + if(light_manager) { + light_manager->remove_ies(slot); + } +} + +void IESLightNode::get_slot() +{ + assert(light_manager); + + if(slot == -1) { + if(ies.empty()) { + slot = light_manager->add_ies_from_file(filename); + } + else { + slot = light_manager->add_ies(ies); + } + } +} + +void IESLightNode::compile(SVMCompiler& compiler) +{ + light_manager = compiler.light_manager; + get_slot(); + + ShaderInput *strength_in = input("Strength"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + + int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + + compiler.add_node(NODE_IES, + compiler.encode_uchar4( + compiler.stack_assign_if_linked(strength_in), + vector_offset, + compiler.stack_assign(fac_out), + 0), + slot, + __float_as_int(strength)); + + tex_mapping.compile_end(compiler, vector_in, vector_offset); +} + +void IESLightNode::compile(OSLCompiler& compiler) +{ + light_manager = compiler.light_manager; + get_slot(); + + tex_mapping.compile(compiler); + + compiler.parameter("slot", slot); + compiler.add(this, "node_ies_light"); +} + /* Musgrave Texture */ NODE_DEFINE(MusgraveTextureNode) @@ -1470,7 +1562,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) } if(slot != -1) { - compiler.parameter("filename", string_printf("@%d", slot).c_str()); + compiler.parameter("filename", string_printf("@i%d", slot).c_str()); } if(space == NODE_TEX_VOXEL_SPACE_WORLD) { compiler.parameter("mapping", tfm); diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 58c3d472cd3..35a7df690c3 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -25,6 +25,7 @@ CCL_NAMESPACE_BEGIN class ImageManager; +class LightManager; class Scene; class Shader; @@ -281,6 +282,27 @@ public: } }; +class IESLightNode : public TextureNode { +public: + SHADER_NODE_NO_CLONE_CLASS(IESLightNode) + + ~IESLightNode(); + ShaderNode *clone() const; + virtual int get_group() { return NODE_GROUP_LEVEL_2; } + + ustring filename; + ustring ies; + + float strength; + float3 vector; + +private: + LightManager *light_manager; + int slot; + + void get_slot(); +}; + class MappingNode : public ShaderNode { public: SHADER_NODE_CLASS(MappingNode) diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index f1a22350060..dde622bff8a 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -99,7 +99,9 @@ void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene * compile shaders alternating */ thread_scoped_lock lock(ss_mutex); - OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager); + OSLCompiler compiler((void*)this, (void*)ss, + scene->image_manager, + scene->light_manager); compiler.background = (shader == scene->default_background); compiler.compile(scene, og, shader); @@ -546,11 +548,14 @@ OSLNode *OSLShaderManager::osl_node(const std::string& filepath, /* Graph Compiler */ -OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_) +OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, + ImageManager *image_manager_, + LightManager *light_manager_) { manager = manager_; shadingsys = shadingsys_; image_manager = image_manager_; + light_manager = light_manager_; current_type = SHADER_TYPE_SURFACE; current_shader = NULL; background = false; diff --git a/intern/cycles/render/osl.h b/intern/cycles/render/osl.h index 95e35dd857b..7a3208c402a 100644 --- a/intern/cycles/render/osl.h +++ b/intern/cycles/render/osl.h @@ -120,7 +120,9 @@ protected: class OSLCompiler { public: - OSLCompiler(void *manager, void *shadingsys, ImageManager *image_manager); + OSLCompiler(void *manager, void *shadingsys, + ImageManager *image_manager, + LightManager *light_manager); void compile(Scene *scene, OSLGlobals *og, Shader *shader); void add(ShaderNode *node, const char *name, bool isfilepath = false); @@ -146,6 +148,7 @@ public: bool background; ImageManager *image_manager; + LightManager *light_manager; private: #ifdef WITH_OSL diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index ba47e3ab6f8..b35cdbd3db5 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -76,7 +76,8 @@ DeviceScene::DeviceScene(Device *device) svm_nodes(device, "__svm_nodes", MEM_TEXTURE), shaders(device, "__shaders", MEM_TEXTURE), lookup_table(device, "__lookup_table", MEM_TEXTURE), - sobol_directions(device, "__sobol_directions", MEM_TEXTURE) + sobol_directions(device, "__sobol_directions", MEM_TEXTURE), + ies_lights(device, "__ies", MEM_TEXTURE) { memset(&data, 0, sizeof(data)); } diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 04bd4735a86..6c67433c9fc 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -119,6 +119,9 @@ public: /* integrator */ device_vector<uint> sobol_directions; + /* ies lights */ + device_vector<float> ies_lights; + KernelData data; DeviceScene(Device *device); diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index c5b4060d5c3..eb8a35a271f 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -58,7 +58,7 @@ void SVMShaderManager::device_update_shader(Scene *scene, svm_nodes.push_back_slow(make_int4(NODE_SHADER_JUMP, 0, 0, 0)); SVMCompiler::Summary summary; - SVMCompiler compiler(scene->shader_manager, scene->image_manager); + SVMCompiler compiler(scene->shader_manager, scene->image_manager, scene->light_manager); compiler.background = (shader == scene->default_background); compiler.compile(scene, shader, svm_nodes, 0, &summary); @@ -154,10 +154,13 @@ void SVMShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *s /* Graph Compiler */ -SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, ImageManager *image_manager_) +SVMCompiler::SVMCompiler(ShaderManager *shader_manager_, + ImageManager *image_manager_, + LightManager *light_manager_) { shader_manager = shader_manager_; image_manager = image_manager_; + light_manager = light_manager_; max_stack_use = 0; current_type = SHADER_TYPE_SURFACE; current_shader = NULL; diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h index 18be0fa9a22..7cf1e4ad791 100644 --- a/intern/cycles/render/svm.h +++ b/intern/cycles/render/svm.h @@ -95,7 +95,9 @@ public: string full_report() const; }; - SVMCompiler(ShaderManager *shader_manager, ImageManager *image_manager); + SVMCompiler(ShaderManager *shader_manager, + ImageManager *image_manager, + LightManager *light_manager); void compile(Scene *scene, Shader *shader, array<int4>& svm_nodes, @@ -125,6 +127,7 @@ public: ImageManager *image_manager; ShaderManager *shader_manager; + LightManager *light_manager; bool background; protected: diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 24043e2231b..3b690860d53 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -11,6 +11,7 @@ set(INC_SYS set(SRC util_aligned_malloc.cpp util_debug.cpp + util_ies.cpp util_logging.cpp util_math_cdf.cpp util_md5.cpp @@ -45,6 +46,7 @@ set(SRC_HEADERS util_guarded_allocator.h util_half.h util_hash.h + util_ies.h util_image.h util_image_impl.h util_list.h diff --git a/intern/cycles/util/util_ies.cpp b/intern/cycles/util/util_ies.cpp new file mode 100644 index 00000000000..4824c886609 --- /dev/null +++ b/intern/cycles/util/util_ies.cpp @@ -0,0 +1,392 @@ +/* + * Copyright 2011-2018 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/util_foreach.h" +#include "util/util_ies.h" +#include "util/util_math.h" +#include "util/util_string.h" + +CCL_NAMESPACE_BEGIN + +bool IESFile::load(ustring ies) +{ + clear(); + if(!parse(ies) || !process()) { + clear(); + return false; + } + return true; +} + +void IESFile::clear() +{ + intensity.clear(); + v_angles.clear(); + h_angles.clear(); +} + +int IESFile::packed_size() +{ + if(v_angles.size() && h_angles.size() > 0) { + return 2 + h_angles.size() + v_angles.size() + h_angles.size()*v_angles.size(); + } + return 0; +} + +void IESFile::pack(float *data) +{ + if(v_angles.size() && h_angles.size()) { + *(data++) = __int_as_float(h_angles.size()); + *(data++) = __int_as_float(v_angles.size()); + + memcpy(data, &h_angles[0], h_angles.size()*sizeof(float)); + data += h_angles.size(); + memcpy(data, &v_angles[0], v_angles.size()*sizeof(float)); + data += v_angles.size(); + + for(int h = 0; h < intensity.size(); h++) { + memcpy(data, &intensity[h][0], v_angles.size()*sizeof(float)); + data += v_angles.size(); + } + } +} + +class IESTextParser { +public: + vector<char> text; + char *data; + + IESTextParser(ustring str) + : text(str.begin(), str.end()) + { + std::replace(text.begin(), text.end(), ',', ' '); + data = strstr(&text[0], "\nTILT="); + } + + bool eof() { + return (data == NULL) || (data[0] == '\0'); + } + + double get_double() { + if(eof()) { + return 0.0; + } + char *old_data = data; + double val = strtod(data, &data); + if(data == old_data) { + data = NULL; + return 0.0; + } + return val; + } + + long get_long() { + if(eof()) { + return 0; + } + char *old_data = data; + long val = strtol(data, &data, 10); + if(data == old_data) { + data = NULL; + return 0; + } + return val; + } +}; + +bool IESFile::parse(ustring ies) +{ + IESTextParser parser(ies); + if(parser.eof()) { + return false; + } + + /* Handle the tilt data block. */ + if(strncmp(parser.data, "\nTILT=INCLUDE", 13) == 0) { + parser.data += 13; + parser.get_double(); /* Lamp to Luminaire geometry */ + int num_tilt = parser.get_long(); /* Amount of tilt angles and factors */ + /* Skip over angles and factors. */ + for(int i = 0; i < 2*num_tilt; i++) { + parser.get_double(); + } + } + else { + /* Skip to next line. */ + parser.data = strstr(parser.data+1, "\n"); + } + + if(parser.eof()) { + return false; + } + parser.data++; + + parser.get_long(); /* Number of lamps */ + parser.get_double(); /* Lumens per lamp */ + double factor = parser.get_double(); /* Candela multiplier */ + int v_angles_num = parser.get_long(); /* Number of vertical angles */ + int h_angles_num = parser.get_long(); /* Number of horizontal angles */ + type = (IESType) parser.get_long(); /* Photometric type */ + + /* TODO(lukas): Test whether the current type B processing can also deal with type A files. + * In theory the only difference should be orientation which we ignore anyways, but with IES you never know... + */ + if(type != TYPE_B && type != TYPE_C) { + return false; + } + + parser.get_long(); /* Unit of the geometry data */ + parser.get_double(); /* Width */ + parser.get_double(); /* Length */ + parser.get_double(); /* Height */ + factor *= parser.get_double(); /* Ballast factor */ + factor *= parser.get_double(); /* Ballast-Lamp Photometric factor */ + parser.get_double(); /* Input Watts */ + + /* Intensity values in IES files are specified in candela (lumen/sr), a photometric quantity. + * Cycles expects radiometric quantities, though, which requires a conversion. + * However, the Luminous efficacy (ratio of lumens per Watt) depends on the spectral distribution + * of the light source since lumens take human perception into account. + * Since this spectral distribution is not known from the IES file, a typical one must be assumed. + * The D65 standard illuminant has a Luminous efficacy of 177.83, which is used here to convert to Watt/sr. + * A more advanced approach would be to add a Blackbody Temperature input to the node and numerically + * integrate the Luminous efficacy from the resulting spectral distribution. + * Also, the Watt/sr value must be multiplied by 4*pi to get the Watt value that Cycles expects + * for lamp strength. Therefore, the conversion here uses 4*pi/177.83 as a Candela to Watt factor. + */ + factor *= 0.0706650768394; + + v_angles.reserve(v_angles_num); + for(int i = 0; i < v_angles_num; i++) { + v_angles.push_back((float) parser.get_double()); + } + + h_angles.reserve(h_angles_num); + for(int i = 0; i < h_angles_num; i++) { + h_angles.push_back((float) parser.get_double()); + } + + intensity.resize(h_angles_num); + for(int i = 0; i < h_angles_num; i++) { + intensity[i].reserve(v_angles_num); + for(int j = 0; j < v_angles_num; j++) { + intensity[i].push_back((float) (factor * parser.get_double())); + } + } + + return !parser.eof(); +} + +bool IESFile::process_type_b() +{ + vector<vector<float> > newintensity; + newintensity.resize(v_angles.size()); + for(int i = 0; i < v_angles.size(); i++) { + newintensity[i].reserve(h_angles.size()); + for(int j = 0; j < h_angles.size(); j++) { + newintensity[i].push_back(intensity[j][i]); + } + } + intensity.swap(newintensity); + h_angles.swap(v_angles); + + float h_first = h_angles[0], h_last = h_angles[h_angles.size()-1]; + if(h_last != 90.0f) { + return false; + } + + if(h_first == 0.0f) { + /* The range in the file corresponds to 90°-180°, we need to mirror that to get the + * full 180° range. */ + vector<float> new_h_angles; + vector<vector<float> > new_intensity; + int hnum = h_angles.size(); + new_h_angles.reserve(2*hnum-1); + new_intensity.reserve(2*hnum-1); + for(int i = hnum-1; i > 0; i--) { + new_h_angles.push_back(90.0f - h_angles[i]); + new_intensity.push_back(intensity[i]); + } + for(int i = 0; i < hnum; i++) { + new_h_angles.push_back(90.0f + h_angles[i]); + new_intensity.push_back(intensity[i]); + } + h_angles.swap(new_h_angles); + intensity.swap(new_intensity); + } + else if(h_first == -90.0f) { + /* We have full 180° coverage, so just shift to match the angle range convention. */ + for(int i = 0; i < h_angles.size(); i++) { + h_angles[i] += 90.0f; + } + } + /* To get correct results with the cubic interpolation in the kernel, the horizontal range + * has to cover all 360°. Therefore, we copy the 0° entry to 360° to ensure full coverage + * and seamless interpolation. */ + h_angles.push_back(360.0f); + intensity.push_back(intensity[0]); + + float v_first = v_angles[0], v_last = v_angles[v_angles.size()-1]; + if(v_last != 90.0f) { + return false; + } + + if(v_first == 0.0f) { + /* The range in the file corresponds to 90°-180°, we need to mirror that to get the + * full 180° range. */ + vector<float> new_v_angles; + int hnum = h_angles.size(); + int vnum = v_angles.size(); + new_v_angles.reserve(2*vnum-1); + for(int i = vnum-1; i > 0; i--) { + new_v_angles.push_back(90.0f - v_angles[i]); + } + for(int i = 0; i < vnum; i++) { + new_v_angles.push_back(90.0f + v_angles[i]); + } + for(int i = 0; i < hnum; i++) { + vector<float> new_intensity; + new_intensity.reserve(2*vnum-1); + for(int j = vnum-2; j >= 0; j--) { + new_intensity.push_back(intensity[i][j]); + } + new_intensity.insert(new_intensity.end(), intensity[i].begin(), intensity[i].end()); + intensity[i].swap(new_intensity); + } + v_angles.swap(new_v_angles); + } + else if(v_first == -90.0f) { + /* We have full 180° coverage, so just shift to match the angle range convention. */ + for(int i = 0; i < v_angles.size(); i++) { + v_angles[i] += 90.0f; + } + } + + return true; +} + +bool IESFile::process_type_c() +{ + if(h_angles[0] == 90.0f) { + /* Some files are stored from 90° to 270°, so we just rotate them to the regular 0°-180° range here. */ + for(int i = 0; i < v_angles.size(); i++) { + h_angles[i] -= 90.0f; + } + } + + if(h_angles[0] != 0.0f) { + return false; + } + + if(h_angles.size() == 1) { + h_angles.push_back(360.0f); + intensity.push_back(intensity[0]); + } + + if(h_angles[h_angles.size()-1] == 90.0f) { + /* Only one quadrant is defined, so we need to mirror twice (from one to two, then to four). + * Since the two->four mirroring step might also be required if we get an input of two quadrants, + * we only do the first mirror here and later do the second mirror in either case. */ + int hnum = h_angles.size(); + for(int i = hnum-2; i >= 0; i--) { + h_angles.push_back(180.0f - h_angles[i]); + intensity.push_back(intensity[i]); + } + } + + if(h_angles[h_angles.size()-1] == 180.0f) { + /* Mirror half to the full range. */ + int hnum = h_angles.size(); + for(int i = hnum-2; i >= 0; i--) { + h_angles.push_back(360.0f - h_angles[i]); + intensity.push_back(intensity[i]); + } + } + + /* Some files skip the 360° entry (contrary to standard) because it's supposed to be identical to the 0° entry. + * If the file has a discernible order in its spacing, just fix this. */ + if(h_angles[h_angles.size()-1] != 360.0f) { + int hnum = h_angles.size(); + float last_step = h_angles[hnum-1]-h_angles[hnum-2]; + float first_step = h_angles[1]-h_angles[0]; + float difference = 360.0f - h_angles[hnum-1]; + if(last_step == difference || first_step == difference) { + h_angles.push_back(360.0f); + intensity.push_back(intensity[0]); + } + else { + return false; + } + } + + float v_first = v_angles[0], v_last = v_angles[v_angles.size()-1]; + if(v_first == 90.0f) { + if(v_last == 180.0f) { + /* Flip to ensure that vertical angles always start at 0°. */ + for(int i = 0; i < v_angles.size(); i++) { + v_angles[i] = 180.0f - v_angles[i]; + } + } + else { + return false; + } + } + else if(v_first != 0.0f) { + return false; + } + + return true; +} + +bool IESFile::process() +{ + if(h_angles.size() == 0 || v_angles.size() == 0) { + return false; + } + + if(type == TYPE_B) { + if(!process_type_b()) { + return false; + } + } + else { + assert(type == TYPE_C); + if(!process_type_c()) { + return false; + } + } + + assert(v_angles[0] == 0.0f); + assert(h_angles[0] == 0.0f); + assert(h_angles[h_angles.size()-1] == 360.0f); + + /* Convert from deg to rad. */ + for(int i = 0; i < v_angles.size(); i++) { + v_angles[i] *= M_PI_F / 180.f; + } + for(int i = 0; i < h_angles.size(); i++) { + h_angles[i] *= M_PI_F / 180.f; + } + + return true; +} + +IESFile::~IESFile() +{ + clear(); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_ies.h b/intern/cycles/util/util_ies.h new file mode 100644 index 00000000000..5933cb3962a --- /dev/null +++ b/intern/cycles/util/util_ies.h @@ -0,0 +1,61 @@ +/* + * Copyright 2011-2018 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_IES_H__ +#define __UTIL_IES_H__ + +#include "util/util_param.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +class IESFile { +public: + IESFile() {} + ~IESFile(); + + int packed_size(); + void pack(float *data); + + bool load(ustring ies); + void clear(); + +protected: + bool parse(ustring ies); + bool process(); + bool process_type_b(); + bool process_type_c(); + + /* The brightness distribution is stored in spherical coordinates. + * The horizontal angles correspond to to theta in the regular notation + * and always span the full range from 0° to 360°. + * The vertical angles correspond to phi and always start at 0°. */ + vector<float> v_angles, h_angles; + /* The actual values are stored here, with every entry storing the values + * of one horizontal segment. */ + vector<vector<float> > intensity; + + /* Types of angle representation in IES files. Currently, only B and C are supported. */ + enum IESType { + TYPE_A = 3, + TYPE_B = 2, + TYPE_C = 1 + } type; +}; + +CCL_NAMESPACE_END + +#endif /* __UTIL_IES_H__ */ diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index d0e91a2a1c9..fd3199f209f 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -310,6 +310,17 @@ ccl_device_inline float4 float3_to_float4(const float3 a) return make_float4(a.x, a.y, a.z, 1.0f); } +ccl_device_inline float inverse_lerp(float a, float b, float x) +{ + return (x - a) / (b - a); +} + +/* Cubic interpolation between b and c, a and d are the previous and next point. */ +ccl_device_inline float cubic_interp(float a, float b, float c, float d, float x) +{ + return 0.5f*(((d + 3.0f*(b-c) - a)*x + (2.0f*a - 5.0f*b + 4.0f*c - d))*x + (c - a))*x + b; +} + CCL_NAMESPACE_END #include "util/util_math_int2.h" @@ -4,359 +4,66 @@ REM This is for users who like to configure & build Blender with a single comman setlocal EnableDelayedExpansion setlocal ENABLEEXTENSIONS set BLENDER_DIR=%~dp0 -set BLENDER_DIR_NOSPACES=%BLENDER_DIR: =% -for %%X in (svn.exe) do (set HAS_SVN=%%~$PATH:X) -if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( - echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... - goto EOF -) -set BUILD_DIR=%BLENDER_DIR%..\build_windows -set BUILD_TYPE=Release -rem reset all variables so they do not get accidentally get carried over from previous builds -set BUILD_DIR_OVERRRIDE= -set BUILD_CMAKE_ARGS= -set BUILD_ARCH= -set BUILD_VS_VER= -set BUILD_VS_YEAR= -set BUILD_VS_LIBDIRPOST= -set BUILD_VS_LIBDIR= -set BUILD_VS_SVNDIR= -set BUILD_NGE= -set KEY_NAME= -set MSBUILD_PLATFORM= -set MUST_CLEAN= -set NOBUILD= -set TARGET= -set WINDOWS_ARCH= -set TESTS_CMAKE_ARGS= -:argv_loop -if NOT "%1" == "" ( - REM Help Message - if "%1" == "help" ( - goto HELP - ) +call "%BLENDER_DIR%\build_files\windows\reset_variables.cmd" - REM Build Types - if "%1" == "debug" ( - set BUILD_TYPE=Debug - REM Build Configurations - ) else if "%1" == "noge" ( - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DWITH_GAMEENGINE=OFF -DWITH_PLAYER=OFF - set BUILD_NGE=_noge - ) else if "%1" == "builddir" ( - set BUILD_DIR_OVERRRIDE="%BLENDER_DIR%..\%2" - shift /1 - ) else if "%1" == "with_tests" ( - set TESTS_CMAKE_ARGS=-DWITH_GTESTS=On - ) else if "%1" == "full" ( - set TARGET=Full - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_full.cmake" - ) else if "%1" == "lite" ( - set TARGET=Lite - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_lite.cmake" - ) else if "%1" == "cycles" ( - set TARGET=Cycles - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\cycles_standalone.cmake" - ) else if "%1" == "headless" ( - set TARGET=Headless - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_headless.cmake" - ) else if "%1" == "bpy" ( - set TARGET=Bpy - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\bpy_module.cmake" - ) else if "%1" == "release" ( - set TARGET=Release - ) else if "%1" == "x86" ( - set BUILD_ARCH=x86 - ) else if "%1" == "x64" ( - set BUILD_ARCH=x64 - ) else if "%1" == "2017" ( - set BUILD_VS_VER=15 - set BUILD_VS_YEAR=2017 - set BUILD_VS_LIBDIRPOST=vc14 - ) else if "%1" == "2015" ( - set BUILD_VS_VER=14 - set BUILD_VS_YEAR=2015 - set BUILD_VS_LIBDIRPOST=vc14 - ) else if "%1" == "2013" ( - set BUILD_VS_VER=12 - set BUILD_VS_YEAR=2013 - set BUILD_VS_LIBDIRPOST=vc12 - ) else if "%1" == "packagename" ( - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -DCPACK_OVERRIDE_PACKAGENAME="%2" - shift /1 - ) else if "%1" == "nobuild" ( - set NOBUILD=1 - ) else if "%1" == "showhash" ( - for /f "delims=" %%i in ('git rev-parse HEAD') do echo Branch_hash=%%i - cd release/datafiles/locale - for /f "delims=" %%i in ('git rev-parse HEAD') do echo Locale_hash=%%i - cd %~dp0 - cd release/scripts/addons - for /f "delims=" %%i in ('git rev-parse HEAD') do echo Addons_Hash=%%i - cd %~dp0 - goto EOF - REM Non-Build Commands - ) else if "%1" == "update" ( - svn up ../lib/* - git pull --rebase - git submodule update --remote - goto EOF - ) else if "%1" == "clean" ( - set MUST_CLEAN=1 - ) else ( - echo Command "%1" unknown, aborting! - goto EOF - ) +call "%BLENDER_DIR%\build_files\windows\check_spaces_in_path.cmd" +if errorlevel 1 goto EOF - shift /1 - goto argv_loop -) -if "%BUILD_ARCH%"=="" ( - if "%PROCESSOR_ARCHITECTURE%" == "AMD64" ( - set WINDOWS_ARCH= Win64 - set BUILD_ARCH=x64 - ) else if "%PROCESSOR_ARCHITEW6432%" == "AMD64" ( - set WINDOWS_ARCH= Win64 - set BUILD_ARCH=x64 - ) else ( - set WINDOWS_ARCH= - set BUILD_ARCH=x86 - ) -) else if "%BUILD_ARCH%"=="x64" ( - set WINDOWS_ARCH= Win64 -) else if "%BUILD_ARCH%"=="x86" ( - set WINDOWS_ARCH= -) +call "%BLENDER_DIR%\build_files\windows\parse_arguments.cmd" %* +if errorlevel 1 goto EOF -if "%BUILD_VS_VER%"=="" ( - set BUILD_VS_VER=12 - set BUILD_VS_YEAR=2013 - set BUILD_VS_LIBDIRPOST=vc12 -) +call "%BLENDER_DIR%\build_files\windows\find_dependencies.cmd" +if errorlevel 1 goto EOF -if "%BUILD_ARCH%"=="x64" ( - set MSBUILD_PLATFORM=x64 -) else if "%BUILD_ARCH%"=="x86" ( - set MSBUILD_PLATFORM=win32 +if "%SHOW_HELP%" == "1" ( + call "%BLENDER_DIR%\build_files\windows\show_help.cmd" + goto EOF ) - -if "%target%"=="Release" ( - rem for vc12 check for both cuda 7.5 and 8 - if "%CUDA_PATH%"=="" ( - echo Cuda Not found, aborting! - goto EOF - ) - set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^ - -C"%BLENDER_DIR%\build_files\cmake\config\blender_release.cmake" +if "%BUILD_UPDATE%" == "1" ( + call "%BLENDER_DIR%\build_files\windows\update_sources.cmd" + goto EOF ) -:DetectMSVC -REM Detect MSVC Installation for 2013-2015 -if DEFINED VisualStudioVersion goto msvc_detect_finally -set VALUE_NAME=ProductDir -REM Check 64 bits -set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC" -for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C -if DEFINED MSVC_VC_DIR goto msvc_detect_finally -REM Check 32 bits -set KEY_NAME="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\%BUILD_VS_VER%.0\Setup\VC" -for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAME% 2^>nul`) DO set MSVC_VC_DIR=%%C -if DEFINED MSVC_VC_DIR goto msvc_detect_finally -:msvc_detect_finally -if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat" -if DEFINED MSVC_VC_DIR goto sanity_checks - -rem MSVC Build environment 2017 and up. -for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SXS\VS7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C -if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017 -REM Check 32 bits -for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\sxs\vs7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C -if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017 -:msvc_detect_finally_2017 -if DEFINED MSVC_VS_DIR call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat" +call "%BLENDER_DIR%\build_files\windows\detect_architecture.cmd" -:sanity_checks -REM Sanity Checks -where /Q msbuild -if %ERRORLEVEL% NEQ 0 ( - if "%BUILD_VS_VER%"=="12" ( - rem vs12 not found, try vs14 - echo Visual Studio 2013 not found, trying Visual Studio 2015. - set BUILD_VS_VER=14 - set BUILD_VS_YEAR=2015 - set BUILD_VS_LIBDIRPOST=vc14 - goto DetectMSVC - ) else ( - echo Error: "MSBuild" command not in the PATH. - echo You must have MSVC installed and run this from the "Developer Command Prompt" - echo ^(available from Visual Studio's Start menu entry^), aborting! +if "%BUILD_VS_YEAR%" == "" ( + call "%BLENDER_DIR%\build_files\windows\autodetect_msvc.cmd" + if errorlevel 1 ( + echo Visual Studio not found ^(try with the 'verbose' switch for more information^) goto EOF ) -) - - -set BUILD_DIR=%BUILD_DIR%_%TARGET%%BUILD_NGE%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE% -if NOT "%BUILD_DIR_OVERRRIDE%"=="" ( - set BUILD_DIR=%BUILD_DIR_OVERRRIDE% -) - -where /Q cmake -if %ERRORLEVEL% NEQ 0 ( - echo Error: "CMake" command not in the PATH. - echo You must have CMake installed and added to your PATH, aborting! - goto EOF -) - -if "%BUILD_ARCH%"=="x64" ( - set BUILD_VS_SVNDIR=win64_%BUILD_VS_LIBDIRPOST% -) else if "%BUILD_ARCH%"=="x86" ( - set BUILD_VS_SVNDIR=windows_%BUILD_VS_LIBDIRPOST% -) -set BUILD_VS_LIBDIR="%BLENDER_DIR%..\lib\%BUILD_VS_SVNDIR%" - -if NOT EXIST %BUILD_VS_LIBDIR% ( - rem libs not found, but svn is on the system - if not "%HAS_SVN%"=="" ( - echo. - echo The required external libraries in %BUILD_VS_LIBDIR% are missing - echo. - set /p GetLibs= "Would you like to download them? (y/n)" - if /I "!GetLibs!"=="Y" ( - echo. - echo Downloading %BUILD_VS_SVNDIR% libraries, please wait. - echo. - svn checkout https://svn.blender.org/svnroot/bf-blender/trunk/lib/%BUILD_VS_SVNDIR% %BUILD_VS_LIBDIR% - ) +) else ( + call "%BLENDER_DIR%\build_files\windows\detect_msvc%BUILD_VS_YEAR%.cmd" + if errorlevel 1 ( + echo Visual Studio %BUILD_VS_YEAR% not found ^(try with the 'verbose' switch for more information^) + goto EOF ) ) -if NOT EXIST %BUILD_VS_LIBDIR% ( - echo Error: Path to libraries not found "%BUILD_VS_LIBDIR%" - echo This is needed for building, aborting! - goto EOF -) +call "%BLENDER_DIR%\build_files\windows\set_build_dir.cmd" -if "%TARGET%"=="" ( - echo Error: Convenience target not set - echo This is required for building, aborting! - echo . - goto HELP -) +echo Building blender with VS%BUILD_VS_YEAR% for %BUILD_ARCH% in %BUILD_DIR% -set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% -G "Visual Studio %BUILD_VS_VER% %BUILD_VS_YEAR%%WINDOWS_ARCH%" %TESTS_CMAKE_ARGS% -if NOT EXIST %BUILD_DIR%\nul ( - mkdir %BUILD_DIR% -) -if "%MUST_CLEAN%"=="1" ( - echo Cleaning %BUILD_DIR% - msbuild ^ - %BUILD_DIR%\Blender.sln ^ - /target:clean ^ - /property:Configuration=%BUILD_TYPE% ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% +call "%BLENDER_DIR%\build_files\windows\check_libraries.cmd" +if errorlevel 1 goto EOF - if %ERRORLEVEL% NEQ 0 ( - echo Cleaned "%BUILD_DIR%" - ) - goto EOF -) -REM Only configure on first run or when called with nobuild -if NOT EXIST %BUILD_DIR%\Blender.sln set MUST_CONFIGURE=1 -if "%NOBUILD%"=="1" set MUST_CONFIGURE=1 - -if "%MUST_CONFIGURE%"=="1" ( - cmake ^ - %BUILD_CMAKE_ARGS% ^ - -H%BLENDER_DIR% ^ - -B%BUILD_DIR% ^ - %BUILD_CMAKE_ARGS% - - if %ERRORLEVEL% NEQ 0 ( - echo "Configuration Failed" - goto EOF - ) -) -if DEFINED MSVC_VC_DIR echo call "%MSVC_VC_DIR%\vcvarsall.bat" > %BUILD_DIR%\rebuild.cmd -if DEFINED MSVC_VS_DIR echo call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat" > %BUILD_DIR%\rebuild.cmd -echo cmake . >> %BUILD_DIR%\rebuild.cmd -echo msbuild ^ - %BUILD_DIR%\Blender.sln ^ - /target:build ^ - /property:Configuration=%BUILD_TYPE% ^ - /maxcpucount:2 ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% ^ - /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log >> %BUILD_DIR%\rebuild.cmd -echo msbuild ^ - %BUILD_DIR%\INSTALL.vcxproj ^ - /property:Configuration=%BUILD_TYPE% ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% >> %BUILD_DIR%\rebuild.cmd +call "%BLENDER_DIR%\build_files\windows\check_submodules.cmd" +if errorlevel 1 goto EOF -if "%NOBUILD%"=="1" goto EOF +if "%BUILD_WITH_NINJA%" == "" ( + call "%BLENDER_DIR%\build_files\windows\configure_msbuild.cmd" + if errorlevel 1 goto EOF -msbuild ^ - %BUILD_DIR%\Blender.sln ^ - /target:build ^ - /property:Configuration=%BUILD_TYPE% ^ - /maxcpucount:2 ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% ^ - /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log + call "%BLENDER_DIR%\build_files\windows\build_msbuild.cmd" + if errorlevel 1 goto EOF +) else ( + call "%BLENDER_DIR%\build_files\windows\configure_ninja.cmd" + if errorlevel 1 goto EOF -if %ERRORLEVEL% NEQ 0 ( - echo "Build Failed" - goto EOF + call "%BLENDER_DIR%\build_files\windows\build_ninja.cmd" + if errorlevel 1 goto EOF ) -msbuild ^ - %BUILD_DIR%\INSTALL.vcxproj ^ - /property:Configuration=%BUILD_TYPE% ^ - /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% - -echo. -echo At any point you can optionally modify your build configuration by editing: -echo "%BUILD_DIR%\CMakeCache.txt", then run "rebuild.cmd" in the build folder to build with the changes applied. -echo. -echo Blender successfully built, run from: "%BUILD_DIR%\bin\%BUILD_TYPE%\blender.exe" -echo. -goto EOF -:HELP - echo. - echo Convenience targets - echo - release ^(identical to the official blender.org builds^) - echo - full ^(same as release minus the cuda kernels^) - echo - lite - echo - headless - echo - cycles - echo - bpy - echo. - echo Utilities ^(not associated with building^) - echo - clean ^(Target must be set^) - echo - update - echo - nobuild ^(only generate project files^) - echo - showhash ^(Show git hashes of source tree^) - echo. - echo Configuration options - echo - with_tests ^(enable building unit tests^) - echo - noge ^(disable building game enginge and player^) - echo - debug ^(Build an unoptimized debuggable build^) - echo - packagename [newname] ^(override default cpack package name^) - echo - buildir [newdir] ^(override default build folder^) - echo - x86 ^(override host auto-detect and build 32 bit code^) - echo - x64 ^(override host auto-detect and build 64 bit code^) - echo - 2013 ^(build with visual studio 2013^) - echo - 2015 ^(build with visual studio 2015^) [EXPERIMENTAL] - echo - 2017 ^(build with visual studio 2017^) [EXPERIMENTAL] - echo. - :EOF diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 28e39959c7e..466e7dfa325 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -328,7 +328,8 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): row.prop(md, "delimit") layout_info = layout - layout_info.label(text=iface_("Faces: %d") % md.face_count, translate=False) + layout_info.label(text=iface_("Face Count: {:,}".format(md.face_count)), + translate=False) def DISPLACE(self, layout, ob, md): has_texture = (md.texture is not None) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 591180f08b4..d60710db4aa 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -229,6 +229,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTexChecker"), NodeItem("ShaderNodeTexBrick"), NodeItem("ShaderNodeTexPointDensity"), + NodeItem("ShaderNodeTexIES"), ]), ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ NodeItem("ShaderNodeMixRGB"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f3cbcd7b99f..c654dd51e2a 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -796,6 +796,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, struct Scene *scene, c #define SH_NODE_UVALONGSTROKE 191 #define SH_NODE_TEX_POINTDENSITY 192 #define SH_NODE_BSDF_PRINCIPLED 193 +#define SH_NODE_TEX_IES 194 #define SH_NODE_EEVEE_SPECULAR 195 #define SH_NODE_BEVEL 197 #define SH_NODE_DISPLACEMENT 198 diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 259c5189896..dbaf3f2ee9e 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -560,6 +560,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int NodeShaderScript *nss = (NodeShaderScript *)node->storage; rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data); } + else if (node->type == SH_NODE_TEX_IES) { + NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage; + rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data); + } } } break; @@ -576,6 +580,10 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int NodeShaderScript *nss = (NodeShaderScript *)node->storage; rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data); } + else if (node->type == SH_NODE_TEX_IES) { + NodeShaderTexIES *ies = (NodeShaderTexIES *)node->storage; + rewrite_path_fixed(ies->filepath, visit_cb, absbase, bpath_user_data); + } } } break; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index d86b73ab1a9..a25b21a995a 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3545,6 +3545,7 @@ static void registerShaderNodes(void) register_node_type_sh_tex_checker(); register_node_type_sh_tex_brick(); register_node_type_sh_tex_pointdensity(); + register_node_type_sh_tex_ies(); } static void registerTextureNodes(void) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 7fd7b791a3f..a99057ac0ad 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -50,6 +50,7 @@ #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_math.h" +#include "BLI_string.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -4071,9 +4072,11 @@ void BKE_ptcache_update_info(PTCacheID *pid) } else { PTCacheMem *pm = cache->mem_cache.first; - float bytes = 0.0f; - int i, mb; - + char formatted_tot[16]; + char formatted_mem[15]; + long long int bytes = 0.0f; + int i; + for (; pm; pm=pm->next) { for (i=0; i<BPHYS_TOT_DATA; i++) bytes += MEM_allocN_len(pm->data[i]); @@ -4088,12 +4091,10 @@ void BKE_ptcache_update_info(PTCacheID *pid) totframes++; } - mb = (bytes > 1024.0f * 1024.0f); + BLI_str_format_int_grouped(formatted_tot, totframes); + BLI_str_format_byte_unit(formatted_mem, bytes, true); - BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%i frames in memory (%.1f %s)"), - totframes, - bytes / (mb ? 1024.0f * 1024.0f : 1024.0f), - mb ? IFACE_("Mb") : IFACE_("kb")); + BLI_snprintf(mem_info, sizeof(mem_info), IFACE_("%s frames in memory (%s)"), formatted_tot, formatted_mem); } if (cache->flag & PTCACHE_OUTDATED) { diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index 48be9d1842f..faa8dc03615 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -71,6 +71,7 @@ char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT A size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL(); size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL(); +void BLI_str_format_byte_unit(char dst[15], long long int size, const bool base_10) ATTR_NONNULL(); int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 1a6fd082e95..49630347032 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -799,6 +799,7 @@ int BLI_str_rstrip_float_zero(char *str, const char pad) while (end_p != p && *end_p == '0') { *end_p = pad; end_p--; + totstrip++; } } } @@ -995,6 +996,41 @@ size_t BLI_str_format_int_grouped(char dst[16], int num) } /** + * Format a size in bytes using binary units. + * 1000 -> 1 KB + * Number of decimal places grows with the used unit (e.g. 1.5 MB, 1.55 GB, 1.545 TB). + * + * \param dst The resulting string. Dimension of 14 to support largest possible value for \a bytes (LLONG_MAX). + * \param bytes Number to format + * \param base_10 Calculate using base 10 (GB, MB, ...) or 2 (GiB, MiB, ...) + */ +void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base_10) +{ + double bytes_converted = bytes; + int order = 0; + int decimals; + const int base = base_10 ? 1000 : 1024; + const char *units_base_10[] = {"B", "KB", "MB", "GB", "TB", "PB"}; + const char *units_base_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB"}; + const int tot_units = ARRAY_SIZE(units_base_2); + + BLI_STATIC_ASSERT(ARRAY_SIZE(units_base_2) == ARRAY_SIZE(units_base_10), "array size mismatch"); + + while ((ABS(bytes_converted) >= base) && ((order + 1) < tot_units)) { + bytes_converted /= base; + order++; + } + decimals = MAX2(order - 1, 0); + + /* Format value first, stripping away floating zeroes. */ + const size_t dst_len = 15; + size_t len = BLI_snprintf_rlen(dst, dst_len, "%.*f", decimals, bytes_converted); + len -= (size_t)BLI_str_rstrip_float_zero(dst, '\0'); + dst[len++] = ' '; + BLI_strncpy(dst + len, base_10 ? units_base_10[order] : units_base_2[order], dst_len - len); +} + +/** * Find the ranges needed to split \a str into its individual words. * * \param str: The string to search for words. diff --git a/source/blender/blenlib/intern/threads.c b/source/blender/blenlib/intern/threads.c index 761f3982e28..e6f5d9839ea 100644 --- a/source/blender/blenlib/intern/threads.c +++ b/source/blender/blenlib/intern/threads.c @@ -488,7 +488,8 @@ void BLI_spin_lock(SpinLock *spin) #elif defined(_MSC_VER) while (InterlockedExchangeAcquire(spin, 1)) { while (*spin) { - /* pass */ + /* Spinlock hint for processors with hyperthreading. */ + YieldProcessor(); } } #else diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index dfcf5fd5d8d..d2bfcfa76df 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -410,6 +410,7 @@ static void stats_string(ViewLayer *view_layer) uintptr_t mem_in_use, mmap_in_use; char memstr[MAX_INFO_MEM_LEN]; char gpumemstr[MAX_INFO_MEM_LEN] = ""; + char formatted_mem[15]; char *s; size_t ofs = 0; @@ -445,20 +446,25 @@ static void stats_string(ViewLayer *view_layer) /* get memory statistics */ - ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem:%.2fM"), - (double)((mem_in_use - mmap_in_use) >> 10) / 1024.0); - if (mmap_in_use) - BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%.2fM)"), (double)((mmap_in_use) >> 10) / 1024.0); + BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, true); + ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, IFACE_(" | Mem: %s"), formatted_mem); + + if (mmap_in_use) { + BLI_str_format_byte_unit(formatted_mem, mmap_in_use, true); + BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" (%s)"), formatted_mem); + } if (GPU_mem_stats_supported()) { int gpu_free_mem, gpu_tot_memory; GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem); - ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem:%.2fM"), (double)((gpu_free_mem)) / 1024.0); + BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, true); + ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, IFACE_(" | Free GPU Mem: %s"), formatted_mem); if (gpu_tot_memory) { - BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%.2fM"), (double)((gpu_tot_memory)) / 1024.0); + BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, true); + BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_("/%s"), formatted_mem); } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index ca6ae5955a9..19e2ae9808a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1021,6 +1021,21 @@ static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), Pointer uiItemR(layout, ptr, "component", 0, "", ICON_NONE); } +static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayout *row; + + row = uiLayoutRow(layout, false); + uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + + row = uiLayoutRow(layout, true); + + if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) + uiItemR(row, ptr, "ies", 0, "", ICON_NONE); + else + uiItemR(row, ptr, "filepath", 0, "", ICON_NONE); +} + static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *row; @@ -1189,6 +1204,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_OUTPUT_LINESTYLE: ntype->draw_buttons = node_buts_output_linestyle; break; + case SH_NODE_TEX_IES: + ntype->draw_buttons = node_shader_buts_ies; + break; case SH_NODE_BEVEL: ntype->draw_buttons = node_shader_buts_bevel; break; diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 66eaf34865f..cd8a49fd697 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -1110,7 +1110,7 @@ static void view3d_ndof_pan_zoom( static void view3d_ndof_orbit( const struct wmNDOFMotionData *ndof, ScrArea *sa, ARegion *ar, /* optional, can be NULL*/ - ViewOpsData *vod) + ViewOpsData *vod, const bool apply_dyn_ofs) { View3D *v3d = sa->spacedata.first; RegionView3D *rv3d = ar->regiondata; @@ -1173,7 +1173,7 @@ static void view3d_ndof_orbit( mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat); } - if (vod) { + if (apply_dyn_ofs) { viewrotate_apply_dyn_ofs(vod, rv3d->viewquat); } } @@ -1342,7 +1342,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event) } if (has_rotation) { - view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, true); } } @@ -1424,7 +1424,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev } if (has_rotation) { - view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, vod, true); } } else { /* free/explore (like fly mode) */ @@ -1442,7 +1442,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev ED_view3d_distance_set(rv3d, 0.0f); if (has_rotation) { - view3d_ndof_orbit(ndof, vod->sa, vod->ar, NULL); + view3d_ndof_orbit(ndof, vod->sa, vod->ar, NULL, false); } ED_view3d_distance_set(rv3d, dist_backup); diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 613830bac8d..af1045ee059 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -891,6 +891,12 @@ typedef struct NodeShaderUVMap { char uv_map[64]; } NodeShaderUVMap; +typedef struct NodeShaderTexIES { + int mode; + + char filepath[1024]; /* 1024 = FILE_MAX */ +} NodeShaderTexIES; + typedef struct NodeSunBeams { float source[2]; @@ -904,6 +910,9 @@ typedef struct NodeSunBeams { /* script node flag */ #define NODE_SCRIPT_AUTO_UPDATE 1 +/* ies node mode */ +#define NODE_IES_INTERNAL 0 +#define NODE_IES_EXTERNAL 1 /* frame node flags */ #define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 4744b2e33df..1cd907aeb91 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -527,6 +527,7 @@ extern StructRNA RNA_ShaderNodeCombineRGB; extern StructRNA RNA_ShaderNodeExtendedMaterial; extern StructRNA RNA_ShaderNodeGeometry; extern StructRNA RNA_ShaderNodeHueSaturation; +extern StructRNA RNA_ShaderNodeIESLight; extern StructRNA RNA_ShaderNodeInvert; extern StructRNA RNA_ShaderNodeLampData; extern StructRNA RNA_ShaderNodeMapping; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index e05e9d32277..182e606a357 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -2950,6 +2950,30 @@ static bNodeSocket *rna_NodeOutputFile_slots_new(ID *id, bNode *node, bContext * return sock; } +static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value) +{ + bNode *node = (bNode *)ptr->data; + NodeShaderTexIES *nss = node->storage; + + if (nss->mode != value) { + nss->mode = value; + nss->filepath[0] = '\0'; + + /* replace text datablock by filepath */ + if (node->id) { + Text *text = (Text *)node->id; + + if (value == NODE_IES_EXTERNAL && text->name) { + BLI_strncpy(nss->filepath, text->name, sizeof(nss->filepath)); + BLI_path_rel(nss->filepath, G.main->name); + } + + id_us_min(node->id); + node->id = NULL; + } + } +} + static void rna_ShaderNodeScript_mode_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; @@ -3292,6 +3316,12 @@ static const EnumPropertyItem node_script_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +static EnumPropertyItem node_ies_mode_items[] = { + {NODE_IES_INTERNAL, "INTERNAL", 0, "Internal", "Use internal text datablock"}, + {NODE_IES_EXTERNAL, "EXTERNAL", 0, "External", "Use external .ies file"}, + {0, NULL, 0, NULL, NULL} +}; + static const EnumPropertyItem node_principled_distribution_items[] = { {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, @@ -4403,6 +4433,32 @@ static void def_sh_subsurface(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNodeSubsurface_update"); } +static void def_sh_tex_ies(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "ies", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "Text"); + RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_REFCOUNT); + RNA_def_property_ui_text(prop, "IES Text", "Internal IES file"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + RNA_def_struct_sdna_from(srna, "NodeShaderTexIES", "storage"); + + prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_ui_text(prop, "File Path", "IES light path"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_funcs(prop, NULL, "rna_ShaderNodeTexIES_mode_set", NULL); + RNA_def_property_enum_items(prop, node_ies_mode_items); + RNA_def_property_ui_text(prop, "Source", "Whether the IES file is loaded from disk or from a Text datablock"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + + RNA_def_struct_sdna_from(srna, "bNode", NULL); +} + static void def_sh_script(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 5acd0a9fcea..67c86180188 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -173,6 +173,7 @@ set(SRC shader/nodes/node_shader_fresnel.c shader/nodes/node_shader_geometry.c shader/nodes/node_shader_holdout.c + shader/nodes/node_shader_ies_light.c shader/nodes/node_shader_layer_weight.c shader/nodes/node_shader_light_falloff.c shader/nodes/node_shader_light_path.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 3d6a8647628..158d20a5c19 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -136,6 +136,7 @@ void register_node_type_sh_tex_musgrave(void); void register_node_type_sh_tex_noise(void); void register_node_type_sh_tex_checker(void); void register_node_type_sh_bump(void); +void register_node_type_sh_tex_ies(void); #endif diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index efb8eb66737..437093a9cb3 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -126,6 +126,7 @@ DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "CO DefNode( ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEVEL", Bevel, "Bevel", "" ) DefNode( ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DISPLACEMENT", Displacement, "Displacement", "" ) DefNode( ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","" ) +DefNode( ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" ) DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.c new file mode 100644 index 00000000000..8084f445e34 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.c @@ -0,0 +1,61 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2018 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "../node_shader_util.h" + +/* **************** IES Light ******************** */ + +static bNodeSocketTemplate sh_node_tex_ies_in[] = { + { SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + { SOCK_FLOAT, 1, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000000.0f, PROP_NONE}, + { -1, 0, "" } +}; + +static bNodeSocketTemplate sh_node_tex_ies_out[] = { + { SOCK_FLOAT, 0, N_("Fac")}, + { -1, 0, "" } +}; + +static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeShaderTexIES *tex = MEM_callocN(sizeof(NodeShaderTexIES), "NodeShaderIESLight"); + node->storage = tex; +} + +/* node type definition */ +void register_node_type_sh_tex_ies(void) +{ + static bNodeType ntype; + + sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out); + node_type_init(&ntype, node_shader_init_tex_ies); + node_type_storage(&ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/tests/gtests/blenlib/BLI_string_test.cc b/tests/gtests/blenlib/BLI_string_test.cc index f6f7e17c8ca..f3a12cef26a 100644 --- a/tests/gtests/blenlib/BLI_string_test.cc +++ b/tests/gtests/blenlib/BLI_string_test.cc @@ -364,6 +364,72 @@ TEST(string, StrFormatIntGrouped) EXPECT_STREQ("-999", num_str); } +/* BLI_str_format_byte_unit */ +TEST(string, StrFormatByteUnits) +{ + char size_str[15]; + long long int size; + + /* Base 10 */ + BLI_str_format_byte_unit(size_str, size = 0, true); + EXPECT_STREQ("0 B", size_str); + BLI_str_format_byte_unit(size_str, size = -0, true); + EXPECT_STREQ("0 B", size_str); + + BLI_str_format_byte_unit(size_str, size = 1, true); + EXPECT_STREQ("1 B", size_str); + BLI_str_format_byte_unit(size_str, size = -1, true); + EXPECT_STREQ("-1 B", size_str); + + BLI_str_format_byte_unit(size_str, size = 1000, true); + EXPECT_STREQ("1 KB", size_str); + BLI_str_format_byte_unit(size_str, size = -1000, true); + EXPECT_STREQ("-1 KB", size_str); + + BLI_str_format_byte_unit(size_str, size = 1024, true); + EXPECT_STREQ("1 KB", size_str); + BLI_str_format_byte_unit(size_str, size = -1024, true); + EXPECT_STREQ("-1 KB", size_str); + + BLI_str_format_byte_unit(size_str, size = 9223372036854775807, true); /* LLONG_MAX - largest possible value */ + EXPECT_STREQ("9223.372 PB", size_str); + BLI_str_format_byte_unit(size_str, size = -9223372036854775807, true); + EXPECT_STREQ("-9223.372 PB", size_str); + + + /* Base 2 */ + BLI_str_format_byte_unit(size_str, size = 0, false); + EXPECT_STREQ("0 B", size_str); + BLI_str_format_byte_unit(size_str, size = -0, false); + EXPECT_STREQ("0 B", size_str); + + BLI_str_format_byte_unit(size_str, size = 1, false); + EXPECT_STREQ("1 B", size_str); + BLI_str_format_byte_unit(size_str, size = -1, false); + EXPECT_STREQ("-1 B", size_str); + + BLI_str_format_byte_unit(size_str, size = 1000, false); + EXPECT_STREQ("1000 B", size_str); + BLI_str_format_byte_unit(size_str, size = -1000, false); + EXPECT_STREQ("-1000 B", size_str); + + BLI_str_format_byte_unit(size_str, size = 1024, false); + EXPECT_STREQ("1 KiB", size_str); + BLI_str_format_byte_unit(size_str, size = -1024, false); + EXPECT_STREQ("-1 KiB", size_str); + + BLI_str_format_byte_unit(size_str, size = 9223372036854775807, false); /* LLONG_MAX - largest possible value */ + EXPECT_STREQ("8192.0 PiB", size_str); + BLI_str_format_byte_unit(size_str, size = -9223372036854775807, false); + EXPECT_STREQ("-8192.0 PiB", size_str); + + /* Test maximum string length. */ + BLI_str_format_byte_unit(size_str, size = -9223200000000000000, false); + EXPECT_STREQ("-8191.8472 PiB", size_str); +} + + + #define STRING_FIND_SPLIT_WORDS_EX(word_str_src, word_str_src_len, limit_words, ...) \ { \ int word_info[][2] = \ |