Compare commits
502 Commits
nodes-upda
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
03f726a550 | |||
2112710249 | |||
96f73c9a16 | |||
2de71cff72 | |||
260bcc482d | |||
065b88ed8b | |||
d8834b0015 | |||
329cda9519 | |||
0a6186dcdf | |||
662e37d280 | |||
edfcaf0abd | |||
25c42e650d | |||
962153dbed | |||
c0dd6f1164 | |||
72f73c0b71 | |||
dbc4f6fdc9 | |||
871f7f4ad8 | |||
3febcb98ed | |||
0896457c59 | |||
214e4aac97 | |||
479cc9a83e | |||
71655ff8df | |||
7192e57d63 | |||
b0d9e6797f | |||
119d53263f | |||
![]() |
85b044b3ef | ||
46aafbbf66 | |||
e648e38887 | |||
0f49e4832c | |||
d5776f4829 | |||
51862c8445 | |||
5b97c00e9f | |||
4db4123409 | |||
cf72194214 | |||
22ab0159a9 | |||
4734de1093 | |||
594790d8a5 | |||
7a4ef5256a | |||
feaa61a968 | |||
ac09411368 | |||
a217e043be | |||
55f9014616 | |||
6b041ad3d0 | |||
b8ecdbcd96 | |||
e5f8db92b6 | |||
fffe219bdb | |||
1d06d35034 | |||
ba71eb467e | |||
9bfd4ae222 | |||
![]() |
04376c3bac | ||
787350dde8 | |||
7bffafab7b | |||
![]() |
c0f600cad1 | ||
400cb25fc7 | |||
f41beca977 | |||
24c16f5457 | |||
809dce5bde | |||
![]() |
e3098de2a1 | ||
23132fcdc1 | |||
60d6333b80 | |||
![]() |
88dc274d05 | ||
96d0cd57dc | |||
e98824d6c4 | |||
7f38872533 | |||
0246128b7f | |||
f8dd0080a9 | |||
6028ac44a1 | |||
7304541f66 | |||
32844d32c1 | |||
4443831c6b | |||
6baa62245f | |||
cb40c7ca1f | |||
4c8d68c032 | |||
736b6a70a4 | |||
![]() |
69fdcea978 | ||
ba055493a0 | |||
![]() |
d60e28093f | ||
869b84452a | |||
eaa1527385 | |||
4dba206011 | |||
b5117660da | |||
035d4c28ab | |||
df3884d512 | |||
7db3746033 | |||
394a0b0da5 | |||
118946d195 | |||
2946f72a2a | |||
ded68fb102 | |||
6df81ddb84 | |||
a01cf90fd8 | |||
43ad345caa | |||
e314260fa7 | |||
08af3e6e92 | |||
![]() |
fecec1644c | ||
ddecd7aaca | |||
![]() |
c48a01a88a | ||
c0016a8581 | |||
4300050e20 | |||
87adcbc94f | |||
6aebbe6a0a | |||
eb278f5e12 | |||
899935d5d0 | |||
3f0d785d23 | |||
d5261e973b | |||
8f2b60ddbf | |||
6a4533dd02 | |||
ae3472998a | |||
![]() |
0ed2df81cc | ||
5655b3d1c5 | |||
5225e459da | |||
bb0e29c922 | |||
7772880d69 | |||
77744b581d | |||
![]() |
0b3c7544b5 | ||
4cadccebfa | |||
b9486c39bc | |||
fd29a161cc | |||
00f264ea42 | |||
0ae23636e7 | |||
5f6033e091 | |||
7b5acc8009 | |||
160d57d33c | |||
3e775a4fc5 | |||
41e6509818 | |||
8fa05efe0a | |||
92f4abc37f | |||
b51a473e29 | |||
ab344775c2 | |||
ed38d0c25d | |||
399b6ec76c | |||
1275ce61b1 | |||
e0fd5fef12 | |||
f801d40daf | |||
3930b8c69e | |||
333c3c92ab | |||
dc8844f8ef | |||
![]() |
d6891d9bee | ||
215734bc52 | |||
6293cf6131 | |||
ad2fb92e9c | |||
04ef718226 | |||
806bf3f452 | |||
83603ba26a | |||
497bc4d199 | |||
216414c65a | |||
c741558509 | |||
1ef275963d | |||
4f61843a7e | |||
45d100208e | |||
48c8f9fc9a | |||
cd1bb63159 | |||
![]() |
bb487bc2bc | ||
e53afad241 | |||
c9a9d5332b | |||
![]() |
e6bbbd965a | ||
6d24017529 | |||
6a9d7139f7 | |||
![]() |
bbcb60fb22 | ||
62cb5c5c4a | |||
48ba341d15 | |||
6aae140278 | |||
f3e26c847b | |||
cbc671947a | |||
18fbcaf7b9 | |||
![]() |
2f39f7f815 | ||
d480f03952 | |||
55615e2600 | |||
fcd2d63b64 | |||
8652e69d8b | |||
32c687b5ec | |||
946da86e02 | |||
6806459246 | |||
b6538e1492 | |||
eb03529ab9 | |||
d481c6651d | |||
8f6cc16490 | |||
b81d88a8e2 | |||
1a9b9dd64d | |||
5deb3229a0 | |||
079f35572b | |||
0116a567dd | |||
6c0c766bca | |||
4599748962 | |||
![]() |
e38de11f05 | ||
9c0f11344e | |||
05879f2c36 | |||
fe1740ae6a | |||
aab7540b7a | |||
895d3cd11e | |||
182edd4c35 | |||
76d52cbcb4 | |||
7c2c66cdb8 | |||
61040a36aa | |||
128ca8c7f6 | |||
692e926b18 | |||
49ea8e4fea | |||
b83ee724a4 | |||
4ca19c7153 | |||
3335f852a1 | |||
26fea4de63 | |||
d9930cddfd | |||
cb7b4064d6 | |||
![]() |
cd692c6954 | ||
3b87fd376a | |||
![]() |
8e3dea27ec | ||
2d867426b1 | |||
ce95a2b148 | |||
b04997cca4 | |||
fddd5eb692 | |||
ff594715b8 | |||
71e2c366f7 | |||
6fe00939b0 | |||
6deb37474e | |||
e2a411570e | |||
3886ab05b4 | |||
73b047bcd4 | |||
22ed1c7b61 | |||
0e4a250279 | |||
7ea577eef3 | |||
d6f162dfa9 | |||
0986992dbd | |||
909e0819ae | |||
52c349cfcd | |||
b417fb9251 | |||
64d750fb73 | |||
d3a699925d | |||
eb165f574b | |||
![]() |
8830cfe541 | ||
ff9bc901f4 | |||
3ea6cf7d41 | |||
4c26bb0232 | |||
![]() |
0be26f563e | ||
76e24609fd | |||
3f1873111e | |||
b541b5f875 | |||
a7aeec2655 | |||
a7bb537a61 | |||
![]() |
b33b70ed07 | ||
d245782b80 | |||
3fab16fe8e | |||
4f64fa4f86 | |||
69c9363e39 | |||
335379d8fc | |||
3fbe6f513d | |||
9cff9f9f5d | |||
2796ee7da0 | |||
01c1b1e82e | |||
f4adb35f28 | |||
b0df8f53ba | |||
4c675bc356 | |||
151eed752b | |||
d98791a106 | |||
6188c29603 | |||
1ab75c1d49 | |||
bb8ce95b5e | |||
bc97d78329 | |||
99738fbfdc | |||
1f8485ae82 | |||
![]() |
bc0d55e724 | ||
263fa406cd | |||
![]() |
92edf37997 | ||
![]() |
89014b51f1 | ||
cf10eb54cc | |||
d01781129f | |||
4dd6c9ad45 | |||
6844f7bedb | |||
![]() |
bd44e82b25 | ||
c15635bd8d | |||
04c24bec07 | |||
ff2265f0a9 | |||
8158211198 | |||
ca64bd0aac | |||
6c326ba0a2 | |||
834523e239 | |||
27b9cb7a1e | |||
03d7561708 | |||
b4f950cbbe | |||
![]() |
cc4e674e41 | ||
e844e9e8f3 | |||
0cff7c2a22 | |||
720ea8a67d | |||
be6409a748 | |||
fb1822ddeb | |||
f45860fba9 | |||
ed9759349b | |||
02e0c6f42e | |||
317f09ebf9 | |||
03e2f11d48 | |||
647a8bff06 | |||
f5acfd9c04 | |||
d8582d966f | |||
2b51124d6a | |||
450593ddf0 | |||
d3d4be1db3 | |||
d1c5e2e050 | |||
604ae5f7b6 | |||
1def985d78 | |||
438d645a36 | |||
171433e841 | |||
d6ca7ab20e | |||
07b702f828 | |||
1d1020b79f | |||
49acc52e02 | |||
8abf6efcf6 | |||
![]() |
10b9621079 | ||
ae920d789e | |||
b5bfb5f34c | |||
c18d91918f | |||
58ba75f9e3 | |||
a8185d2d74 | |||
2af789d1f3 | |||
c1730ed165 | |||
145270d8d7 | |||
e5d4a0c559 | |||
26c2c617b4 | |||
![]() |
76dcf70dac | ||
d2130c5327 | |||
add719e31a | |||
ac6b263906 | |||
557e7f135e | |||
051141acde | |||
d9a530c55e | |||
![]() |
8c21076add | ||
![]() |
c8004ab407 | ||
![]() |
b867df903f | ||
cb67bfdba2 | |||
218df99410 | |||
3b0fab6dfa | |||
effc048710 | |||
cd92b2350f | |||
10464843dd | |||
![]() |
0f45576590 | ||
26f1a5e2c8 | |||
5950b3ab73 | |||
71dc134f89 | |||
7389fd9a35 | |||
8a1c1279b3 | |||
0d2589d08c | |||
fb87d236ed | |||
18d900caca | |||
41357d556f | |||
39e914cee7 | |||
57281b73c4 | |||
652fbc2005 | |||
a25a1f39aa | |||
4e1a1821e0 | |||
391af6bea2 | |||
7724251af8 | |||
d3dd735fea | |||
cec103d5a9 | |||
0342fb5d20 | |||
dbd34a5acb | |||
b35a96e195 | |||
20d5d7b8ec | |||
c6f64d46ed | |||
![]() |
ea54cbe1b4 | ||
28b9dd7b1f | |||
c0900a64ce | |||
b1a607ce04 | |||
f8abc3fb2f | |||
d6e97a53ab | |||
b54e741a8b | |||
00b57136e4 | |||
![]() |
6f50969406 | ||
![]() |
ebd55b4acd | ||
![]() |
a53feb0aff | ||
c1a477b497 | |||
1973fd89df | |||
04c75c5ce7 | |||
223f048138 | |||
efd7c95bb2 | |||
a4813379f9 | |||
4f6f445120 | |||
8b93265c19 | |||
a2203a27d9 | |||
67d56eb71e | |||
77187718e4 | |||
eccd8af828 | |||
1062649b5e | |||
3ff5d8f719 | |||
ceb049133c | |||
d8bf332f86 | |||
![]() |
0e4f7b4a4b | ||
11cfa6c718 | |||
d60a7a8744 | |||
8edb2222ae | |||
aa60416361 | |||
06cb48e1b2 | |||
1f0d6f7635 | |||
3fd5c93f9c | |||
de91cdd930 | |||
48722e8971 | |||
1cf45fe10f | |||
![]() |
836aeebf70 | ||
7dcd72b0d3 | |||
![]() |
fc993a7d54 | ||
659385aa0d | |||
![]() |
11c03ff03d | ||
d4595187dd | |||
![]() |
1aaf6f4a1d | ||
5090bfaa37 | |||
ff66c0b24c | |||
5f9b3950eb | |||
c7e222c5ee | |||
f595b5aaf9 | |||
f1839a872b | |||
d8fc478dd7 | |||
123fd3d5c4 | |||
54e8b0ad57 | |||
eea7e751f4 | |||
4fa97ee3c6 | |||
9939b28888 | |||
414aaad1d4 | |||
c2e155f429 | |||
9413a5a00d | |||
dbe3303180 | |||
94ff60acc1 | |||
20f0c76061 | |||
872db161dc | |||
b926fb8acc | |||
dca1a1198a | |||
241ac50684 | |||
5dc643fa98 | |||
c01174354f | |||
4c4c6951f8 | |||
f3bf9b5035 | |||
0f6b47c49d | |||
6d0eb66464 | |||
c1806d565c | |||
![]() |
a22d87bdec | ||
![]() |
1e21b4e5dd | ||
![]() |
e68ddf02bb | ||
![]() |
acfce155e7 | ||
![]() |
0590bff3ab | ||
![]() |
a765f9f712 | ||
![]() |
651e702c52 | ||
![]() |
abe39529f6 | ||
![]() |
8659ae3b2d | ||
5f820329b0 | |||
f3395c753f | |||
4e90f53dbc | |||
251b41702d | |||
c3e90684bf | |||
81a29b8c9e | |||
a4d2d344e5 | |||
445f87684a | |||
105d3fb41e | |||
eb400e3ec2 | |||
![]() |
c4df8f301f | ||
![]() |
507dc9eb29 | ||
![]() |
c1b6319e9a | ||
600ffb71d3 | |||
d04aa1fd44 | |||
7ee74c6988 | |||
578c279ed9 | |||
e70c463661 | |||
040f67df6c | |||
519a6c425d | |||
a84e8fab2b | |||
7bda09e55d | |||
b26cc7ce2e | |||
af26fadb31 | |||
![]() |
f0328b464c | ||
![]() |
be493d60b5 | ||
![]() |
0e7bbe614f | ||
32bcef550e | |||
a684165cad | |||
0feac81b3c | |||
e751367fe7 | |||
518e436a37 | |||
a855d8ca6b | |||
eb90899cd0 | |||
e9a60ce199 | |||
9500604e36 | |||
![]() |
ba0146db67 | ||
![]() |
68da165ff2 | ||
![]() |
9225ca1227 | ||
9a229688a8 | |||
00e0048175 | |||
bf4b625992 | |||
![]() |
d342af8fe4 | ||
![]() |
50253272bc | ||
![]() |
261afa7bce | ||
![]() |
192a2e6b3b | ||
![]() |
7f9d5895ad | ||
![]() |
3537a57974 | ||
3de4388252 | |||
0fc72070fe | |||
a6a2c045a9 | |||
16ddba2b0d | |||
c872ff784f | |||
8ab1fc7a24 | |||
3f97468bd4 | |||
b39820ed7c | |||
22ab8523fa | |||
452a679869 | |||
eca6e4cb2d | |||
c333af11bb | |||
2aec7410fd | |||
79327e2a52 | |||
![]() |
12dd850446 | ||
![]() |
33bcefcf71 |
@@ -110,6 +110,10 @@ if(POLICY CMP0074)
|
||||
cmake_policy(SET CMP0074 NEW)
|
||||
endif()
|
||||
|
||||
# Install CODE|SCRIPT allow the use of generator expressions.
|
||||
if(POLICY CMP0087)
|
||||
cmake_policy(SET CMP0087 NEW)
|
||||
endif()
|
||||
#-----------------------------------------------------------------------------
|
||||
# Load some macros.
|
||||
include(build_files/cmake/macros.cmake)
|
||||
@@ -251,6 +255,16 @@ if(WITH_GHOST_X11)
|
||||
option(WITH_X11_ALPHA "Enable X11 transparent background" ON)
|
||||
endif()
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(WITH_SYSTEM_GLEW "Use GLEW OpenGL wrapper library provided by the operating system" OFF)
|
||||
option(WITH_SYSTEM_GLES "Use OpenGL ES library provided by the operating system" ON)
|
||||
else()
|
||||
# not an option for other OS's
|
||||
set(WITH_SYSTEM_GLEW OFF)
|
||||
set(WITH_SYSTEM_GLES OFF)
|
||||
endif()
|
||||
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
option(WITH_SYSTEM_EIGEN3 "Use the systems Eigen3 library" OFF)
|
||||
endif()
|
||||
@@ -414,6 +428,10 @@ mark_as_advanced(WITH_CYCLES_NETWORK)
|
||||
option(WITH_CUDA_DYNLOAD "Dynamically load CUDA libraries at runtime" ON)
|
||||
mark_as_advanced(WITH_CUDA_DYNLOAD)
|
||||
|
||||
# Draw Manager
|
||||
option(WITH_DRAW_DEBUG "Add extra debug capabilities to Draw Manager" OFF)
|
||||
mark_as_advanced(WITH_DRAW_DEBUG)
|
||||
|
||||
# LLVM
|
||||
option(WITH_LLVM "Use LLVM" OFF)
|
||||
if(APPLE)
|
||||
@@ -475,32 +493,15 @@ endif()
|
||||
|
||||
# OpenGL
|
||||
|
||||
if(UNIX AND NOT APPLE)
|
||||
# GLEW can only built with either GLX or EGL support and most binary
|
||||
# distributions are built with GLX support. So we always compile GLEW
|
||||
# with EGL support manually, and the options are no longer available.
|
||||
set(WITH_SYSTEM_GLEW OFF)
|
||||
set(WITH_SYSTEM_GLES ON)
|
||||
|
||||
# Always use EGL instead of GLX, for X11, Wayland and headless.
|
||||
set(WITH_GL_EGL ON)
|
||||
else()
|
||||
# System GLEW and GLES were never an option on other platforms.
|
||||
set(WITH_SYSTEM_GLEW OFF)
|
||||
set(WITH_SYSTEM_GLES OFF)
|
||||
|
||||
# Experimental EGL option.
|
||||
option(WITH_GL_EGL "Use the EGL OpenGL system library instead of the platform specific OpenGL system library (CGL or WGL)" OFF)
|
||||
mark_as_advanced(WITH_GL_EGL)
|
||||
endif()
|
||||
|
||||
option(WITH_OPENGL "When off limits visibility of the opengl headers to just bf_gpu and gawain (temporary option for development purposes)" ON)
|
||||
option(WITH_GLEW_ES "Switches to experimental copy of GLEW that has support for OpenGL ES. (temporary option for development purposes)" OFF)
|
||||
option(WITH_GL_EGL "Use the EGL OpenGL system library instead of the platform specific OpenGL system library (CGL, glX, or WGL)" OFF)
|
||||
option(WITH_GL_PROFILE_ES20 "Support using OpenGL ES 2.0. (through either EGL or the AGL/WGL/XGL 'es20' profile)" OFF)
|
||||
|
||||
mark_as_advanced(
|
||||
WITH_OPENGL
|
||||
WITH_GLEW_ES
|
||||
WITH_GL_EGL
|
||||
WITH_GL_PROFILE_ES20
|
||||
)
|
||||
|
||||
@@ -611,12 +612,6 @@ if(WIN32)
|
||||
option(WITH_WINDOWS_FIND_MODULES "Use find_package to locate libraries" OFF)
|
||||
mark_as_advanced(WITH_WINDOWS_FIND_MODULES)
|
||||
|
||||
option(WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS "Organize the visual studio projects according to source folder structure." ON)
|
||||
mark_as_advanced(WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS)
|
||||
|
||||
option(WINDOWS_USE_VISUAL_STUDIO_SOURCE_FOLDERS "Organize the source files in filters matching the source folders." ON)
|
||||
mark_as_advanced(WINDOWS_USE_VISUAL_STUDIO_SOURCE_FOLDERS)
|
||||
|
||||
option(WINDOWS_PYTHON_DEBUG "Include the files needed for debugging python scripts with visual studio 2017+." OFF)
|
||||
mark_as_advanced(WINDOWS_PYTHON_DEBUG)
|
||||
|
||||
@@ -634,6 +629,18 @@ if(WIN32)
|
||||
|
||||
endif()
|
||||
|
||||
if(WIN32 OR XCODE)
|
||||
option(IDE_GROUP_SOURCES_IN_FOLDERS "Organize the source files in filters matching the source folders." ON)
|
||||
mark_as_advanced(IDE_GROUP_SOURCES_IN_FOLDERS)
|
||||
|
||||
option(IDE_GROUP_PROJECTS_IN_FOLDERS "Organize the projects according to source folder structure." ON)
|
||||
mark_as_advanced(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
|
||||
if (IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# See WITH_WINDOWS_SCCACHE for Windows.
|
||||
option(WITH_COMPILER_CCACHE "Use ccache to improve rebuild times (Works with Ninja, Makefiles and Xcode)" OFF)
|
||||
|
34
GNUmakefile
34
GNUmakefile
@@ -63,7 +63,7 @@ Package Targets
|
||||
|
||||
* package_debian: Build a debian package.
|
||||
* package_pacman: Build an arch linux pacman package.
|
||||
* package_archive: Build an archive package.
|
||||
* package_archive: Build an archive package.
|
||||
|
||||
Testing Targets
|
||||
Not associated with building Blender.
|
||||
@@ -167,7 +167,7 @@ endef
|
||||
|
||||
# This makefile is not meant for Windows
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(error On Windows, use "cmd //c make.bat" instead of "make")
|
||||
$(error On Windows, use "cmd //c make.bat" instead of "make")
|
||||
endif
|
||||
|
||||
# System Vars
|
||||
@@ -379,7 +379,7 @@ deps: .FORCE
|
||||
|
||||
@cmake -H"$(DEPS_SOURCE_DIR)" \
|
||||
-B"$(DEPS_BUILD_DIR)" \
|
||||
-DHARVEST_TARGET=$(DEPS_INSTALL_DIR)
|
||||
-DHARVEST_TARGET=$(DEPS_INSTALL_DIR)
|
||||
|
||||
@echo
|
||||
@echo Building dependencies ...
|
||||
@@ -456,7 +456,8 @@ project_eclipse: .FORCE
|
||||
check_cppcheck: .FORCE
|
||||
$(CMAKE_CONFIG)
|
||||
cd "$(BUILD_DIR)" ; \
|
||||
$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py" 2> \
|
||||
$(PYTHON) \
|
||||
"$(BLENDER_DIR)/build_files/cmake/cmake_static_check_cppcheck.py" 2> \
|
||||
"$(BLENDER_DIR)/check_cppcheck.txt"
|
||||
@echo "written: check_cppcheck.txt"
|
||||
|
||||
@@ -518,8 +519,9 @@ source_archive: .FORCE
|
||||
python3 ./build_files/utils/make_source_archive.py
|
||||
|
||||
source_archive_complete: .FORCE
|
||||
cmake -S "$(BLENDER_DIR)/build_files/build_environment" -B"$(BUILD_DIR)/source_archive" \
|
||||
-DCMAKE_BUILD_TYPE_INIT:STRING=$(BUILD_TYPE) -DPACKAGE_USE_UPSTREAM_SOURCES=OFF
|
||||
cmake \
|
||||
-S "$(BLENDER_DIR)/build_files/build_environment" -B"$(BUILD_DIR)/source_archive" \
|
||||
-DCMAKE_BUILD_TYPE_INIT:STRING=$(BUILD_TYPE) -DPACKAGE_USE_UPSTREAM_SOURCES=OFF
|
||||
# This assumes CMake is still using a default `PACKAGE_DIR` variable:
|
||||
python3 ./build_files/utils/make_source_archive.py --include-packages "$(BUILD_DIR)/source_archive/packages"
|
||||
|
||||
@@ -527,9 +529,11 @@ source_archive_complete: .FORCE
|
||||
INKSCAPE_BIN?="inkscape"
|
||||
icons: .FORCE
|
||||
BLENDER_BIN=$(BLENDER_BIN) INKSCAPE_BIN=$(INKSCAPE_BIN) \
|
||||
"$(BLENDER_DIR)/release/datafiles/blender_icons_update.py"
|
||||
BLENDER_BIN=$(BLENDER_BIN) INKSCAPE_BIN=$(INKSCAPE_BIN) \
|
||||
"$(BLENDER_DIR)/release/datafiles/prvicons_update.py"
|
||||
"$(BLENDER_DIR)/release/datafiles/blender_icons_update.py"
|
||||
INKSCAPE_BIN=$(INKSCAPE_BIN) \
|
||||
"$(BLENDER_DIR)/release/datafiles/prvicons_update.py"
|
||||
INKSCAPE_BIN=$(INKSCAPE_BIN) \
|
||||
"$(BLENDER_DIR)/release/datafiles/alert_icons_update.py"
|
||||
|
||||
icons_geom: .FORCE
|
||||
BLENDER_BIN=$(BLENDER_BIN) \
|
||||
@@ -543,7 +547,7 @@ update_code: .FORCE
|
||||
|
||||
format: .FORCE
|
||||
PATH="../lib/${OS_NCASE}_${CPU}/llvm/bin/:../lib/${OS_NCASE}_centos7_${CPU}/llvm/bin/:../lib/${OS_NCASE}/llvm/bin/:$(PATH)" \
|
||||
$(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
|
||||
$(PYTHON) source/tools/utils_maintenance/clang_format_paths.py $(PATHS)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -553,8 +557,9 @@ format: .FORCE
|
||||
# Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation.
|
||||
doc_py: .FORCE
|
||||
ASAN_OPTIONS=halt_on_error=0:${ASAN_OPTIONS} \
|
||||
$(BLENDER_BIN) --background -noaudio --factory-startup \
|
||||
--python doc/python_api/sphinx_doc_gen.py
|
||||
$(BLENDER_BIN) \
|
||||
--background -noaudio --factory-startup \
|
||||
--python doc/python_api/sphinx_doc_gen.py
|
||||
sphinx-build -b html -j $(NPROCS) doc/python_api/sphinx-in doc/python_api/sphinx-out
|
||||
@echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/index.html'"
|
||||
|
||||
@@ -563,8 +568,9 @@ doc_doxy: .FORCE
|
||||
@echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'"
|
||||
|
||||
doc_dna: .FORCE
|
||||
$(BLENDER_BIN) --background -noaudio --factory-startup \
|
||||
--python doc/blender_file_format/BlendFileDnaExporter_25.py
|
||||
$(BLENDER_BIN) \
|
||||
--background -noaudio --factory-startup \
|
||||
--python doc/blender_file_format/BlendFileDnaExporter_25.py
|
||||
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
|
||||
|
||||
doc_man: .FORCE
|
||||
|
@@ -84,7 +84,7 @@ include(cmake/openimageio.cmake)
|
||||
include(cmake/tiff.cmake)
|
||||
if(WIN32)
|
||||
include(cmake/flexbison.cmake)
|
||||
else()
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
include(cmake/flex.cmake)
|
||||
endif()
|
||||
include(cmake/osl.cmake)
|
||||
|
@@ -29,13 +29,13 @@ elseif(APPLE)
|
||||
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "arm64")
|
||||
set(ISPC_EXTRA_ARGS_APPLE
|
||||
-DBISON_EXECUTABLE=/opt/homebrew/opt/bison/bin/bison
|
||||
-DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
|
||||
-DFLEX_EXECUTABLE=/opt/homebrew/opt/flex/bin/flex
|
||||
-DARM_ENABLED=On
|
||||
)
|
||||
else()
|
||||
set(ISPC_EXTRA_ARGS_APPLE
|
||||
-DBISON_EXECUTABLE=/usr/local/opt/bison/bin/bison
|
||||
-DFLEX_EXECUTABLE=${LIBDIR}/flex/bin/flex
|
||||
-DFLEX_EXECUTABLE=/usr/local/opt/flex/bin/flex
|
||||
-DARM_ENABLED=Off
|
||||
)
|
||||
endif()
|
||||
@@ -84,7 +84,7 @@ if(WIN32)
|
||||
external_ispc
|
||||
external_flexbison
|
||||
)
|
||||
else()
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
add_dependencies(
|
||||
external_ispc
|
||||
external_flex
|
||||
|
@@ -16,12 +16,18 @@
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
if(APPLE)
|
||||
set(OPENMP_PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openmp/src/external_openmp < ${PATCH_DIR}/openmp.diff)
|
||||
else()
|
||||
set(OPENMP_PATCH_COMMAND)
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_openmp
|
||||
URL file://${PACKAGE_DIR}/${OPENMP_FILE}
|
||||
DOWNLOAD_DIR ${DOWNLOAD_DIR}
|
||||
URL_HASH ${OPENMP_HASH_TYPE}=${OPENMP_HASH}
|
||||
PREFIX ${BUILD_DIR}/openmp
|
||||
PATCH_COMMAND ${OPENMP_PATCH_COMMAND}
|
||||
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/openmp ${DEFAULT_CMAKE_FLAGS}
|
||||
INSTALL_COMMAND cd ${BUILD_DIR}/openmp/src/external_openmp-build && install_name_tool -id @rpath/libomp.dylib runtime/src/libomp.dylib && make install
|
||||
INSTALL_DIR ${LIBDIR}/openmp
|
||||
|
@@ -96,7 +96,7 @@ if(WIN32)
|
||||
external_osl
|
||||
external_flexbison
|
||||
)
|
||||
else()
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
add_dependencies(
|
||||
external_osl
|
||||
external_flex
|
||||
|
@@ -23,7 +23,7 @@ set(PNG_EXTRA_ARGS
|
||||
)
|
||||
|
||||
if(BLENDER_PLATFORM_ARM)
|
||||
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=ON -DCMAKE_SYSTEM_PROCESSOR="aarch64")
|
||||
set(PNG_EXTRA_ARGS ${PNG_EXTRA_ARGS} -DPNG_HARDWARE_OPTIMIZATIONS=ON -DPNG_ARM_NEON=on -DCMAKE_SYSTEM_PROCESSOR="aarch64")
|
||||
endif()
|
||||
|
||||
ExternalProject_Add(external_png
|
||||
|
@@ -158,10 +158,18 @@ set(LLVM_HASH 5a4fab4d7fc84aefffb118ac2c8a4fc0)
|
||||
set(LLVM_HASH_TYPE MD5)
|
||||
set(LLVM_FILE llvm-project-${LLVM_VERSION}.src.tar.xz)
|
||||
|
||||
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${LLVM_VERSION}/openmp-${LLVM_VERSION}.src.tar.xz)
|
||||
set(OPENMP_HASH ac48ce3e4582ccb82f81ab59eb3fc9dc)
|
||||
if(APPLE)
|
||||
# Cloth physics test is crashing due to this bug:
|
||||
# https://bugs.llvm.org/show_bug.cgi?id=50579
|
||||
set(OPENMP_VERSION 9.0.1)
|
||||
set(OPENMP_HASH 6eade16057edbdecb3c4eef9daa2bfcf)
|
||||
else()
|
||||
set(OPENMP_VERSION ${LLVM_VERSION})
|
||||
set(OPENMP_HASH ac48ce3e4582ccb82f81ab59eb3fc9dc)
|
||||
endif()
|
||||
set(OPENMP_URI https://github.com/llvm/llvm-project/releases/download/llvmorg-${OPENMP_VERSION}/openmp-${OPENMP_VERSION}.src.tar.xz)
|
||||
set(OPENMP_HASH_TYPE MD5)
|
||||
set(OPENMP_FILE openmp-${LLVM_VERSION}.src.tar.xz)
|
||||
set(OPENMP_FILE openmp-${OPENMP_VERSION}.src.tar.xz)
|
||||
|
||||
set(OPENIMAGEIO_VERSION 2.2.15.1)
|
||||
set(OPENIMAGEIO_URI https://github.com/OpenImageIO/oiio/archive/Release-${OPENIMAGEIO_VERSION}.tar.gz)
|
||||
|
@@ -603,6 +603,9 @@ MP3LAME_DEV=""
|
||||
OPENJPEG_USE=false
|
||||
OPENJPEG_DEV=""
|
||||
|
||||
# Whether to use system GLEW or not (OpenSubDiv needs recent glew to work).
|
||||
NO_SYSTEM_GLEW=false
|
||||
|
||||
# Switch to english language, else some things (like check_package_DEB()) won't work!
|
||||
LANG_BACK=$LANG
|
||||
LANG=""
|
||||
@@ -1016,7 +1019,7 @@ PRINT ""
|
||||
PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" )
|
||||
|
||||
_boost_version_nodots=`echo "$BOOST_VERSION" | sed -r 's/\./_/g'`
|
||||
BOOST_SOURCE=( "https://dl.bintray.com/boostorg/release/$BOOST_VERSION/source/boost_$_boost_version_nodots.tar.bz2" )
|
||||
BOOST_SOURCE=( "https://boostorg.jfrog.io/artifactory/main/release/$BOOST_VERSION/source/boost_$_boost_version_nodots.tar.bz2" )
|
||||
BOOST_BUILD_MODULES="--with-system --with-filesystem --with-thread --with-regex --with-locale --with-date_time --with-wave --with-iostreams --with-python --with-program_options --with-serialization --with-atomic"
|
||||
|
||||
TBB_SOURCE=( "https://github.com/oneapi-src/oneTBB/archive/$TBB_VERSION$TBB_VERSION_UPDATE.tar.gz" )
|
||||
@@ -1444,9 +1447,7 @@ compile_Python() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "Python--$PYTHON_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1462,6 +1463,9 @@ compile_Python() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-python option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "python-$PYTHON_VERSION_SHORT"
|
||||
|
||||
# Extra step: install required modules with pip.
|
||||
@@ -1555,9 +1559,7 @@ compile_Boost() {
|
||||
--prefix=$_inst --disable-icu boost.locale.icu=off install
|
||||
./b2 --clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "Boost-$BOOST_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1571,7 +1573,9 @@ compile_Boost() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-boost option."
|
||||
fi
|
||||
|
||||
# Just always run it, much simpler this way!
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "boost"
|
||||
}
|
||||
|
||||
@@ -1684,9 +1688,7 @@ compile_TBB() {
|
||||
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "TBB-$TBB_VERSION$TBB_VERSION_UPDATE failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1700,6 +1702,9 @@ compile_TBB() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-tbb option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "tbb"
|
||||
}
|
||||
|
||||
@@ -1819,9 +1824,7 @@ compile_OCIO() {
|
||||
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenColorIO-$OCIO_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1835,6 +1838,9 @@ compile_OCIO() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-ocio option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "ocio"
|
||||
}
|
||||
|
||||
@@ -1950,9 +1956,7 @@ compile_OPENEXR() {
|
||||
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenEXR-$OPENEXR_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -1968,7 +1972,9 @@ compile_OPENEXR() {
|
||||
|
||||
_with_built_openexr=true
|
||||
|
||||
# Just always run it, much simpler this way!
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "openexr"
|
||||
}
|
||||
|
||||
@@ -2109,9 +2115,7 @@ compile_OIIO() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenImageIO-$OIIO_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2125,7 +2129,9 @@ compile_OIIO() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-oiio option."
|
||||
fi
|
||||
|
||||
# Just always run it, much simpler this way!
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "oiio"
|
||||
}
|
||||
|
||||
@@ -2234,9 +2240,7 @@ compile_LLVM() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "LLVM-$LLVM_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2249,6 +2253,10 @@ compile_LLVM() {
|
||||
INFO "Own LLVM-$LLVM_VERSION (CLANG included) is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-llvm option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -2387,9 +2395,7 @@ compile_OSL() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenShadingLanguage-$OSL_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2403,6 +2409,9 @@ compile_OSL() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-osl option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "osl"
|
||||
}
|
||||
|
||||
@@ -2503,9 +2512,7 @@ compile_OSD() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenSubdiv-$OSD_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2519,6 +2526,9 @@ compile_OSD() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-osd option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "osd"
|
||||
}
|
||||
|
||||
@@ -2608,9 +2618,7 @@ compile_BLOSC() {
|
||||
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "Blosc-$OPENVDB_BLOSC_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2623,6 +2631,9 @@ compile_BLOSC() {
|
||||
|
||||
magic_compile_set blosc-$OPENVDB_BLOSC_VERSION $blosc_magic
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "blosc"
|
||||
}
|
||||
|
||||
@@ -2713,9 +2724,7 @@ install_NanoVDB() {
|
||||
#~ mkdir -p $_inst
|
||||
#~ cp -r $_src/include $_inst/include
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "NanoVDB-v$OPENVDB_VERSION failed to install, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2727,6 +2736,10 @@ install_NanoVDB() {
|
||||
else
|
||||
INFO "Own NanoVDB-v$OPENVDB_VERSION is up to date, nothing to do!"
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -2846,9 +2859,7 @@ compile_OPENVDB() {
|
||||
make -j$THREADS install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenVDB-$OPENVDB_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2862,6 +2873,9 @@ compile_OPENVDB() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-openvdb option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "openvdb"
|
||||
|
||||
if [ "$WITH_NANOVDB" = true ]; then
|
||||
@@ -2959,9 +2973,7 @@ compile_ALEMBIC() {
|
||||
make -j$THREADS install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "Alembic-$ALEMBIC_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -2975,6 +2987,9 @@ compile_ALEMBIC() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-alembic option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "alembic"
|
||||
}
|
||||
|
||||
@@ -3059,9 +3074,7 @@ compile_USD() {
|
||||
make -j$THREADS install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "USD-$USD_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3075,6 +3088,9 @@ compile_USD() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-usd option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "usd"
|
||||
}
|
||||
|
||||
@@ -3168,9 +3184,7 @@ compile_OpenCOLLADA() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenCOLLADA-$OPENCOLLADA_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3183,6 +3197,10 @@ compile_OpenCOLLADA() {
|
||||
INFO "Own OpenCOLLADA-$OPENCOLLADA_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-opencollada option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -3283,9 +3301,7 @@ compile_Embree() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "Embree-$EMBREE_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3298,6 +3314,10 @@ compile_Embree() {
|
||||
INFO "Own Embree-$EMBREE_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-embree option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -3360,9 +3380,7 @@ install_ISPC() {
|
||||
mkdir -p $_inst
|
||||
cp -r $_src/bin $_inst/bin
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "ISPC-v$ISPC_VERSION failed to install, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3375,6 +3393,10 @@ install_ISPC() {
|
||||
INFO "Own ISPC-v$ISPC_VERSION is up to date, nothing to do!"
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
|
||||
_ispc_path_bin=$_inst/bin
|
||||
run_ldconfig "ispc"
|
||||
}
|
||||
@@ -3474,9 +3496,7 @@ compile_OIDN() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "OpenImageDenoise-$OIDN_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3490,6 +3510,9 @@ compile_OIDN() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-oidn option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "oidn"
|
||||
}
|
||||
|
||||
@@ -3606,9 +3629,7 @@ compile_FFmpeg() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "FFmpeg-$FFMPEG_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3621,6 +3642,10 @@ compile_FFmpeg() {
|
||||
INFO "Own ffmpeg-$FFMPEG_VERSION is up to date, nothing to do!"
|
||||
INFO "If you want to force rebuild of this lib, use the --force-ffmpeg option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
@@ -3719,9 +3744,7 @@ compile_XR_OpenXR_SDK() {
|
||||
make -j$THREADS && make install
|
||||
make clean
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
else
|
||||
if [ ! -d $_inst ]; then
|
||||
ERROR "XR-OpenXR-SDK-$XR_OPENXR_VERSION failed to compile, exiting"
|
||||
exit 1
|
||||
fi
|
||||
@@ -3735,6 +3758,9 @@ compile_XR_OpenXR_SDK() {
|
||||
INFO "If you want to force rebuild of this lib, use the --force-xr-openxr option."
|
||||
fi
|
||||
|
||||
if [ -d $_inst ]; then
|
||||
_create_inst_shortcut
|
||||
fi
|
||||
run_ldconfig "xr-openxr-sdk"
|
||||
}
|
||||
|
||||
@@ -3982,9 +4008,13 @@ install_DEB() {
|
||||
version_ge $_glew "1.7.0"
|
||||
if [ $? -eq 1 ]; then
|
||||
WARNING "OpenSubdiv disabled because GLEW-$_glew is not enough"
|
||||
WARNING "Blender will not use system GLEW library"
|
||||
OSD_SKIP=true
|
||||
NO_SYSTEM_GLEW=true
|
||||
else
|
||||
WARNING "OpenSubdiv will compile with GLEW-$_glew but with limited capability"
|
||||
WARNING "Blender will not use system GLEW library"
|
||||
NO_SYSTEM_GLEW=true
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -5955,6 +5985,12 @@ print_info() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$NO_SYSTEM_GLEW" = true ]; then
|
||||
_1="-D WITH_SYSTEM_GLEW=OFF"
|
||||
PRINT " $_1"
|
||||
_buildargs="$_buildargs $_1"
|
||||
fi
|
||||
|
||||
if [ "$FFMPEG_SKIP" = false ]; then
|
||||
_1="-D WITH_CODEC_FFMPEG=ON"
|
||||
_2="-D FFMPEG_LIBRARIES='avformat;avcodec;avutil;avdevice;swscale;swresample;lzma;rt;`print_info_ffmpeglink`'"
|
||||
|
23
build_files/build_environment/patches/openmp.diff
Normal file
23
build_files/build_environment/patches/openmp.diff
Normal file
@@ -0,0 +1,23 @@
|
||||
diff --git a/runtime/src/z_Linux_asm.S b/runtime/src/z_Linux_asm.S
|
||||
index 0d8885e..42aa5ad 100644
|
||||
--- a/runtime/src/z_Linux_asm.S
|
||||
+++ b/runtime/src/z_Linux_asm.S
|
||||
@@ -1540,10 +1540,12 @@ __kmp_unnamed_critical_addr:
|
||||
.comm .gomp_critical_user_,32,8
|
||||
.data
|
||||
.align 8
|
||||
- .global __kmp_unnamed_critical_addr
|
||||
-__kmp_unnamed_critical_addr:
|
||||
+ .global ___kmp_unnamed_critical_addr
|
||||
+___kmp_unnamed_critical_addr:
|
||||
.8byte .gomp_critical_user_
|
||||
- .size __kmp_unnamed_critical_addr,8
|
||||
+# if !(KMP_OS_DARWIN)
|
||||
+ .size ___kmp_unnamed_critical_addr,8
|
||||
+# endif
|
||||
#endif /* KMP_ARCH_PPC64 || KMP_ARCH_AARCH64 */
|
||||
|
||||
#if KMP_OS_LINUX
|
||||
|
||||
|
||||
|
66
build_files/cmake/Modules/FindZstd.cmake
Normal file
66
build_files/cmake/Modules/FindZstd.cmake
Normal file
@@ -0,0 +1,66 @@
|
||||
# - Find Zstd library
|
||||
# Find the native Zstd includes and library
|
||||
# This module defines
|
||||
# ZSTD_INCLUDE_DIRS, where to find zstd.h, Set when
|
||||
# ZSTD_INCLUDE_DIR is found.
|
||||
# ZSTD_LIBRARIES, libraries to link against to use Zstd.
|
||||
# ZSTD_ROOT_DIR, The base directory to search for Zstd.
|
||||
# This can also be an environment variable.
|
||||
# ZSTD_FOUND, If false, do not try to use Zstd.
|
||||
#
|
||||
# also defined, but not for general use are
|
||||
# ZSTD_LIBRARY, where to find the Zstd library.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2019 Blender Foundation.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
# If ZSTD_ROOT_DIR was defined in the environment, use it.
|
||||
IF(NOT ZSTD_ROOT_DIR AND NOT $ENV{ZSTD_ROOT_DIR} STREQUAL "")
|
||||
SET(ZSTD_ROOT_DIR $ENV{ZSTD_ROOT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(_zstd_SEARCH_DIRS
|
||||
${ZSTD_ROOT_DIR}
|
||||
)
|
||||
|
||||
FIND_PATH(ZSTD_INCLUDE_DIR
|
||||
NAMES
|
||||
zstd.h
|
||||
HINTS
|
||||
${_zstd_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
include
|
||||
)
|
||||
|
||||
FIND_LIBRARY(ZSTD_LIBRARY
|
||||
NAMES
|
||||
zstd
|
||||
HINTS
|
||||
${_zstd_SEARCH_DIRS}
|
||||
PATH_SUFFIXES
|
||||
lib64 lib
|
||||
)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set ZSTD_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Zstd DEFAULT_MSG
|
||||
ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
|
||||
|
||||
IF(ZSTD_FOUND)
|
||||
SET(ZSTD_LIBRARIES ${ZSTD_LIBRARY})
|
||||
SET(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR})
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
ZSTD_INCLUDE_DIR
|
||||
ZSTD_LIBRARY
|
||||
)
|
@@ -208,7 +208,7 @@ function(blender_source_group
|
||||
)
|
||||
|
||||
# if enabled, use the sources directories as filters.
|
||||
if(WINDOWS_USE_VISUAL_STUDIO_SOURCE_FOLDERS)
|
||||
if(IDE_GROUP_SOURCES_IN_FOLDERS)
|
||||
foreach(_SRC ${sources})
|
||||
# remove ../'s
|
||||
get_filename_component(_SRC_DIR ${_SRC} REALPATH)
|
||||
@@ -240,8 +240,8 @@ function(blender_source_group
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# if enabled, set the FOLDER property for visual studio projects
|
||||
if(WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS)
|
||||
# if enabled, set the FOLDER property for the projects
|
||||
if(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
get_filename_component(FolderDir ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
|
||||
string(REPLACE ${CMAKE_SOURCE_DIR} "" FolderDir ${FolderDir})
|
||||
set_target_properties(${name} PROPERTIES FOLDER ${FolderDir})
|
||||
|
@@ -411,25 +411,9 @@ if(WITH_OPENMP)
|
||||
set(OPENMP_FOUND ON)
|
||||
set(OpenMP_C_FLAGS "-Xclang -fopenmp -I'${LIBDIR}/openmp/include'")
|
||||
set(OpenMP_CXX_FLAGS "-Xclang -fopenmp -I'${LIBDIR}/openmp/include'")
|
||||
set(OpenMP_LINKER_FLAGS "-L'${LIBDIR}/openmp/lib' -lomp")
|
||||
|
||||
# Copy libomp.dylib to allow executables like datatoc and tests to work.
|
||||
# `@executable_path/../Resources/lib/` `LC_ID_DYLIB` is added by the deps builder.
|
||||
# For single config generator datatoc, tests etc.
|
||||
execute_process(
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/Resources/lib
|
||||
COMMAND cp -p ${LIBDIR}/openmp/lib/libomp.dylib ${CMAKE_BINARY_DIR}/Resources/lib/libomp.dylib
|
||||
)
|
||||
# For multi-config generator datatoc, etc.
|
||||
execute_process(
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/bin/Resources/lib
|
||||
COMMAND cp -p ${LIBDIR}/openmp/lib/libomp.dylib ${CMAKE_BINARY_DIR}/bin/Resources/lib/libomp.dylib
|
||||
)
|
||||
# For multi-config generator tests.
|
||||
execute_process(
|
||||
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/bin/tests/Resources/lib
|
||||
COMMAND cp -p ${LIBDIR}/openmp/lib/libomp.dylib ${CMAKE_BINARY_DIR}/bin/tests/Resources/lib/libomp.dylib
|
||||
)
|
||||
set(OpenMP_LIBRARY_DIR "${LIBDIR}/openmp/lib/")
|
||||
set(OpenMP_LINKER_FLAGS "-L'${OpenMP_LIBRARY_DIR}' -lomp")
|
||||
set(OpenMP_LIBRARY "${OpenMP_LIBRARY_DIR}/libomp.dylib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -457,6 +441,9 @@ if(WITH_HARU)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ZSTD_ROOT_DIR ${LIBDIR}/zstd)
|
||||
find_package(Zstd REQUIRED)
|
||||
|
||||
if(EXISTS ${LIBDIR})
|
||||
without_system_libs_end()
|
||||
endif()
|
||||
@@ -511,3 +498,15 @@ if(WITH_COMPILER_CCACHE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# For binaries that are built but not installed (also not distributed) (datatoc,
|
||||
# makesdna, tests, etc.), we add an rpath to the OpenMP library dir through
|
||||
# CMAKE_BUILD_RPATH. This avoids having to make many copies of the dylib next to each binary.
|
||||
#
|
||||
# For the installed Python module and installed Blender executable, CMAKE_INSTALL_RPATH
|
||||
# is modified to find the dylib in an adjacent folder. Install step puts the libraries there.
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
list(APPEND CMAKE_BUILD_RPATH "${OpenMP_LIBRARY_DIR}")
|
||||
|
||||
set(CMAKE_SKIP_INSTALL_RPATH FALSE)
|
||||
list(APPEND CMAKE_INSTALL_RPATH "@loader_path/../Resources/${BLENDER_VERSION}/lib")
|
||||
|
@@ -99,6 +99,7 @@ endif()
|
||||
find_package_wrapper(JPEG REQUIRED)
|
||||
find_package_wrapper(PNG REQUIRED)
|
||||
find_package_wrapper(ZLIB REQUIRED)
|
||||
find_package_wrapper(Zstd REQUIRED)
|
||||
find_package_wrapper(Freetype REQUIRED)
|
||||
|
||||
if(WITH_PYTHON)
|
||||
@@ -581,6 +582,8 @@ if(WITH_GHOST_WAYLAND)
|
||||
pkg_check_modules(wayland-cursor REQUIRED wayland-cursor)
|
||||
pkg_check_modules(dbus REQUIRED dbus-1)
|
||||
|
||||
set(WITH_GL_EGL ON)
|
||||
|
||||
list(APPEND PLATFORM_LINKLIBS
|
||||
${wayland-client_LINK_LIBRARIES}
|
||||
${wayland-egl_LINK_LIBRARIES}
|
||||
|
@@ -57,8 +57,6 @@ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ${WINDOWS_USE_VISUAL_STUDIO_PROJECT_FOLDERS})
|
||||
|
||||
if(NOT WITH_PYTHON_MODULE)
|
||||
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT blender)
|
||||
endif()
|
||||
@@ -217,8 +215,8 @@ else()
|
||||
endif()
|
||||
|
||||
if(WITH_WINDOWS_PDB)
|
||||
set(PDB_INFO_OVERRIDE_FLAGS "${SYMBOL_FORMAT_RELEASE}")
|
||||
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
|
||||
set(PDB_INFO_OVERRIDE_FLAGS "${SYMBOL_FORMAT_RELEASE}")
|
||||
set(PDB_INFO_OVERRIDE_LINKER_FLAGS "/DEBUG /OPT:REF /OPT:ICF /INCREMENTAL:NO")
|
||||
endif()
|
||||
|
||||
string(APPEND CMAKE_CXX_FLAGS_DEBUG " /MDd ${SYMBOL_FORMAT}")
|
||||
@@ -875,3 +873,6 @@ if(WITH_HARU)
|
||||
set(WITH_HARU OFF)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(ZSTD_INCLUDE_DIRS ${LIBDIR}/zstd/include)
|
||||
set(ZSTD_LIBRARIES ${LIBDIR}/zstd/lib/zstd_static.lib)
|
||||
|
@@ -1,11 +1,10 @@
|
||||
Pipeline Config
|
||||
===============
|
||||
|
||||
This configuration file is used by buildbot new build pipeline for the `update-code` step.
|
||||
The `yaml` configuration file is used by buildbot build pipeline `update-code` step.
|
||||
|
||||
It will also be used by the `../utils/make_update.py` script in the near future.
|
||||
The file allows to set branches or specific commits for both git submodules and svn artifacts. Can also define various build package versions for use by build workers. Especially useful in experimental and release branches.
|
||||
|
||||
NOTES:
|
||||
* Keep both `yaml` and `json` files in sync until deployment of build pipeline updates.
|
||||
* The `json` file be removed once all branches are running with the `yaml` file.
|
||||
* Expected buildbot pipeline update is *Friday, July 30th* or *Monday August, 2nd*.
|
||||
NOTE:
|
||||
* The configuration file is ```NOT``` used by the `../utils/make_update.py` script.
|
||||
* That will implemented in the future.
|
||||
|
@@ -1,87 +0,0 @@
|
||||
{
|
||||
"update-code":
|
||||
{
|
||||
"git" :
|
||||
{
|
||||
"submodules":
|
||||
[
|
||||
{ "path": "release/scripts/addons", "branch": "master", "commit_id": "HEAD" },
|
||||
{ "path": "release/scripts/addons_contrib", "branch": "master", "commit_id": "HEAD" },
|
||||
{ "path": "release/datafiles/locale", "branch": "master", "commit_id": "HEAD" },
|
||||
{ "path": "source/tools", "branch": "master", "commit_id": "HEAD" }
|
||||
]
|
||||
},
|
||||
"svn":
|
||||
{
|
||||
"tests": { "path": "lib/tests", "branch": "trunk", "commit_id": "HEAD" },
|
||||
"libraries":
|
||||
{
|
||||
"darwin-x86_64": { "path": "lib/darwin", "branch": "trunk", "commit_id": "HEAD" },
|
||||
"darwin-arm64": { "path": "lib/darwin_arm64", "branch": "trunk", "commit_id": "HEAD" },
|
||||
"linux-x86_64": { "path": "lib/linux_centos7_x86_64", "branch": "trunk", "commit_id": "HEAD" },
|
||||
"windows-amd64": { "path": "lib/win64_vc15", "branch": "trunk", "commit_id": "HEAD" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"buildbot":
|
||||
{
|
||||
"gcc":
|
||||
{
|
||||
"version": "9.0"
|
||||
},
|
||||
"sdks":
|
||||
{
|
||||
"optix":
|
||||
{
|
||||
"version": "7.1.0"
|
||||
},
|
||||
"cuda10":
|
||||
{
|
||||
"version": "10.1"
|
||||
},
|
||||
"cuda11":
|
||||
{
|
||||
"version": "11.4"
|
||||
}
|
||||
},
|
||||
"cmake":
|
||||
{
|
||||
"default":
|
||||
{
|
||||
"version": "any",
|
||||
"overrides":
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
"darwin-x86_64":
|
||||
{
|
||||
"overrides":
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
"darwin-arm64":
|
||||
{
|
||||
"overrides":
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
"linux-x86_64":
|
||||
{
|
||||
"overrides":
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
"windows-amd64":
|
||||
{
|
||||
"overrides":
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
build_files/windows/doc_py.cmd
Normal file
34
build_files/windows/doc_py.cmd
Normal file
@@ -0,0 +1,34 @@
|
||||
set SOURCEDIR=%BLENDER_DIR%/doc/python_api/sphinx-in
|
||||
set BUILDDIR=%BLENDER_DIR%/doc/python_api/sphinx-out
|
||||
if "%BF_LANG%" == "" set BF_LANG=en
|
||||
set SPHINXOPTS=-j auto -D language=%BF_LANG%
|
||||
|
||||
call "%~dp0\find_sphinx.cmd"
|
||||
|
||||
if EXIST "%SPHINX_BIN%" (
|
||||
goto detect_sphinx_done
|
||||
)
|
||||
|
||||
echo unable to locate sphinx-build, run "set sphinx_BIN=full_path_to_sphinx-build.exe"
|
||||
exit /b 1
|
||||
|
||||
:detect_sphinx_done
|
||||
|
||||
call "%~dp0\find_blender.cmd"
|
||||
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
echo unable to locate blender, run "set BLENDER_BIN=full_path_to_blender.exe"
|
||||
exit /b 1
|
||||
|
||||
:detect_blender_done
|
||||
|
||||
%BLENDER_BIN% ^
|
||||
--background -noaudio --factory-startup ^
|
||||
--python %BLENDER_DIR%/doc/python_api/sphinx_doc_gen.py
|
||||
|
||||
"%SPHINX_BIN%" -b html %SPHINXOPTS% %O% %SOURCEDIR% %BUILDDIR%
|
||||
|
||||
:EOF
|
28
build_files/windows/find_blender.cmd
Normal file
28
build_files/windows/find_blender.cmd
Normal file
@@ -0,0 +1,28 @@
|
||||
REM First see if there is an environment variable set
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
REM Check the build folder next, if ninja was used there will be no
|
||||
REM debug/release folder
|
||||
set BLENDER_BIN=%BUILD_DIR%\bin\blender.exe
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
REM Check the release folder next
|
||||
set BLENDER_BIN=%BUILD_DIR%\bin\release\blender.exe
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
REM Check the debug folder next
|
||||
set BLENDER_BIN=%BUILD_DIR%\bin\debug\blender.exe
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
REM at this point, we don't know where blender is, clear the variable
|
||||
set BLENDER_BIN=
|
||||
|
||||
:detect_blender_done
|
21
build_files/windows/find_inkscape.cmd
Normal file
21
build_files/windows/find_inkscape.cmd
Normal file
@@ -0,0 +1,21 @@
|
||||
REM First see if there is an environment variable set
|
||||
if EXIST "%INKSCAPE_BIN%" (
|
||||
goto detect_inkscape_done
|
||||
)
|
||||
|
||||
REM Then see if inkscape is available in the path
|
||||
for %%X in (inkscape.exe) do (set INKSCAPE_BIN=%%~$PATH:X)
|
||||
if EXIST "%INKSCAPE_BIN%" (
|
||||
goto detect_inkscape_done
|
||||
)
|
||||
|
||||
REM Finally see if it is perhaps installed at the default location
|
||||
set INKSCAPE_BIN=%ProgramFiles%\Inkscape\bin\inkscape.exe
|
||||
if EXIST "%INKSCAPE_BIN%" (
|
||||
goto detect_inkscape_done
|
||||
)
|
||||
|
||||
REM If still not found clear the variable
|
||||
set INKSCAPE_BIN=
|
||||
|
||||
:detect_inkscape_done
|
23
build_files/windows/find_sphinx.cmd
Normal file
23
build_files/windows/find_sphinx.cmd
Normal file
@@ -0,0 +1,23 @@
|
||||
REM First see if there is an environment variable set
|
||||
if EXIST "%SPHINX_BIN%" (
|
||||
goto detect_sphinx_done
|
||||
)
|
||||
|
||||
REM Then see if inkscape is available in the path
|
||||
for %%X in (sphinx-build.exe) do (set SPHINX_BIN=%%~$PATH:X)
|
||||
if EXIST "%SPHINX_BIN%" (
|
||||
goto detect_sphinx_done
|
||||
)
|
||||
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINX_BIN environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
|
||||
REM If still not found clear the variable
|
||||
set SPHINX_BIN=
|
||||
|
||||
:detect_sphinx_done
|
42
build_files/windows/icons.cmd
Normal file
42
build_files/windows/icons.cmd
Normal file
@@ -0,0 +1,42 @@
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
echo python not found at %PYTHON%
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
echo found python (%PYTHON%)
|
||||
|
||||
call "%~dp0\find_inkscape.cmd"
|
||||
|
||||
if EXIST "%INKSCAPE_BIN%" (
|
||||
goto detect_inkscape_done
|
||||
)
|
||||
|
||||
echo unable to locate inkscape, run "set inkscape_BIN=full_path_to_inkscape.exe"
|
||||
exit /b 1
|
||||
|
||||
:detect_inkscape_done
|
||||
|
||||
call "%~dp0\find_blender.cmd"
|
||||
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
echo unable to locate blender, run "set BLENDER_BIN=full_path_to_blender.exe"
|
||||
exit /b 1
|
||||
|
||||
:detect_blender_done
|
||||
|
||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\blender_icons_update.py
|
||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\prvicons_update.py
|
||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\alert_icons_update.py
|
||||
|
||||
:EOF
|
29
build_files/windows/icons_geom.cmd
Normal file
29
build_files/windows/icons_geom.cmd
Normal file
@@ -0,0 +1,29 @@
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
set PYTHON=%BLENDER_DIR%\..\lib\win64_vc15\python\39\bin\python.exe
|
||||
if EXIST %PYTHON% (
|
||||
goto detect_python_done
|
||||
)
|
||||
|
||||
echo python not found at %PYTHON%
|
||||
exit /b 1
|
||||
|
||||
:detect_python_done
|
||||
echo found python (%PYTHON%)
|
||||
|
||||
call "%~dp0\find_blender.cmd"
|
||||
|
||||
if EXIST "%BLENDER_BIN%" (
|
||||
goto detect_blender_done
|
||||
)
|
||||
|
||||
echo unable to locate blender, run "set BLENDER_BIN=full_path_to_blender.exe"
|
||||
exit /b 1
|
||||
|
||||
:detect_blender_done
|
||||
|
||||
%PYTHON% -B %BLENDER_DIR%\release\datafiles\blender_icons_geom_update.py
|
||||
|
||||
:EOF
|
@@ -107,6 +107,15 @@ if NOT "%1" == "" (
|
||||
set FORMAT=1
|
||||
set FORMAT_ARGS=%2 %3 %4 %5 %6 %7 %8 %9
|
||||
goto EOF
|
||||
) else if "%1" == "icons" (
|
||||
set ICONS=1
|
||||
goto EOF
|
||||
) else if "%1" == "icons_geom" (
|
||||
set ICONS_GEOM=1
|
||||
goto EOF
|
||||
) else if "%1" == "doc_py" (
|
||||
set DOC_PY=1
|
||||
goto EOF
|
||||
) else (
|
||||
echo Command "%1" unknown, aborting!
|
||||
goto ERR
|
||||
|
@@ -31,3 +31,6 @@ set PYDEBUG_CMAKE_ARGS=
|
||||
set FORMAT=
|
||||
set TEST=
|
||||
set BUILD_WITH_SCCACHE=
|
||||
set ICONS=
|
||||
set ICONS_GEOM=
|
||||
set DOC_PY=
|
||||
|
@@ -31,6 +31,10 @@ echo - 2019 ^(build with visual studio 2019^)
|
||||
echo - 2019pre ^(build with visual studio 2019 pre-release^)
|
||||
echo - 2019b ^(build with visual studio 2019 Build Tools^)
|
||||
|
||||
echo.
|
||||
echo Documentation Targets ^(Not associated with building^)
|
||||
echo - doc_py ^(Generate sphinx python api docs^)
|
||||
|
||||
echo.
|
||||
echo Experimental options
|
||||
echo - with_opengl_tests ^(enable both the render and draw opengl test suites^)
|
||||
|
@@ -123,7 +123,7 @@ def Align(handle):
|
||||
class BlendFile:
|
||||
'''
|
||||
Reads a blendfile and store the header, all the fileblocks, and catalogue
|
||||
structs foound in the DNA fileblock
|
||||
structs found in the DNA fileblock
|
||||
|
||||
- BlendFile.Header (BlendFileHeader instance)
|
||||
- BlendFile.Blocks (list of BlendFileBlock instances)
|
||||
|
@@ -31,7 +31,8 @@ def draw():
|
||||
context.space_data,
|
||||
context.region,
|
||||
view_matrix,
|
||||
projection_matrix)
|
||||
projection_matrix,
|
||||
True)
|
||||
|
||||
gpu.state.depth_mask_set(False)
|
||||
draw_texture_2d(offscreen.texture_color, (10, 10), WIDTH, HEIGHT)
|
||||
|
@@ -254,6 +254,8 @@ else:
|
||||
"gpu.shader",
|
||||
"gpu.state",
|
||||
"gpu.texture",
|
||||
"gpu.platform",
|
||||
"gpu.capabilities",
|
||||
"gpu_extras",
|
||||
"idprop.types",
|
||||
"mathutils",
|
||||
@@ -1047,7 +1049,7 @@ context_type_map = {
|
||||
"annotation_data": ("GreasePencil", False),
|
||||
"annotation_data_owner": ("ID", False),
|
||||
"armature": ("Armature", False),
|
||||
"asset_library": ("AssetLibraryReference", False),
|
||||
"asset_library_ref": ("AssetLibraryReference", False),
|
||||
"bone": ("Bone", False),
|
||||
"brush": ("Brush", False),
|
||||
"camera": ("Camera", False),
|
||||
@@ -2000,6 +2002,8 @@ def write_rst_importable_modules(basepath):
|
||||
"gpu.shader": "GPU Shader Utilities",
|
||||
"gpu.state": "GPU State Utilities",
|
||||
"gpu.texture": "GPU Texture Utilities",
|
||||
"gpu.platform": "GPU Platform Utilities",
|
||||
"gpu.capabilities": "GPU Capabilities Utilities",
|
||||
"bmesh": "BMesh Module",
|
||||
"bmesh.ops": "BMesh Operators",
|
||||
"bmesh.types": "BMesh Types",
|
||||
|
2
extern/CMakeLists.txt
vendored
2
extern/CMakeLists.txt
vendored
@@ -111,5 +111,5 @@ if(WITH_MOD_FLUID)
|
||||
endif()
|
||||
|
||||
if (WITH_COMPOSITOR)
|
||||
add_subdirectory(smaa_areatex)
|
||||
add_subdirectory(smaa_areatex)
|
||||
endif()
|
||||
|
4
extern/audaspace/bindings/C/AUD_Special.cpp
vendored
4
extern/audaspace/bindings/C/AUD_Special.cpp
vendored
@@ -86,6 +86,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
|
||||
info.specs.channels = AUD_CHANNELS_INVALID;
|
||||
info.specs.rate = AUD_RATE_INVALID;
|
||||
info.length = 0.0f;
|
||||
info.start_offset = 0.0f;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -95,6 +96,7 @@ AUD_API AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
|
||||
{
|
||||
info.specs = convSpecToC(reader->getSpecs());
|
||||
info.length = reader->getLength() / (float) info.specs.rate;
|
||||
info.start_offset = reader->getStartOffset();
|
||||
}
|
||||
}
|
||||
catch(Exception&)
|
||||
@@ -245,7 +247,7 @@ AUD_API int AUD_readSound(AUD_Sound* sound, float* buffer, int length, int sampl
|
||||
|
||||
buffer[i * 3] = min;
|
||||
buffer[i * 3 + 1] = max;
|
||||
buffer[i * 3 + 2] = sqrt(power) / len;
|
||||
buffer[i * 3 + 2] = sqrt(power / len); // RMS
|
||||
|
||||
if(overallmax < max)
|
||||
overallmax = max;
|
||||
|
1
extern/audaspace/bindings/C/AUD_Types.h
vendored
1
extern/audaspace/bindings/C/AUD_Types.h
vendored
@@ -176,4 +176,5 @@ typedef struct
|
||||
{
|
||||
AUD_Specs specs;
|
||||
float length;
|
||||
double start_offset;
|
||||
} AUD_SoundInfo;
|
||||
|
2
extern/audaspace/bindings/python/setup.py.in
vendored
2
extern/audaspace/bindings/python/setup.py.in
vendored
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
6
extern/audaspace/include/IReader.h
vendored
6
extern/audaspace/include/IReader.h
vendored
@@ -70,6 +70,12 @@ public:
|
||||
*/
|
||||
virtual int getPosition() const=0;
|
||||
|
||||
/**
|
||||
* Returns the start offset the sound should have to line up with related sources.
|
||||
* \return The required start offset in seconds.
|
||||
*/
|
||||
virtual double getStartOffset() const { return 0.0;}
|
||||
|
||||
/**
|
||||
* Returns the specification of the reader.
|
||||
* \return The Specs structure.
|
||||
|
2
extern/audaspace/include/fx/VolumeReader.h
vendored
2
extern/audaspace/include/fx/VolumeReader.h
vendored
@@ -67,4 +67,4 @@ public:
|
||||
virtual void read(int& length, bool& eos, sample_t* buffer);
|
||||
};
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
AUD_NAMESPACE_END
|
||||
|
80
extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
vendored
80
extern/audaspace/plugins/ffmpeg/FFMPEGReader.cpp
vendored
@@ -68,7 +68,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
for(int i = 0; i < m_frame->nb_samples; i++)
|
||||
{
|
||||
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
for(int i = 0; i < m_frame->nb_samples; i++)
|
||||
{
|
||||
std::memcpy(((data_t*)buffer.getBuffer()) + buf_pos + ((m_codecCtx->channels * i) + channel) * single_size,
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
m_frame->data[channel] + i * single_size, single_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,10 @@ int FFMPEGReader::decode(AVPacket& packet, Buffer& buffer)
|
||||
void FFMPEGReader::init()
|
||||
{
|
||||
m_position = 0;
|
||||
m_start_offset = 0.0f;
|
||||
m_pkgbuf_left = 0;
|
||||
m_st_time = 0;
|
||||
m_duration = 0;
|
||||
|
||||
if(avformat_find_stream_info(m_formatCtx, nullptr) < 0)
|
||||
AUD_THROW(FileException, "File couldn't be read, ffmpeg couldn't find the stream info.");
|
||||
@@ -134,15 +137,41 @@ void FFMPEGReader::init()
|
||||
// find audio stream and codec
|
||||
m_stream = -1;
|
||||
|
||||
double dur_sec = 0;
|
||||
|
||||
for(unsigned int i = 0; i < m_formatCtx->nb_streams; i++)
|
||||
{
|
||||
#ifdef FFMPEG_OLD_CODE
|
||||
if((m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
if(m_formatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#else
|
||||
if((m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
if(m_formatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||
#endif
|
||||
&& (m_stream < 0))
|
||||
{
|
||||
AVStream *audio_stream = m_formatCtx->streams[i];
|
||||
double audio_timebase = av_q2d(audio_stream->time_base);
|
||||
|
||||
if (audio_stream->start_time != AV_NOPTS_VALUE)
|
||||
{
|
||||
m_st_time = audio_stream->start_time;
|
||||
}
|
||||
|
||||
int64_t ctx_start_time = 0;
|
||||
if (m_formatCtx->start_time != AV_NOPTS_VALUE) {
|
||||
ctx_start_time = m_formatCtx->start_time;
|
||||
}
|
||||
|
||||
m_start_offset = m_st_time * audio_timebase - (double)ctx_start_time / AV_TIME_BASE;
|
||||
|
||||
if(audio_stream->duration != AV_NOPTS_VALUE)
|
||||
{
|
||||
dur_sec = audio_stream->duration * audio_timebase;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the audio starts after the stream start time, subract this from the total duration. */
|
||||
dur_sec = (double)m_formatCtx->duration / AV_TIME_BASE - m_start_offset;
|
||||
}
|
||||
|
||||
m_stream=i;
|
||||
break;
|
||||
}
|
||||
@@ -213,6 +242,7 @@ void FFMPEGReader::init()
|
||||
}
|
||||
|
||||
m_specs.rate = (SampleRate) m_codecCtx->sample_rate;
|
||||
m_duration = lround(dur_sec * m_codecCtx->sample_rate);
|
||||
}
|
||||
|
||||
FFMPEGReader::FFMPEGReader(std::string filename) :
|
||||
@@ -338,21 +368,17 @@ void FFMPEGReader::seek(int position)
|
||||
{
|
||||
if(position >= 0)
|
||||
{
|
||||
uint64_t st_time = m_formatCtx->start_time;
|
||||
uint64_t seek_pos = ((uint64_t)position) * ((uint64_t)AV_TIME_BASE) / ((uint64_t)m_specs.rate);
|
||||
double pts_time_base =
|
||||
av_q2d(m_formatCtx->streams[m_stream]->time_base);
|
||||
|
||||
if(st_time != AV_NOPTS_VALUE) {
|
||||
seek_pos += st_time;
|
||||
uint64_t seek_pts = (((uint64_t)position) / ((uint64_t)m_specs.rate)) / pts_time_base;
|
||||
|
||||
if(m_st_time != AV_NOPTS_VALUE) {
|
||||
seek_pts += m_st_time;
|
||||
}
|
||||
|
||||
double pts_time_base =
|
||||
av_q2d(m_formatCtx->streams[m_stream]->time_base);
|
||||
uint64_t pts_st_time =
|
||||
((st_time != AV_NOPTS_VALUE) ? st_time : 0)
|
||||
/ pts_time_base / (uint64_t) AV_TIME_BASE;
|
||||
|
||||
// a value < 0 tells us that seeking failed
|
||||
if(av_seek_frame(m_formatCtx, -1, seek_pos,
|
||||
if(av_seek_frame(m_formatCtx, m_stream, seek_pts,
|
||||
AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_ANY) >= 0)
|
||||
{
|
||||
avcodec_flush_buffers(m_codecCtx);
|
||||
@@ -374,7 +400,7 @@ void FFMPEGReader::seek(int position)
|
||||
if(packet.pts != AV_NOPTS_VALUE)
|
||||
{
|
||||
// calculate real position, and read to frame!
|
||||
m_position = (packet.pts - pts_st_time) * pts_time_base * m_specs.rate;
|
||||
m_position = (packet.pts - m_st_time) * pts_time_base * m_specs.rate;
|
||||
|
||||
if(m_position < position)
|
||||
{
|
||||
@@ -405,8 +431,7 @@ void FFMPEGReader::seek(int position)
|
||||
int FFMPEGReader::getLength() const
|
||||
{
|
||||
// return approximated remaning size
|
||||
return (int)((m_formatCtx->duration * m_codecCtx->sample_rate)
|
||||
/ AV_TIME_BASE)-m_position;
|
||||
return m_duration - m_position;
|
||||
}
|
||||
|
||||
int FFMPEGReader::getPosition() const
|
||||
@@ -414,6 +439,11 @@ int FFMPEGReader::getPosition() const
|
||||
return m_position;
|
||||
}
|
||||
|
||||
double FFMPEGReader::getStartOffset() const
|
||||
{
|
||||
return m_start_offset;
|
||||
}
|
||||
|
||||
Specs FFMPEGReader::getSpecs() const
|
||||
{
|
||||
return m_specs.specs;
|
||||
@@ -450,11 +480,13 @@ void FFMPEGReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
// decode the package
|
||||
pkgbuf_pos = decode(packet, m_pkgbuf);
|
||||
|
||||
// copy to output buffer
|
||||
data_size = std::min(pkgbuf_pos, left * sample_size);
|
||||
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
|
||||
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
||||
left -= data_size / sample_size;
|
||||
if (packet.pts >= m_st_time) {
|
||||
// copy to output buffer
|
||||
data_size = std::min(pkgbuf_pos, left * sample_size);
|
||||
m_convert((data_t*) buf, (data_t*) m_pkgbuf.getBuffer(), data_size / AUD_FORMAT_SIZE(m_specs.format));
|
||||
buf += data_size / AUD_FORMAT_SIZE(m_specs.format);
|
||||
left -= data_size / sample_size;
|
||||
}
|
||||
}
|
||||
av_packet_unref(&packet);
|
||||
}
|
||||
|
17
extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
vendored
17
extern/audaspace/plugins/ffmpeg/FFMPEGReader.h
vendored
@@ -54,6 +54,22 @@ private:
|
||||
*/
|
||||
int m_position;
|
||||
|
||||
/**
|
||||
* The start offset in seconds relative to the media container start time.
|
||||
* IE how much the sound should be delayed to be kept in sync with the rest of the containter streams.
|
||||
*/
|
||||
double m_start_offset;
|
||||
|
||||
/**
|
||||
* The start time pts of the stream. All packets before this timestamp shouldn't be played back (only decoded).
|
||||
*/
|
||||
int64_t m_st_time;
|
||||
|
||||
/**
|
||||
* The duration of the audio stream in samples.
|
||||
*/
|
||||
int64_t m_duration;
|
||||
|
||||
/**
|
||||
* The specification of the audio data.
|
||||
*/
|
||||
@@ -182,6 +198,7 @@ public:
|
||||
virtual void seek(int position);
|
||||
virtual int getLength() const;
|
||||
virtual int getPosition() const;
|
||||
virtual double getStartOffset() const;
|
||||
virtual Specs getSpecs() const;
|
||||
virtual void read(int& length, bool& eos, sample_t* buffer);
|
||||
};
|
||||
|
@@ -32,17 +32,24 @@ void PulseAudioDevice::PulseAudio_state_callback(pa_context *context, void *data
|
||||
device->m_state = AUD_pa_context_get_state(context);
|
||||
}
|
||||
|
||||
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t num_bytes, void *data)
|
||||
void PulseAudioDevice::PulseAudio_request(pa_stream *stream, size_t total_bytes, void *data)
|
||||
{
|
||||
PulseAudioDevice* device = (PulseAudioDevice*)data;
|
||||
|
||||
void* buffer;
|
||||
|
||||
AUD_pa_stream_begin_write(stream, &buffer, &num_bytes);
|
||||
while(total_bytes > 0)
|
||||
{
|
||||
size_t num_bytes = total_bytes;
|
||||
|
||||
device->mix((data_t*)buffer, num_bytes / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
|
||||
AUD_pa_stream_begin_write(stream, &buffer, &num_bytes);
|
||||
|
||||
AUD_pa_stream_write(stream, buffer, num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
|
||||
device->mix((data_t*)buffer, num_bytes / AUD_DEVICE_SAMPLE_SIZE(device->m_specs));
|
||||
|
||||
AUD_pa_stream_write(stream, buffer, num_bytes, nullptr, 0, PA_SEEK_RELATIVE);
|
||||
|
||||
total_bytes -= num_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseAudioDevice::PulseAudio_underflow(pa_stream *stream, void *data)
|
||||
@@ -96,7 +103,6 @@ void PulseAudioDevice::runMixingThread()
|
||||
|
||||
PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buffersize) :
|
||||
m_state(PA_CONTEXT_UNCONNECTED),
|
||||
m_buffersize(buffersize),
|
||||
m_underflows(0)
|
||||
{
|
||||
m_mainloop = AUD_pa_mainloop_new();
|
||||
@@ -187,6 +193,9 @@ PulseAudioDevice::PulseAudioDevice(std::string name, DeviceSpecs specs, int buff
|
||||
AUD_pa_stream_set_write_callback(m_stream, PulseAudio_request, this);
|
||||
AUD_pa_stream_set_underflow_callback(m_stream, PulseAudio_underflow, this);
|
||||
|
||||
buffersize *= AUD_DEVICE_SAMPLE_SIZE(m_specs);
|
||||
m_buffersize = buffersize;
|
||||
|
||||
pa_buffer_attr buffer_attr;
|
||||
|
||||
buffer_attr.fragsize = -1U;
|
||||
|
@@ -59,7 +59,7 @@ private:
|
||||
* \param num_bytes The length in bytes to be supplied.
|
||||
* \param data The PulseAudio device.
|
||||
*/
|
||||
AUD_LOCAL static void PulseAudio_request(pa_stream* stream, size_t num_bytes, void* data);
|
||||
AUD_LOCAL static void PulseAudio_request(pa_stream* stream, size_t total_bytes, void* data);
|
||||
|
||||
/**
|
||||
* Reports an underflow from the PulseAudio server.
|
||||
|
2
extern/audaspace/src/fx/VolumeReader.cpp
vendored
2
extern/audaspace/src/fx/VolumeReader.cpp
vendored
@@ -57,4 +57,4 @@ void VolumeReader::read(int& length, bool& eos, sample_t* buffer)
|
||||
buffer[i] = buffer[i] * m_volumeStorage->getVolume();
|
||||
}
|
||||
|
||||
AUD_NAMESPACE_END
|
||||
AUD_NAMESPACE_END
|
||||
|
7
extern/nanosvg/README.blender
vendored
Normal file
7
extern/nanosvg/README.blender
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Project: NanoSVG
|
||||
URL: https://github.com/memononen/nanosvg
|
||||
License: zlib
|
||||
Upstream version:
|
||||
Local modifications: Added some functionality to manage grease pencil layers
|
||||
|
||||
Added a fix to SVG import arc and float errors (https://developer.blender.org/rB11dc674c78b49fc4e0b7c134c375b6c8b8eacbcc)
|
86
extern/nanosvg/patches/NanoSVG.diff
vendored
Normal file
86
extern/nanosvg/patches/NanoSVG.diff
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
diff --git a/c:/tmp/nanosvg_original.h b/c:/tmp/nanosvg_modif.h
|
||||
index 24a01a86d3d..eca0d07e79d 100644
|
||||
--- a/c:/tmp/nanosvg_original.h
|
||||
+++ b/c:/tmp/nanosvg_modif.h
|
||||
@@ -24,7 +24,8 @@
|
||||
*
|
||||
* Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
|
||||
*
|
||||
- */
|
||||
+ * This is a modified version for Blender used by importers.
|
||||
+ **/
|
||||
|
||||
#ifndef NANOSVG_H
|
||||
#define NANOSVG_H
|
||||
@@ -148,6 +149,8 @@ extern "C" {
|
||||
typedef struct NSVGshape
|
||||
{
|
||||
char id[64]; // Optional 'id' attr of the shape or its group
|
||||
+ /* Blender: Parent ID used for layer creation. */
|
||||
+ char id_parent[64];
|
||||
NSVGpaint fill; // Fill paint
|
||||
NSVGpaint stroke; // Stroke paint
|
||||
float opacity; // Opacity of the shape.
|
||||
@@ -370,6 +373,7 @@ int nsvg__parseXML(char* input,
|
||||
/* Simple SVG parser. */
|
||||
|
||||
#define NSVG_MAX_ATTR 128
|
||||
+#define NSVG_MAX_BREADCRUMB 5
|
||||
|
||||
enum NSVGgradientUnits
|
||||
{
|
||||
@@ -471,6 +475,10 @@ typedef struct NSVGparser
|
||||
float dpi;
|
||||
char pathFlag;
|
||||
char defsFlag;
|
||||
+ /** Blender breadcrumb for layers. */
|
||||
+ char breadcrumb[NSVG_MAX_BREADCRUMB][64];
|
||||
+ /** Blender number of elements in breadcrumb. */
|
||||
+ int breadcrumb_len;
|
||||
} NSVGparser;
|
||||
|
||||
static void nsvg__xformIdentity(float* t)
|
||||
@@ -980,6 +988,14 @@ static void nsvg__addShape(NSVGparser* p)
|
||||
memset(shape, 0, sizeof(NSVGshape));
|
||||
|
||||
memcpy(shape->id, attr->id, sizeof shape->id);
|
||||
+ /* Copy parent id from breadcrumb. */
|
||||
+ if (p->breadcrumb_len > 0) {
|
||||
+ memcpy(shape->id_parent, p->breadcrumb[0], sizeof shape->id_parent);
|
||||
+ }
|
||||
+ else {
|
||||
+ memcpy(shape->id_parent, attr->id, sizeof shape->id_parent);
|
||||
+ }
|
||||
+
|
||||
scale = nsvg__getAverageScale(attr->xform);
|
||||
shape->strokeWidth = attr->strokeWidth * scale;
|
||||
shape->strokeDashOffset = attr->strokeDashOffset * scale;
|
||||
@@ -2814,6 +2830,14 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
||||
if (strcmp(el, "g") == 0) {
|
||||
nsvg__pushAttr(p);
|
||||
nsvg__parseAttribs(p, attr);
|
||||
+
|
||||
+ /* Save the breadcrumb of groups. */
|
||||
+ if (p->breadcrumb_len < NSVG_MAX_BREADCRUMB) {
|
||||
+ NSVGattrib *attr_id = nsvg__getAttr(p);
|
||||
+ memcpy(
|
||||
+ p->breadcrumb[p->breadcrumb_len], attr_id->id, sizeof(p->breadcrumb[p->breadcrumb_len]));
|
||||
+ p->breadcrumb_len++;
|
||||
+ }
|
||||
}
|
||||
else if (strcmp(el, "path") == 0) {
|
||||
if (p->pathFlag) // Do not allow nested paths.
|
||||
@@ -2874,7 +2898,12 @@ static void nsvg__endElement(void* ud, const char* el)
|
||||
NSVGparser* p = (NSVGparser*)ud;
|
||||
|
||||
if (strcmp(el, "g") == 0) {
|
||||
- nsvg__popAttr(p);
|
||||
+ /* Remove the breadcrumb level. */
|
||||
+ if (p->breadcrumb_len > 0) {
|
||||
+ p->breadcrumb[p->breadcrumb_len - 1][0] = '\0';
|
||||
+ p->breadcrumb_len--;
|
||||
+ }
|
||||
+ nsvg__popAttr(p);
|
||||
}
|
||||
else if (strcmp(el, "path") == 0) {
|
||||
p->pathFlag = 0;
|
@@ -115,6 +115,16 @@ if(WITH_OPENVDB)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_ALEMBIC)
|
||||
add_definitions(-DWITH_ALEMBIC)
|
||||
list(APPEND INC_SYS
|
||||
${ALEMBIC_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND LIB
|
||||
${ALEMBIC_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WITH_OPENIMAGEDENOISE)
|
||||
add_definitions(-DWITH_OPENIMAGEDENOISE)
|
||||
list(APPEND INC_SYS
|
||||
|
@@ -61,6 +61,7 @@ class CyclesRender(bpy.types.RenderEngine):
|
||||
bl_use_save_buffers = True
|
||||
bl_use_spherical_stereo = True
|
||||
bl_use_custom_freestyle = True
|
||||
bl_use_alembic_procedural = True
|
||||
|
||||
def __init__(self):
|
||||
self.session = None
|
||||
|
@@ -227,6 +227,11 @@ def update_render_passes(self, context):
|
||||
view_layer.update_render_passes()
|
||||
|
||||
|
||||
def update_render_engine(self, context):
|
||||
scene = context.scene
|
||||
scene.update_render_engine()
|
||||
|
||||
|
||||
class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
|
||||
device: EnumProperty(
|
||||
@@ -240,6 +245,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
|
||||
description="Feature set to use for rendering",
|
||||
items=enum_feature_set,
|
||||
default='SUPPORTED',
|
||||
update=update_render_engine,
|
||||
)
|
||||
shading_system: BoolProperty(
|
||||
name="Open Shading Language",
|
||||
@@ -1164,12 +1170,6 @@ class CyclesVisibilitySettings(bpy.types.PropertyGroup):
|
||||
|
||||
@classmethod
|
||||
def register(cls):
|
||||
bpy.types.Object.cycles_visibility = PointerProperty(
|
||||
name="Cycles Visibility Settings",
|
||||
description="Cycles visibility settings",
|
||||
type=cls,
|
||||
)
|
||||
|
||||
bpy.types.World.cycles_visibility = PointerProperty(
|
||||
name="Cycles Visibility Settings",
|
||||
description="Cycles visibility settings",
|
||||
@@ -1178,7 +1178,6 @@ class CyclesVisibilitySettings(bpy.types.PropertyGroup):
|
||||
|
||||
@classmethod
|
||||
def unregister(cls):
|
||||
del bpy.types.Object.cycles_visibility
|
||||
del bpy.types.World.cycles_visibility
|
||||
|
||||
|
||||
@@ -1268,18 +1267,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup):
|
||||
default=0.1,
|
||||
)
|
||||
|
||||
is_shadow_catcher: BoolProperty(
|
||||
name="Shadow Catcher",
|
||||
description="Only render shadows on this object, for compositing renders into real footage",
|
||||
default=False,
|
||||
)
|
||||
|
||||
is_holdout: BoolProperty(
|
||||
name="Holdout",
|
||||
description="Render objects as a holdout or matte, creating a "
|
||||
"hole in the image with zero alpha, to fill out in "
|
||||
"compositing with real footage or another render",
|
||||
default=False,
|
||||
ao_distance: FloatProperty(
|
||||
name="AO Distance",
|
||||
description="AO distance used for approximate global illumination (0 means use world setting)",
|
||||
min=0.0,
|
||||
default=0.0,
|
||||
subtype='DISTANCE',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@@ -1102,7 +1102,7 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel):
|
||||
|
||||
if ob:
|
||||
is_sortable = len(ob.material_slots) > 1
|
||||
rows = 1
|
||||
rows = 3
|
||||
if (is_sortable):
|
||||
rows = 4
|
||||
|
||||
@@ -1228,6 +1228,26 @@ class CYCLES_OBJECT_PT_shading_shadow_terminator(CyclesButtonsPanel, Panel):
|
||||
flow.prop(cob, "shadow_terminator_offset", text="Shading Offset")
|
||||
|
||||
|
||||
class CYCLES_OBJECT_PT_shading_gi_approximation(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Fast GI Approximation"
|
||||
bl_parent_id = "CYCLES_OBJECT_PT_shading"
|
||||
bl_context = "object"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
scene = context.scene
|
||||
ob = context.object
|
||||
|
||||
cob = ob.cycles
|
||||
cscene = scene.cycles
|
||||
|
||||
col = layout.column()
|
||||
col.active = cscene.use_fast_gi
|
||||
col.prop(cob, "ao_distance")
|
||||
|
||||
|
||||
class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
|
||||
bl_label = "Visibility"
|
||||
bl_context = "object"
|
||||
@@ -1250,10 +1270,9 @@ class CYCLES_OBJECT_PT_visibility(CyclesButtonsPanel, Panel):
|
||||
col.prop(ob, "hide_render", text="Renders", invert_checkbox=True, toggle=False)
|
||||
|
||||
if has_geometry_visibility(ob):
|
||||
cob = ob.cycles
|
||||
col = layout.column(heading="Mask")
|
||||
col.prop(cob, "is_shadow_catcher")
|
||||
col.prop(cob, "is_holdout")
|
||||
col.prop(ob, "is_shadow_catcher")
|
||||
col.prop(ob, "is_holdout")
|
||||
|
||||
|
||||
class CYCLES_OBJECT_PT_visibility_ray_visibility(CyclesButtonsPanel, Panel):
|
||||
@@ -1273,19 +1292,17 @@ class CYCLES_OBJECT_PT_visibility_ray_visibility(CyclesButtonsPanel, Panel):
|
||||
|
||||
scene = context.scene
|
||||
ob = context.object
|
||||
cob = ob.cycles
|
||||
visibility = ob.cycles_visibility
|
||||
|
||||
col = layout.column()
|
||||
col.prop(visibility, "camera")
|
||||
col.prop(visibility, "diffuse")
|
||||
col.prop(visibility, "glossy")
|
||||
col.prop(visibility, "transmission")
|
||||
col.prop(visibility, "scatter")
|
||||
col.prop(ob, "visible_camera", text="Camera")
|
||||
col.prop(ob, "visible_diffuse", text="Diffuse")
|
||||
col.prop(ob, "visible_glossy", text="Glossy")
|
||||
col.prop(ob, "visible_transmission", text="Transmission")
|
||||
col.prop(ob, "visible_volume_scatter", text="Volume Scatter")
|
||||
|
||||
if ob.type != 'LIGHT':
|
||||
sub = col.column()
|
||||
sub.prop(visibility, "shadow")
|
||||
sub.prop(ob, "visible_shadow", text="Shadow")
|
||||
|
||||
|
||||
class CYCLES_OBJECT_PT_visibility_culling(CyclesButtonsPanel, Panel):
|
||||
@@ -2305,6 +2322,7 @@ classes = (
|
||||
CYCLES_OBJECT_PT_motion_blur,
|
||||
CYCLES_OBJECT_PT_shading,
|
||||
CYCLES_OBJECT_PT_shading_shadow_terminator,
|
||||
CYCLES_OBJECT_PT_shading_gi_approximation,
|
||||
CYCLES_OBJECT_PT_visibility,
|
||||
CYCLES_OBJECT_PT_visibility_ray_visibility,
|
||||
CYCLES_OBJECT_PT_visibility_culling,
|
||||
|
@@ -1038,23 +1038,6 @@ static void create_subd_mesh(Scene *scene,
|
||||
|
||||
/* Sync */
|
||||
|
||||
static BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob)
|
||||
{
|
||||
if (b_ob.modifiers.length() > 0) {
|
||||
BL::Modifier b_mod = b_ob.modifiers[b_ob.modifiers.length() - 1];
|
||||
|
||||
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
|
||||
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
|
||||
|
||||
if (MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
|
||||
return mesh_cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
|
||||
}
|
||||
|
||||
/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes
|
||||
* things like velocity from cache modifier, fluid simulation).
|
||||
*
|
||||
@@ -1095,7 +1078,7 @@ static void sync_mesh_cached_velocities(BL::Object &b_ob, Scene *scene, Mesh *me
|
||||
return;
|
||||
}
|
||||
|
||||
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob);
|
||||
BL::MeshSequenceCacheModifier b_mesh_cache = object_mesh_cache_find(b_ob, true);
|
||||
|
||||
if (!b_mesh_cache) {
|
||||
return;
|
||||
@@ -1258,7 +1241,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
|
||||
}
|
||||
|
||||
/* Cached motion blur already exported. */
|
||||
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob);
|
||||
BL::MeshSequenceCacheModifier mesh_cache = object_mesh_cache_find(b_ob, true);
|
||||
if (mesh_cache) {
|
||||
return;
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "render/alembic.h"
|
||||
#include "render/camera.h"
|
||||
#include "render/graph.h"
|
||||
#include "render/integrator.h"
|
||||
@@ -199,8 +200,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
/* Visibility flags for both parent and child. */
|
||||
PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
bool use_holdout = get_boolean(cobject, "is_holdout") ||
|
||||
b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
|
||||
bool use_holdout = b_parent.holdout_get(PointerRNA_NULL, b_view_layer);
|
||||
uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY;
|
||||
|
||||
if (b_parent.ptr.data != b_ob.ptr.data) {
|
||||
@@ -287,8 +287,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
object->set_visibility(visibility);
|
||||
|
||||
bool is_shadow_catcher = get_boolean(cobject, "is_shadow_catcher");
|
||||
object->set_is_shadow_catcher(is_shadow_catcher);
|
||||
object->set_is_shadow_catcher(b_ob.is_shadow_catcher());
|
||||
|
||||
float shadow_terminator_shading_offset = get_float(cobject, "shadow_terminator_offset");
|
||||
object->set_shadow_terminator_shading_offset(shadow_terminator_shading_offset);
|
||||
@@ -297,6 +296,13 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
|
||||
"shadow_terminator_geometry_offset");
|
||||
object->set_shadow_terminator_geometry_offset(shadow_terminator_geometry_offset);
|
||||
|
||||
float ao_distance = get_float(cobject, "ao_distance");
|
||||
if (ao_distance == 0.0f && b_parent.ptr.data != b_ob.ptr.data) {
|
||||
PointerRNA cparent = RNA_pointer_get(&b_parent.ptr, "cycles");
|
||||
ao_distance = get_float(cparent, "ao_distance");
|
||||
}
|
||||
object->set_ao_distance(ao_distance);
|
||||
|
||||
/* sync the asset name for Cryptomatte */
|
||||
BL::Object parent = b_ob.parent();
|
||||
ustring parent_name;
|
||||
@@ -479,6 +485,64 @@ bool BlenderSync::sync_object_attributes(BL::DepsgraphObjectInstance &b_instance
|
||||
|
||||
/* Object Loop */
|
||||
|
||||
void BlenderSync::sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache)
|
||||
{
|
||||
#ifdef WITH_ALEMBIC
|
||||
BL::CacheFile cache_file = b_mesh_cache.cache_file();
|
||||
void *cache_file_key = cache_file.ptr.data;
|
||||
|
||||
AlembicProcedural *procedural = static_cast<AlembicProcedural *>(
|
||||
procedural_map.find(cache_file_key));
|
||||
|
||||
if (procedural == nullptr) {
|
||||
procedural = scene->create_node<AlembicProcedural>();
|
||||
procedural_map.add(cache_file_key, procedural);
|
||||
}
|
||||
else {
|
||||
procedural_map.used(procedural);
|
||||
}
|
||||
|
||||
float current_frame = b_scene.frame_current();
|
||||
if (cache_file.override_frame()) {
|
||||
current_frame = cache_file.frame();
|
||||
}
|
||||
|
||||
if (!cache_file.override_frame()) {
|
||||
procedural->set_start_frame(b_scene.frame_start());
|
||||
procedural->set_end_frame(b_scene.frame_end());
|
||||
}
|
||||
|
||||
procedural->set_frame(current_frame);
|
||||
procedural->set_frame_rate(b_scene.render().fps() / b_scene.render().fps_base());
|
||||
procedural->set_frame_offset(cache_file.frame_offset());
|
||||
|
||||
string absolute_path = blender_absolute_path(b_data, b_ob, b_mesh_cache.cache_file().filepath());
|
||||
procedural->set_filepath(ustring(absolute_path));
|
||||
|
||||
procedural->set_scale(cache_file.scale());
|
||||
|
||||
/* create or update existing AlembicObjects */
|
||||
ustring object_path = ustring(b_mesh_cache.object_path());
|
||||
|
||||
AlembicObject *abc_object = procedural->get_or_create_object(object_path);
|
||||
|
||||
array<Node *> used_shaders = find_used_shaders(b_ob);
|
||||
abc_object->set_used_shaders(used_shaders);
|
||||
|
||||
PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles");
|
||||
const float subd_dicing_rate = max(0.1f, RNA_float_get(&cobj, "dicing_rate") * dicing_rate);
|
||||
abc_object->set_subd_dicing_rate(subd_dicing_rate);
|
||||
abc_object->set_subd_max_level(max_subdivisions);
|
||||
|
||||
if (abc_object->is_modified() || procedural->is_modified()) {
|
||||
procedural->tag_update(scene);
|
||||
}
|
||||
#else
|
||||
(void)b_ob;
|
||||
(void)b_mesh_cache;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
BL::SpaceView3D &b_v3d,
|
||||
float motion_time)
|
||||
@@ -494,6 +558,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
light_map.pre_sync();
|
||||
geometry_map.pre_sync();
|
||||
object_map.pre_sync();
|
||||
procedural_map.pre_sync();
|
||||
particle_system_map.pre_sync();
|
||||
motion_times.clear();
|
||||
}
|
||||
@@ -534,15 +599,38 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
|
||||
/* Object itself. */
|
||||
if (b_instance.show_self()) {
|
||||
sync_object(b_depsgraph,
|
||||
b_view_layer,
|
||||
b_instance,
|
||||
motion_time,
|
||||
false,
|
||||
show_lights,
|
||||
culling,
|
||||
&use_portal,
|
||||
sync_hair ? NULL : &geom_task_pool);
|
||||
#ifdef WITH_ALEMBIC
|
||||
bool use_procedural = false;
|
||||
BL::MeshSequenceCacheModifier b_mesh_cache(PointerRNA_NULL);
|
||||
|
||||
/* Experimental as Blender does not have good support for procedurals at the moment, also
|
||||
* only available in preview renders since currently do not have a good cache policy, the
|
||||
* data being loaded at once for all the frames. */
|
||||
if (experimental && b_v3d) {
|
||||
b_mesh_cache = object_mesh_cache_find(b_ob, false);
|
||||
use_procedural = b_mesh_cache && b_mesh_cache.cache_file().use_render_procedural();
|
||||
}
|
||||
|
||||
if (use_procedural) {
|
||||
/* Skip in the motion case, as generating motion blur data will be handled in the
|
||||
* procedural. */
|
||||
if (!motion) {
|
||||
sync_procedural(b_ob, b_mesh_cache);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
sync_object(b_depsgraph,
|
||||
b_view_layer,
|
||||
b_instance,
|
||||
motion_time,
|
||||
false,
|
||||
show_lights,
|
||||
culling,
|
||||
&use_portal,
|
||||
sync_hair ? NULL : &geom_task_pool);
|
||||
}
|
||||
}
|
||||
|
||||
/* Particle hair as separate object. */
|
||||
@@ -575,6 +663,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph,
|
||||
object_map.post_sync();
|
||||
geometry_map.post_sync();
|
||||
particle_system_map.post_sync();
|
||||
procedural_map.post_sync();
|
||||
}
|
||||
|
||||
if (motion)
|
||||
|
@@ -71,7 +71,7 @@ bool BlenderSync::sync_dupli_particle(BL::Object &b_ob,
|
||||
Particle pa;
|
||||
|
||||
pa.index = persistent_id[0];
|
||||
pa.age = b_scene.frame_current() - b_pa.birth_time();
|
||||
pa.age = b_scene.frame_current_final() - b_pa.birth_time();
|
||||
pa.lifetime = b_pa.lifetime();
|
||||
pa.location = get_float3(b_pa.location());
|
||||
pa.rotation = get_float4(b_pa.rotation());
|
||||
|
@@ -487,6 +487,24 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
|
||||
continue;
|
||||
|
||||
/* Read metadata. */
|
||||
bool is_bool_param = false;
|
||||
ustring param_label = param->name;
|
||||
|
||||
for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
|
||||
if (metadata.type == TypeDesc::STRING) {
|
||||
if (metadata.name == "widget") {
|
||||
/* Boolean socket. */
|
||||
if (metadata.sdefault[0] == "boolean" || metadata.sdefault[0] == "checkBox") {
|
||||
is_bool_param = true;
|
||||
}
|
||||
}
|
||||
else if (metadata.name == "label") {
|
||||
/* Socket label. */
|
||||
param_label = metadata.sdefault[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
/* determine socket type */
|
||||
string socket_type;
|
||||
BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
|
||||
@@ -494,6 +512,7 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
float default_float = 0.0f;
|
||||
int default_int = 0;
|
||||
string default_string = "";
|
||||
bool default_boolean = false;
|
||||
|
||||
if (param->isclosure) {
|
||||
socket_type = "NodeSocketShader";
|
||||
@@ -523,10 +542,19 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
}
|
||||
else if (param->type.aggregate == TypeDesc::SCALAR) {
|
||||
if (param->type.basetype == TypeDesc::INT) {
|
||||
socket_type = "NodeSocketInt";
|
||||
data_type = BL::NodeSocket::type_INT;
|
||||
if (param->validdefault)
|
||||
default_int = param->idefault[0];
|
||||
if (is_bool_param) {
|
||||
socket_type = "NodeSocketBool";
|
||||
data_type = BL::NodeSocket::type_BOOLEAN;
|
||||
if (param->validdefault) {
|
||||
default_boolean = (bool)param->idefault[0];
|
||||
}
|
||||
}
|
||||
else {
|
||||
socket_type = "NodeSocketInt";
|
||||
data_type = BL::NodeSocket::type_INT;
|
||||
if (param->validdefault)
|
||||
default_int = param->idefault[0];
|
||||
}
|
||||
}
|
||||
else if (param->type.basetype == TypeDesc::FLOAT) {
|
||||
socket_type = "NodeSocketFloat";
|
||||
@@ -546,33 +574,57 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
else
|
||||
continue;
|
||||
|
||||
/* find socket socket */
|
||||
BL::NodeSocket b_sock(PointerRNA_NULL);
|
||||
/* Update existing socket. */
|
||||
bool found_existing = false;
|
||||
if (param->isoutput) {
|
||||
b_sock = b_node.outputs[param->name.string()];
|
||||
/* remove if type no longer matches */
|
||||
if (b_sock && b_sock.bl_idname() != socket_type) {
|
||||
b_node.outputs.remove(b_data, b_sock);
|
||||
b_sock = BL::NodeSocket(PointerRNA_NULL);
|
||||
for (BL::NodeSocket &b_sock : b_node.outputs) {
|
||||
if (b_sock.identifier() == param->name) {
|
||||
if (b_sock.bl_idname() != socket_type) {
|
||||
/* Remove if type no longer matches. */
|
||||
b_node.outputs.remove(b_data, b_sock);
|
||||
}
|
||||
else {
|
||||
/* Reuse and update label. */
|
||||
if (b_sock.name() != param_label) {
|
||||
b_sock.name(param_label.string());
|
||||
}
|
||||
used_sockets.insert(b_sock.ptr.data);
|
||||
found_existing = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
b_sock = b_node.inputs[param->name.string()];
|
||||
/* remove if type no longer matches */
|
||||
if (b_sock && b_sock.bl_idname() != socket_type) {
|
||||
b_node.inputs.remove(b_data, b_sock);
|
||||
b_sock = BL::NodeSocket(PointerRNA_NULL);
|
||||
for (BL::NodeSocket &b_sock : b_node.inputs) {
|
||||
if (b_sock.identifier() == param->name) {
|
||||
if (b_sock.bl_idname() != socket_type) {
|
||||
/* Remove if type no longer matches. */
|
||||
b_node.inputs.remove(b_data, b_sock);
|
||||
}
|
||||
else {
|
||||
/* Reuse and update label. */
|
||||
if (b_sock.name() != param_label) {
|
||||
b_sock.name(param_label.string());
|
||||
}
|
||||
used_sockets.insert(b_sock.ptr.data);
|
||||
found_existing = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!b_sock) {
|
||||
/* create new socket */
|
||||
if (param->isoutput)
|
||||
b_sock = b_node.outputs.create(
|
||||
b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
|
||||
else
|
||||
b_sock = b_node.inputs.create(
|
||||
b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
|
||||
if (!found_existing) {
|
||||
/* Create new socket. */
|
||||
BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
|
||||
socket_type.c_str(),
|
||||
param_label.c_str(),
|
||||
param->name.c_str()) :
|
||||
b_node.inputs.create(b_data,
|
||||
socket_type.c_str(),
|
||||
param_label.c_str(),
|
||||
param->name.c_str());
|
||||
|
||||
/* set default value */
|
||||
if (data_type == BL::NodeSocket::type_VALUE) {
|
||||
@@ -590,9 +642,12 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
|
||||
else if (data_type == BL::NodeSocket::type_STRING) {
|
||||
set_string(b_sock.ptr, "default_value", default_string);
|
||||
}
|
||||
}
|
||||
else if (data_type == BL::NodeSocket::type_BOOLEAN) {
|
||||
set_boolean(b_sock.ptr, "default_value", default_boolean);
|
||||
}
|
||||
|
||||
used_sockets.insert(b_sock.ptr.data);
|
||||
used_sockets.insert(b_sock.ptr.data);
|
||||
}
|
||||
}
|
||||
|
||||
/* remove unused parameters */
|
||||
|
@@ -149,7 +149,7 @@ BlenderAttributeType blender_attribute_name_split_type(ustring name, string *r_r
|
||||
static BL::NodeSocket get_node_output(BL::Node &b_node, const string &name)
|
||||
{
|
||||
for (BL::NodeSocket &b_out : b_node.outputs) {
|
||||
if (b_out.name() == name) {
|
||||
if (b_out.identifier() == name) {
|
||||
return b_out;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +215,12 @@ static void set_default_value(ShaderInput *input,
|
||||
break;
|
||||
}
|
||||
case SocketType::INT: {
|
||||
node->set(socket, get_int(b_sock.ptr, "default_value"));
|
||||
if (b_sock.type() == BL::NodeSocket::type_BOOLEAN) {
|
||||
node->set(socket, get_boolean(b_sock.ptr, "default_value"));
|
||||
}
|
||||
else {
|
||||
node->set(socket, get_int(b_sock.ptr, "default_value"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SocketType::COLOR: {
|
||||
@@ -1002,71 +1007,59 @@ static bool node_use_modified_socket_name(ShaderNode *node)
|
||||
return true;
|
||||
}
|
||||
|
||||
static ShaderInput *node_find_input_by_name(ShaderNode *node,
|
||||
BL::Node &b_node,
|
||||
BL::NodeSocket &b_socket)
|
||||
static ShaderInput *node_find_input_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
|
||||
{
|
||||
string name = b_socket.name();
|
||||
string name = b_socket.identifier();
|
||||
ShaderInput *input = node->input(name.c_str());
|
||||
|
||||
if (node_use_modified_socket_name(node)) {
|
||||
bool found = false;
|
||||
int counter = 0, total = 0;
|
||||
if (!input && node_use_modified_socket_name(node)) {
|
||||
/* Different internal name for shader. */
|
||||
if (string_startswith(name, "Shader")) {
|
||||
string_replace(name, "Shader", "Closure");
|
||||
}
|
||||
input = node->input(name.c_str());
|
||||
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
if (b_input.name() == name) {
|
||||
if (!found) {
|
||||
counter++;
|
||||
}
|
||||
total++;
|
||||
if (!input) {
|
||||
/* Different internal numbering of two sockets with same name.
|
||||
* Note that the Blender convention for unique socket names changed
|
||||
* from . to _ at some point, so we check both to handle old files. */
|
||||
if (string_endswith(name, "_001")) {
|
||||
string_replace(name, "_001", "2");
|
||||
}
|
||||
else if (string_endswith(name, ".001")) {
|
||||
string_replace(name, ".001", "2");
|
||||
}
|
||||
else if (string_endswith(name, "_002")) {
|
||||
string_replace(name, "_002", "3");
|
||||
}
|
||||
else if (string_endswith(name, ".002")) {
|
||||
string_replace(name, ".002", "3");
|
||||
}
|
||||
else {
|
||||
name += "1";
|
||||
}
|
||||
|
||||
if (b_input.ptr.data == b_socket.ptr.data)
|
||||
found = true;
|
||||
input = node->input(name.c_str());
|
||||
}
|
||||
|
||||
/* rename if needed */
|
||||
if (name == "Shader")
|
||||
name = "Closure";
|
||||
|
||||
if (total > 1)
|
||||
name = string_printf("%s%d", name.c_str(), counter);
|
||||
}
|
||||
|
||||
return node->input(name.c_str());
|
||||
return input;
|
||||
}
|
||||
|
||||
static ShaderOutput *node_find_output_by_name(ShaderNode *node,
|
||||
BL::Node &b_node,
|
||||
BL::NodeSocket &b_socket)
|
||||
static ShaderOutput *node_find_output_by_name(ShaderNode *node, BL::NodeSocket &b_socket)
|
||||
{
|
||||
string name = b_socket.name();
|
||||
string name = b_socket.identifier();
|
||||
ShaderOutput *output = node->output(name.c_str());
|
||||
|
||||
if (node_use_modified_socket_name(node)) {
|
||||
bool found = false;
|
||||
int counter = 0, total = 0;
|
||||
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
if (b_output.name() == name) {
|
||||
if (!found) {
|
||||
counter++;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
if (b_output.ptr.data == b_socket.ptr.data) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* rename if needed */
|
||||
if (name == "Shader")
|
||||
if (!output && node_use_modified_socket_name(node)) {
|
||||
/* Different internal name for shader. */
|
||||
if (name == "Shader") {
|
||||
name = "Closure";
|
||||
|
||||
if (total > 1)
|
||||
name = string_printf("%s%d", name.c_str(), counter);
|
||||
output = node->output(name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return node->output(name.c_str());
|
||||
return output;
|
||||
}
|
||||
|
||||
static void add_nodes(Scene *scene,
|
||||
@@ -1209,7 +1202,7 @@ static void add_nodes(Scene *scene,
|
||||
if (node) {
|
||||
/* map node sockets for linking */
|
||||
for (BL::NodeSocket &b_input : b_node.inputs) {
|
||||
ShaderInput *input = node_find_input_by_name(node, b_node, b_input);
|
||||
ShaderInput *input = node_find_input_by_name(node, b_input);
|
||||
if (!input) {
|
||||
/* XXX should not happen, report error? */
|
||||
continue;
|
||||
@@ -1219,7 +1212,7 @@ static void add_nodes(Scene *scene,
|
||||
set_default_value(input, b_input, b_data, b_ntree);
|
||||
}
|
||||
for (BL::NodeSocket &b_output : b_node.outputs) {
|
||||
ShaderOutput *output = node_find_output_by_name(node, b_node, b_output);
|
||||
ShaderOutput *output = node_find_output_by_name(node, b_output);
|
||||
if (!output) {
|
||||
/* XXX should not happen, report error? */
|
||||
continue;
|
||||
|
@@ -59,6 +59,7 @@ BlenderSync::BlenderSync(BL::RenderEngine &b_engine,
|
||||
b_scene(b_scene),
|
||||
shader_map(scene),
|
||||
object_map(scene),
|
||||
procedural_map(scene),
|
||||
geometry_map(scene),
|
||||
light_map(scene),
|
||||
particle_system_map(scene),
|
||||
|
@@ -151,6 +151,8 @@ class BlenderSync {
|
||||
TaskPool *geom_task_pool);
|
||||
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
|
||||
|
||||
void sync_procedural(BL::Object &b_ob, BL::MeshSequenceCacheModifier &b_mesh_cache);
|
||||
|
||||
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);
|
||||
|
||||
/* Volume */
|
||||
@@ -221,6 +223,7 @@ class BlenderSync {
|
||||
|
||||
id_map<void *, Shader> shader_map;
|
||||
id_map<ObjectKey, Object> object_map;
|
||||
id_map<void *, Procedural> procedural_map;
|
||||
id_map<GeometryKey, Geometry> geometry_map;
|
||||
id_map<ObjectKey, Light> light_map;
|
||||
id_map<ParticleSystemKey, ParticleSystem> particle_system_map;
|
||||
|
@@ -145,7 +145,7 @@ static inline void curvemapping_minmax(/*const*/ BL::CurveMapping &cumap,
|
||||
float *min_x,
|
||||
float *max_x)
|
||||
{
|
||||
/* const int num_curves = cumap.curves.length(); */ /* Gives linking error so far. */
|
||||
// const int num_curves = cumap.curves.length(); /* Gives linking error so far. */
|
||||
const int num_curves = rgb_curve ? 4 : 3;
|
||||
*min_x = FLT_MAX;
|
||||
*max_x = -FLT_MAX;
|
||||
@@ -246,7 +246,11 @@ static inline string image_user_file_path(BL::ImageUser &iuser,
|
||||
|
||||
string filepath_str = string(filepath);
|
||||
if (load_tiled && ima.source() == BL::Image::source_TILED) {
|
||||
string_replace(filepath_str, "1001", "<UDIM>");
|
||||
string udim;
|
||||
if (ima.tiles.length() > 0) {
|
||||
udim = to_string(ima.tiles[0].number());
|
||||
}
|
||||
string_replace(filepath_str, udim, "<UDIM>");
|
||||
}
|
||||
return filepath_str;
|
||||
}
|
||||
@@ -568,6 +572,35 @@ static inline BL::FluidDomainSettings object_fluid_gas_domain_find(BL::Object &b
|
||||
return BL::FluidDomainSettings(PointerRNA_NULL);
|
||||
}
|
||||
|
||||
static inline BL::MeshSequenceCacheModifier object_mesh_cache_find(BL::Object &b_ob,
|
||||
bool check_velocity)
|
||||
{
|
||||
for (int i = b_ob.modifiers.length() - 1; i >= 0; --i) {
|
||||
BL::Modifier b_mod = b_ob.modifiers[i];
|
||||
|
||||
if (b_mod.type() == BL::Modifier::type_MESH_SEQUENCE_CACHE) {
|
||||
BL::MeshSequenceCacheModifier mesh_cache = BL::MeshSequenceCacheModifier(b_mod);
|
||||
|
||||
if (check_velocity) {
|
||||
if (!MeshSequenceCacheModifier_has_velocity_get(&mesh_cache.ptr)) {
|
||||
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return mesh_cache;
|
||||
}
|
||||
|
||||
/* Skip possible particles system modifiers as they do not modify the geometry. */
|
||||
if (b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return BL::MeshSequenceCacheModifier(PointerRNA_NULL);
|
||||
}
|
||||
|
||||
static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
|
||||
bool preview,
|
||||
bool experimental)
|
||||
@@ -596,15 +629,14 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob,
|
||||
|
||||
static inline uint object_ray_visibility(BL::Object &b_ob)
|
||||
{
|
||||
PointerRNA cvisibility = RNA_pointer_get(&b_ob.ptr, "cycles_visibility");
|
||||
uint flag = 0;
|
||||
|
||||
flag |= get_boolean(cvisibility, "camera") ? PATH_RAY_CAMERA : 0;
|
||||
flag |= get_boolean(cvisibility, "diffuse") ? PATH_RAY_DIFFUSE : 0;
|
||||
flag |= get_boolean(cvisibility, "glossy") ? PATH_RAY_GLOSSY : 0;
|
||||
flag |= get_boolean(cvisibility, "transmission") ? PATH_RAY_TRANSMIT : 0;
|
||||
flag |= get_boolean(cvisibility, "shadow") ? PATH_RAY_SHADOW : 0;
|
||||
flag |= get_boolean(cvisibility, "scatter") ? PATH_RAY_VOLUME_SCATTER : 0;
|
||||
flag |= b_ob.visible_camera() ? PATH_RAY_CAMERA : 0;
|
||||
flag |= b_ob.visible_diffuse() ? PATH_RAY_DIFFUSE : 0;
|
||||
flag |= b_ob.visible_glossy() ? PATH_RAY_GLOSSY : 0;
|
||||
flag |= b_ob.visible_transmission() ? PATH_RAY_TRANSMIT : 0;
|
||||
flag |= b_ob.visible_shadow() ? PATH_RAY_SHADOW : 0;
|
||||
flag |= b_ob.visible_volume_scatter() ? PATH_RAY_VOLUME_SCATTER : 0;
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
function(cycles_set_solution_folder target)
|
||||
if(WINDOWS_USE_VISUAL_STUDIO_FOLDERS)
|
||||
if(IDE_GROUP_PROJECTS_IN_FOLDERS)
|
||||
get_filename_component(folderdir ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
|
||||
string(REPLACE ${CMAKE_SOURCE_DIR} "" folderdir ${folderdir})
|
||||
set_target_properties(${target} PROPERTIES FOLDER ${folderdir})
|
||||
|
@@ -239,4 +239,14 @@ ccl_device_forceinline int intersection_get_shader(KernelGlobals *ccl_restrict k
|
||||
return shader & SHADER_MASK;
|
||||
}
|
||||
|
||||
ccl_device_forceinline int intersection_get_object(KernelGlobals *ccl_restrict kg,
|
||||
const Intersection *ccl_restrict isect)
|
||||
{
|
||||
if (isect->object != OBJECT_NONE) {
|
||||
return isect->object;
|
||||
}
|
||||
|
||||
return kernel_tex_fetch(__prim_object, isect->prim);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
@@ -107,6 +107,20 @@ triangle_smooth_normal(KernelGlobals *kg, float3 Ng, int prim, float u, float v)
|
||||
return is_zero(N) ? Ng : N;
|
||||
}
|
||||
|
||||
ccl_device_inline float3
|
||||
triangle_smooth_normal_unnormalized(KernelGlobals *kg, float3 Ng, int prim, float u, float v)
|
||||
{
|
||||
/* load triangle vertices */
|
||||
const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim);
|
||||
float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x));
|
||||
float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y));
|
||||
float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z));
|
||||
|
||||
float3 N = (1.0f - u - v) * n2 + u * n0 + v * n1;
|
||||
|
||||
return is_zero(N) ? Ng : N;
|
||||
}
|
||||
|
||||
/* Ray differentials on triangle */
|
||||
|
||||
ccl_device_inline void triangle_dPdudv(KernelGlobals *kg,
|
||||
|
@@ -81,7 +81,8 @@ ccl_device_noinline void compute_light_pass(
|
||||
kg, sd, emission_sd, L, &state, &ray, &throughput, &ss_indirect)) {
|
||||
while (ss_indirect.num_rays) {
|
||||
kernel_path_subsurface_setup_indirect(kg, &ss_indirect, &state, &ray, L, &throughput);
|
||||
kernel_path_indirect(kg, &indirect_sd, emission_sd, &ray, throughput, &state, L);
|
||||
kernel_path_indirect(
|
||||
kg, &indirect_sd, emission_sd, &ray, throughput, &state, L, sd->object);
|
||||
}
|
||||
is_sss_sample = true;
|
||||
}
|
||||
@@ -97,7 +98,8 @@ ccl_device_noinline void compute_light_pass(
|
||||
state.ray_t = 0.0f;
|
||||
# endif
|
||||
/* compute indirect light */
|
||||
kernel_path_indirect(kg, &indirect_sd, emission_sd, &ray, throughput, &state, L);
|
||||
kernel_path_indirect(
|
||||
kg, &indirect_sd, emission_sd, &ray, throughput, &state, L, sd->object);
|
||||
|
||||
/* sum and reset indirect light pass variables for the next samples */
|
||||
path_radiance_sum_indirect(L);
|
||||
|
@@ -58,7 +58,8 @@ ccl_device_forceinline bool kernel_path_scene_intersect(KernelGlobals *kg,
|
||||
ccl_addr_space PathState *state,
|
||||
Ray *ray,
|
||||
Intersection *isect,
|
||||
PathRadiance *L)
|
||||
PathRadiance *L,
|
||||
const int last_object)
|
||||
{
|
||||
PROFILING_INIT(kg, PROFILING_SCENE_INTERSECT);
|
||||
|
||||
@@ -66,6 +67,12 @@ ccl_device_forceinline bool kernel_path_scene_intersect(KernelGlobals *kg,
|
||||
|
||||
if (path_state_ao_bounce(kg, state)) {
|
||||
ray->t = kernel_data.background.ao_distance;
|
||||
if (last_object != OBJECT_NONE) {
|
||||
const float object_ao_distance = kernel_tex_fetch(__objects, last_object).ao_distance;
|
||||
if (object_ao_distance != 0.0f) {
|
||||
ray->t = object_ao_distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool hit = scene_intersect(kg, ray, visibility, isect);
|
||||
@@ -253,7 +260,7 @@ ccl_device_forceinline bool kernel_path_shader_apply(KernelGlobals *kg,
|
||||
PROFILING_INIT(kg, PROFILING_SHADER_APPLY);
|
||||
|
||||
#ifdef __SHADOW_TRICKS__
|
||||
if ((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
|
||||
if (sd->object_flag & SD_OBJECT_SHADOW_CATCHER) {
|
||||
if (state->flag & PATH_RAY_TRANSPARENT_BACKGROUND) {
|
||||
state->flag |= (PATH_RAY_SHADOW_CATCHER | PATH_RAY_STORE_SHADOW_INFO);
|
||||
|
||||
@@ -369,7 +376,8 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
||||
Ray *ray,
|
||||
float3 throughput,
|
||||
PathState *state,
|
||||
PathRadiance *L)
|
||||
PathRadiance *L,
|
||||
const int last_object)
|
||||
{
|
||||
# ifdef __SUBSURFACE__
|
||||
SubsurfaceIndirectRays ss_indirect;
|
||||
@@ -382,7 +390,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
|
||||
for (;;) {
|
||||
/* Find intersection with objects in scene. */
|
||||
Intersection isect;
|
||||
bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L);
|
||||
bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L, last_object);
|
||||
|
||||
/* Find intersection with lamps and compute emission for MIS. */
|
||||
kernel_path_lamp_emission(kg, state, ray, throughput, &isect, sd, L);
|
||||
@@ -526,7 +534,7 @@ ccl_device_forceinline void kernel_path_integrate(KernelGlobals *kg,
|
||||
for (;;) {
|
||||
/* Find intersection with objects in scene. */
|
||||
Intersection isect;
|
||||
bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L);
|
||||
bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L, sd.object);
|
||||
|
||||
/* Find intersection with lamps and compute emission for MIS. */
|
||||
kernel_path_lamp_emission(kg, state, ray, throughput, &isect, &sd, L);
|
||||
|
@@ -92,6 +92,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg,
|
||||
volume_ray.t = (hit) ? isect->t : FLT_MAX;
|
||||
|
||||
float step_size = volume_stack_step_size(kg, state->volume_stack);
|
||||
const int object = sd->object;
|
||||
|
||||
# ifdef __VOLUME_DECOUPLED__
|
||||
/* decoupled ray marching only supported on CPU */
|
||||
@@ -134,7 +135,8 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg,
|
||||
|
||||
if (result == VOLUME_PATH_SCATTERED &&
|
||||
kernel_path_volume_bounce(kg, sd, &tp, &ps, &L->state, &pray)) {
|
||||
kernel_path_indirect(kg, indirect_sd, emission_sd, &pray, tp * num_samples_inv, &ps, L);
|
||||
kernel_path_indirect(
|
||||
kg, indirect_sd, emission_sd, &pray, tp * num_samples_inv, &ps, L, object);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
@@ -180,7 +182,7 @@ ccl_device_forceinline void kernel_branched_path_volume(KernelGlobals *kg,
|
||||
kernel_path_volume_connect_light(kg, sd, emission_sd, tp, state, L);
|
||||
|
||||
if (kernel_path_volume_bounce(kg, sd, &tp, &ps, &L->state, &pray)) {
|
||||
kernel_path_indirect(kg, indirect_sd, emission_sd, &pray, tp, &ps, L);
|
||||
kernel_path_indirect(kg, indirect_sd, emission_sd, &pray, tp, &ps, L, object);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
@@ -266,7 +268,8 @@ ccl_device_noinline_cpu void kernel_branched_path_surface_indirect_light(KernelG
|
||||
|
||||
ps.rng_hash = state->rng_hash;
|
||||
|
||||
kernel_path_indirect(kg, indirect_sd, emission_sd, &bsdf_ray, tp * num_samples_inv, &ps, L);
|
||||
kernel_path_indirect(
|
||||
kg, indirect_sd, emission_sd, &bsdf_ray, tp * num_samples_inv, &ps, L, sd->object);
|
||||
|
||||
/* for render passes, sum and reset indirect light pass variables
|
||||
* for the next samples */
|
||||
@@ -395,7 +398,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
|
||||
for (;;) {
|
||||
/* Find intersection with objects in scene. */
|
||||
Intersection isect;
|
||||
bool hit = kernel_path_scene_intersect(kg, &state, &ray, &isect, L);
|
||||
bool hit = kernel_path_scene_intersect(kg, &state, &ray, &isect, L, sd.object);
|
||||
|
||||
# ifdef __VOLUME__
|
||||
/* Volume integration. */
|
||||
|
@@ -1447,7 +1447,10 @@ typedef struct KernelObject {
|
||||
|
||||
float shadow_terminator_shading_offset;
|
||||
float shadow_terminator_geometry_offset;
|
||||
float pad1, pad2, pad3;
|
||||
|
||||
float ao_distance;
|
||||
|
||||
float pad1, pad2;
|
||||
} KernelObject;
|
||||
static_assert_align(KernelObject, 16);
|
||||
|
||||
|
@@ -58,7 +58,9 @@ shader node_texture_coordinate(
|
||||
getattribute("geom:uv", UV);
|
||||
}
|
||||
else {
|
||||
getattribute("geom:generated", Generated);
|
||||
if (!getattribute("geom:generated", Generated)) {
|
||||
Generated = transform("object", P);
|
||||
}
|
||||
getattribute("geom:uv", UV);
|
||||
}
|
||||
|
||||
|
@@ -65,7 +65,10 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg)
|
||||
PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
|
||||
|
||||
Intersection isect;
|
||||
bool hit = kernel_path_scene_intersect(kg, state, &ray, &isect, L);
|
||||
const int last_object = state->bounce > 0 ?
|
||||
intersection_get_object(kg, &kernel_split_state.isect[ray_index]) :
|
||||
OBJECT_NONE;
|
||||
bool hit = kernel_path_scene_intersect(kg, state, &ray, &isect, L, last_object);
|
||||
kernel_split_state.isect[ray_index] = isect;
|
||||
|
||||
if (!hit) {
|
||||
|
@@ -72,6 +72,22 @@ ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, u
|
||||
}
|
||||
#endif
|
||||
|
||||
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
|
||||
/* No generated attribute, fall back to object coordinates. */
|
||||
float3 f = sd->P;
|
||||
object_inverse_position_transform(kg, sd, &f);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
}
|
||||
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, out_offset, 1.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Surface. */
|
||||
if (desc.type == NODE_ATTR_FLOAT) {
|
||||
float f = primitive_surface_attribute_float(kg, sd, desc, NULL, NULL);
|
||||
@@ -145,6 +161,22 @@ ccl_device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *
|
||||
}
|
||||
#endif
|
||||
|
||||
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
|
||||
/* No generated attribute, fall back to object coordinates. */
|
||||
float3 f = sd->P + sd->dP.dx;
|
||||
object_inverse_position_transform(kg, sd, &f);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
}
|
||||
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, out_offset, 1.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Surface */
|
||||
if (desc.type == NODE_ATTR_FLOAT) {
|
||||
float dx;
|
||||
@@ -222,6 +254,22 @@ ccl_device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *
|
||||
}
|
||||
#endif
|
||||
|
||||
if (node.y == ATTR_STD_GENERATED && desc.element == ATTR_ELEMENT_NONE) {
|
||||
/* No generated attribute, fall back to object coordinates. */
|
||||
float3 f = sd->P + sd->dP.dy;
|
||||
object_inverse_position_transform(kg, sd, &f);
|
||||
if (type == NODE_ATTR_OUTPUT_FLOAT) {
|
||||
stack_store_float(stack, out_offset, average(f));
|
||||
}
|
||||
else if (type == NODE_ATTR_OUTPUT_FLOAT3) {
|
||||
stack_store_float3(stack, out_offset, f);
|
||||
}
|
||||
else {
|
||||
stack_store_float(stack, out_offset, 1.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Surface */
|
||||
if (desc.type == NODE_ATTR_FLOAT) {
|
||||
float dy;
|
||||
|
@@ -267,7 +267,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
|
||||
if (space == NODE_NORMAL_MAP_TANGENT) {
|
||||
/* tangent space */
|
||||
if (sd->object == OBJECT_NONE) {
|
||||
if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) {
|
||||
/* Fallback to unperturbed normal. */
|
||||
stack_store_float3(stack, normal_offset, sd->N);
|
||||
return;
|
||||
@@ -276,10 +276,8 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
/* first try to get tangent attribute */
|
||||
const AttributeDescriptor attr = find_attribute(kg, sd, node.z);
|
||||
const AttributeDescriptor attr_sign = find_attribute(kg, sd, node.w);
|
||||
const AttributeDescriptor attr_normal = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL);
|
||||
|
||||
if (attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND ||
|
||||
attr_normal.offset == ATTR_STD_NOT_FOUND) {
|
||||
if (attr.offset == ATTR_STD_NOT_FOUND || attr_sign.offset == ATTR_STD_NOT_FOUND) {
|
||||
/* Fallback to unperturbed normal. */
|
||||
stack_store_float3(stack, normal_offset, sd->N);
|
||||
return;
|
||||
@@ -291,7 +289,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
|
||||
float3 normal;
|
||||
|
||||
if (sd->shader & SHADER_SMOOTH_NORMAL) {
|
||||
normal = primitive_surface_attribute_float3(kg, sd, attr_normal, NULL, NULL);
|
||||
normal = triangle_smooth_normal_unnormalized(kg, sd->Ng, sd->prim, sd->u, sd->v);
|
||||
}
|
||||
else {
|
||||
normal = sd->Ng;
|
||||
|
@@ -959,14 +959,6 @@ void AlembicProcedural::read_mesh(AlembicObject *abc_object, Abc::chrono_t frame
|
||||
|
||||
update_attributes(mesh->attributes, cached_data, frame_time);
|
||||
|
||||
/* we don't yet support arbitrary attributes, for now add vertex
|
||||
* coordinates as generated coordinates if requested */
|
||||
if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) {
|
||||
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
|
||||
memcpy(
|
||||
attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
|
||||
}
|
||||
|
||||
if (mesh->is_modified()) {
|
||||
bool need_rebuild = mesh->triangles_is_modified();
|
||||
mesh->tag_update(scene_, need_rebuild);
|
||||
@@ -1053,14 +1045,6 @@ void AlembicProcedural::read_subd(AlembicObject *abc_object, Abc::chrono_t frame
|
||||
|
||||
update_attributes(mesh->subd_attributes, cached_data, frame_time);
|
||||
|
||||
/* we don't yet support arbitrary attributes, for now add vertex
|
||||
* coordinates as generated coordinates if requested */
|
||||
if (mesh->need_attribute(scene_, ATTR_STD_GENERATED)) {
|
||||
Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED);
|
||||
memcpy(
|
||||
attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size());
|
||||
}
|
||||
|
||||
if (mesh->is_modified()) {
|
||||
bool need_rebuild = (mesh->triangles_is_modified()) ||
|
||||
(mesh->subd_num_corners_is_modified()) ||
|
||||
@@ -1110,17 +1094,6 @@ void AlembicProcedural::read_curves(AlembicObject *abc_object, Abc::chrono_t fra
|
||||
|
||||
update_attributes(hair->attributes, cached_data, frame_time);
|
||||
|
||||
/* we don't yet support arbitrary attributes, for now add first keys as generated coordinates if
|
||||
* requested */
|
||||
if (hair->need_attribute(scene_, ATTR_STD_GENERATED)) {
|
||||
Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
|
||||
float3 *generated = attr_generated->data_float3();
|
||||
|
||||
for (size_t i = 0; i < hair->num_curves(); i++) {
|
||||
generated[i] = hair->get_curve_keys()[hair->get_curve(i).first_key];
|
||||
}
|
||||
}
|
||||
|
||||
const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
|
||||
hair->tag_update(scene_, rebuild);
|
||||
}
|
||||
|
@@ -788,6 +788,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
/* Vertex normals are stored in DeviceScene.tri_vnormal. */
|
||||
if (attr && attr->std == ATTR_STD_VERTEX_NORMAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
update_attribute_element_size(geom,
|
||||
attr,
|
||||
ATTR_PRIM_GEOMETRY,
|
||||
@@ -800,6 +805,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
/* Vertex normals are stored in DeviceScene.tri_vnormal. */
|
||||
if (subd_attr && subd_attr->std == ATTR_STD_VERTEX_NORMAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
update_attribute_element_size(mesh,
|
||||
subd_attr,
|
||||
ATTR_PRIM_SUBD,
|
||||
@@ -854,6 +864,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
if (attr) {
|
||||
/* Vertex normals are stored in DeviceScene.tri_vnormal. */
|
||||
if (attr->std == ATTR_STD_VERTEX_NORMAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
|
||||
}
|
||||
@@ -877,6 +892,11 @@ void GeometryManager::device_update_attributes(Device *device,
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
if (subd_attr) {
|
||||
/* Vertex normals are stored in DeviceScene.tri_vnormal. */
|
||||
if (subd_attr->std == ATTR_STD_VERTEX_NORMAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
|
||||
}
|
||||
|
@@ -158,13 +158,13 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
foreach (ShaderInput *input, inputs) {
|
||||
if (!input->link) {
|
||||
if (input->flags() & SocketType::LINK_TEXTURE_GENERATED) {
|
||||
if (shader->has_surface)
|
||||
if (shader->has_surface_link())
|
||||
attributes->add(ATTR_STD_GENERATED);
|
||||
if (shader->has_volume)
|
||||
attributes->add(ATTR_STD_GENERATED_TRANSFORM);
|
||||
}
|
||||
else if (input->flags() & SocketType::LINK_TEXTURE_UV) {
|
||||
if (shader->has_surface)
|
||||
if (shader->has_surface_link())
|
||||
attributes->add(ATTR_STD_UV);
|
||||
}
|
||||
}
|
||||
|
@@ -350,7 +350,7 @@ void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attribute
|
||||
#ifdef WITH_PTEX
|
||||
/* todo: avoid loading other texture coordinates when using ptex,
|
||||
* and hide texture coordinate socket in the UI */
|
||||
if (shader->has_surface && string_endswith(filename, ".ptx")) {
|
||||
if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
|
||||
/* ptex */
|
||||
attributes->add(ATTR_STD_PTEX_FACE_ID);
|
||||
attributes->add(ATTR_STD_PTEX_UV);
|
||||
@@ -552,7 +552,7 @@ ImageParams EnvironmentTextureNode::image_params() const
|
||||
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
#ifdef WITH_PTEX
|
||||
if (shader->has_surface && string_endswith(filename, ".ptx")) {
|
||||
if (shader->has_surface_link() && string_endswith(filename, ".ptx")) {
|
||||
/* ptex */
|
||||
attributes->add(ATTR_STD_PTEX_FACE_ID);
|
||||
attributes->add(ATTR_STD_PTEX_UV);
|
||||
@@ -2319,7 +2319,7 @@ AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(get_node_type())
|
||||
|
||||
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
ShaderInput *tangent_in = input("Tangent");
|
||||
|
||||
if (!tangent_in->link)
|
||||
@@ -2843,7 +2843,7 @@ bool PrincipledBsdfNode::has_surface_bssrdf()
|
||||
|
||||
void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
ShaderInput *tangent_in = input("Tangent");
|
||||
|
||||
if (!tangent_in->link)
|
||||
@@ -3684,7 +3684,7 @@ GeometryNode::GeometryNode() : ShaderNode(get_node_type())
|
||||
|
||||
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
if (!output("Tangent")->links.empty()) {
|
||||
attributes->add(ATTR_STD_GENERATED);
|
||||
}
|
||||
@@ -3830,7 +3830,7 @@ TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(get_node_type())
|
||||
|
||||
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
if (!from_dupli) {
|
||||
if (!output("Generated")->links.empty())
|
||||
attributes->add(ATTR_STD_GENERATED);
|
||||
@@ -4388,7 +4388,7 @@ HairInfoNode::HairInfoNode() : ShaderNode(get_node_type())
|
||||
|
||||
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
ShaderOutput *intercept_out = output("Intercept");
|
||||
|
||||
if (!intercept_out->links.empty())
|
||||
@@ -6744,7 +6744,7 @@ NormalMapNode::NormalMapNode() : ShaderNode(get_node_type())
|
||||
|
||||
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attributes->add(ATTR_STD_UV_TANGENT);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
||||
@@ -6838,7 +6838,7 @@ TangentNode::TangentNode() : ShaderNode(get_node_type())
|
||||
|
||||
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface) {
|
||||
if (shader->has_surface_link()) {
|
||||
if (direction_type == NODE_TANGENT_UVMAP) {
|
||||
if (attribute.empty())
|
||||
attributes->add(ATTR_STD_UV_TANGENT);
|
||||
@@ -7021,7 +7021,7 @@ void VectorDisplacementNode::constant_fold(const ConstantFolder &folder)
|
||||
|
||||
void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
|
||||
{
|
||||
if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (shader->has_surface_link() && space == NODE_NORMAL_MAP_TANGENT) {
|
||||
if (attribute.empty()) {
|
||||
attributes->add(ATTR_STD_UV_TANGENT);
|
||||
attributes->add(ATTR_STD_UV_TANGENT_SIGN);
|
||||
|
@@ -102,6 +102,8 @@ NODE_DEFINE(Object)
|
||||
SOCKET_NODE(particle_system, "Particle System", ParticleSystem::get_node_type());
|
||||
SOCKET_INT(particle_index, "Particle Index", 0);
|
||||
|
||||
SOCKET_FLOAT(ao_distance, "AO Distance", 0.0f);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -428,6 +430,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
|
||||
kobject.random_number = random_number;
|
||||
kobject.particle_index = particle_index;
|
||||
kobject.motion_offset = 0;
|
||||
kobject.ao_distance = ob->ao_distance;
|
||||
|
||||
if (geom->get_use_motion_blur()) {
|
||||
state->have_motion = true;
|
||||
|
@@ -73,6 +73,8 @@ class Object : public Node {
|
||||
NODE_SOCKET_API(ParticleSystem *, particle_system);
|
||||
NODE_SOCKET_API(int, particle_index);
|
||||
|
||||
NODE_SOCKET_API(float, ao_distance)
|
||||
|
||||
Object();
|
||||
~Object();
|
||||
|
||||
|
@@ -57,23 +57,26 @@ Session::Session(const SessionParams ¶ms_)
|
||||
stats(),
|
||||
profiler()
|
||||
{
|
||||
device_use_gl = ((params.device.type != DEVICE_CPU) && !params.background);
|
||||
device_use_gl_ = ((params.device.type != DEVICE_CPU) && !params.background);
|
||||
|
||||
TaskScheduler::init(params.threads);
|
||||
|
||||
session_thread = NULL;
|
||||
session_thread_ = NULL;
|
||||
scene = NULL;
|
||||
|
||||
reset_time = 0.0;
|
||||
last_update_time = 0.0;
|
||||
reset_time_ = 0.0;
|
||||
last_update_time_ = 0.0;
|
||||
|
||||
delayed_reset.do_reset = false;
|
||||
delayed_reset.samples = 0;
|
||||
delayed_reset_.do_reset = false;
|
||||
delayed_reset_.samples = 0;
|
||||
|
||||
display_outdated = false;
|
||||
gpu_draw_ready = false;
|
||||
gpu_need_display_buffer_update = false;
|
||||
pause = false;
|
||||
display_outdated_ = false;
|
||||
gpu_draw_ready_ = false;
|
||||
gpu_need_display_buffer_update_ = false;
|
||||
|
||||
pause_ = false;
|
||||
cancel_ = false;
|
||||
new_work_added_ = false;
|
||||
|
||||
buffers = NULL;
|
||||
display = NULL;
|
||||
@@ -127,25 +130,26 @@ Session::~Session()
|
||||
|
||||
void Session::start()
|
||||
{
|
||||
if (!session_thread) {
|
||||
session_thread = new thread(function_bind(&Session::run, this));
|
||||
if (!session_thread_) {
|
||||
session_thread_ = new thread(function_bind(&Session::run, this));
|
||||
}
|
||||
}
|
||||
|
||||
void Session::cancel()
|
||||
{
|
||||
if (session_thread) {
|
||||
if (session_thread_) {
|
||||
/* wait for session thread to end */
|
||||
progress.set_cancel("Exiting");
|
||||
|
||||
gpu_need_display_buffer_update = false;
|
||||
gpu_need_display_buffer_update_cond.notify_all();
|
||||
gpu_need_display_buffer_update_ = false;
|
||||
gpu_need_display_buffer_update_cond_.notify_all();
|
||||
|
||||
{
|
||||
thread_scoped_lock pause_lock(pause_mutex);
|
||||
pause = false;
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
pause_ = false;
|
||||
cancel_ = true;
|
||||
}
|
||||
pause_cond.notify_all();
|
||||
pause_cond_.notify_all();
|
||||
|
||||
wait();
|
||||
}
|
||||
@@ -153,9 +157,9 @@ void Session::cancel()
|
||||
|
||||
bool Session::ready_to_reset()
|
||||
{
|
||||
double dt = time_dt() - reset_time;
|
||||
double dt = time_dt() - reset_time_;
|
||||
|
||||
if (!display_outdated)
|
||||
if (!display_outdated_)
|
||||
return (dt > params.reset_timeout);
|
||||
else
|
||||
return (dt > params.cancel_timeout);
|
||||
@@ -165,48 +169,50 @@ bool Session::ready_to_reset()
|
||||
|
||||
void Session::reset_gpu(BufferParams &buffer_params, int samples)
|
||||
{
|
||||
thread_scoped_lock pause_lock(pause_mutex);
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
|
||||
/* block for buffer access and reset immediately. we can't do this
|
||||
* in the thread, because we need to allocate an OpenGL buffer, and
|
||||
* that only works in the main thread */
|
||||
thread_scoped_lock display_lock(display_mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
thread_scoped_lock display_lock(display_mutex_);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
|
||||
display_outdated = true;
|
||||
reset_time = time_dt();
|
||||
display_outdated_ = true;
|
||||
reset_time_ = time_dt();
|
||||
|
||||
reset_(buffer_params, samples);
|
||||
|
||||
gpu_need_display_buffer_update = false;
|
||||
gpu_need_display_buffer_update_cond.notify_all();
|
||||
gpu_need_display_buffer_update_ = false;
|
||||
gpu_need_display_buffer_update_cond_.notify_all();
|
||||
|
||||
pause_cond.notify_all();
|
||||
new_work_added_ = true;
|
||||
|
||||
pause_cond_.notify_all();
|
||||
}
|
||||
|
||||
bool Session::draw_gpu(BufferParams &buffer_params, DeviceDrawParams &draw_params)
|
||||
{
|
||||
/* block for buffer access */
|
||||
thread_scoped_lock display_lock(display_mutex);
|
||||
thread_scoped_lock display_lock(display_mutex_);
|
||||
|
||||
/* first check we already rendered something */
|
||||
if (gpu_draw_ready) {
|
||||
if (gpu_draw_ready_) {
|
||||
/* then verify the buffers have the expected size, so we don't
|
||||
* draw previous results in a resized window */
|
||||
if (buffer_params.width == display->params.width &&
|
||||
buffer_params.height == display->params.height) {
|
||||
/* for CUDA we need to do tone-mapping still, since we can
|
||||
* only access GL buffers from the main thread. */
|
||||
if (gpu_need_display_buffer_update) {
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
if (gpu_need_display_buffer_update_) {
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
copy_to_display_buffer(tile_manager.state.sample);
|
||||
gpu_need_display_buffer_update = false;
|
||||
gpu_need_display_buffer_update_cond.notify_all();
|
||||
gpu_need_display_buffer_update_ = false;
|
||||
gpu_need_display_buffer_update_cond_.notify_all();
|
||||
}
|
||||
|
||||
display->draw(device, draw_params);
|
||||
|
||||
if (display_outdated && (time_dt() - reset_time) > params.text_timeout)
|
||||
if (display_outdated_ && (time_dt() - reset_time_) > params.text_timeout)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -220,9 +226,9 @@ void Session::run_gpu()
|
||||
{
|
||||
bool tiles_written = false;
|
||||
|
||||
reset_time = time_dt();
|
||||
last_update_time = time_dt();
|
||||
last_display_time = last_update_time;
|
||||
reset_time_ = time_dt();
|
||||
last_update_time_ = time_dt();
|
||||
last_display_time_ = last_update_time_;
|
||||
|
||||
progress.set_render_start_time();
|
||||
|
||||
@@ -255,7 +261,7 @@ void Session::run_gpu()
|
||||
/* buffers mutex is locked entirely while rendering each
|
||||
* sample, and released/reacquired on each iteration to allow
|
||||
* reset and draw in between */
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
|
||||
/* update status and timing */
|
||||
update_status_time();
|
||||
@@ -273,17 +279,17 @@ void Session::run_gpu()
|
||||
/* update status and timing */
|
||||
update_status_time();
|
||||
|
||||
gpu_need_display_buffer_update = !delayed_denoise;
|
||||
gpu_draw_ready = true;
|
||||
gpu_need_display_buffer_update_ = !delayed_denoise;
|
||||
gpu_draw_ready_ = true;
|
||||
progress.set_update();
|
||||
|
||||
/* wait for until display buffer is updated */
|
||||
if (!params.background) {
|
||||
while (gpu_need_display_buffer_update) {
|
||||
while (gpu_need_display_buffer_update_) {
|
||||
if (progress.get_cancel())
|
||||
break;
|
||||
|
||||
gpu_need_display_buffer_update_cond.wait(buffers_lock);
|
||||
gpu_need_display_buffer_update_cond_.wait(buffers_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,23 +311,23 @@ void Session::run_gpu()
|
||||
|
||||
void Session::reset_cpu(BufferParams &buffer_params, int samples)
|
||||
{
|
||||
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
||||
thread_scoped_lock pause_lock(pause_mutex);
|
||||
thread_scoped_lock reset_lock(delayed_reset_.mutex);
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
|
||||
display_outdated = true;
|
||||
reset_time = time_dt();
|
||||
display_outdated_ = true;
|
||||
reset_time_ = time_dt();
|
||||
|
||||
delayed_reset.params = buffer_params;
|
||||
delayed_reset.samples = samples;
|
||||
delayed_reset.do_reset = true;
|
||||
delayed_reset_.params = buffer_params;
|
||||
delayed_reset_.samples = samples;
|
||||
delayed_reset_.do_reset = true;
|
||||
device->task_cancel();
|
||||
|
||||
pause_cond.notify_all();
|
||||
pause_cond_.notify_all();
|
||||
}
|
||||
|
||||
bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_params)
|
||||
{
|
||||
thread_scoped_lock display_lock(display_mutex);
|
||||
thread_scoped_lock display_lock(display_mutex_);
|
||||
|
||||
/* first check we already rendered something */
|
||||
if (display->draw_ready()) {
|
||||
@@ -331,7 +337,7 @@ bool Session::draw_cpu(BufferParams &buffer_params, DeviceDrawParams &draw_param
|
||||
buffer_params.height == display->params.height) {
|
||||
display->draw(device, draw_params);
|
||||
|
||||
if (display_outdated && (time_dt() - reset_time) > params.text_timeout)
|
||||
if (display_outdated_ && (time_dt() - reset_time_) > params.text_timeout)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
@@ -345,46 +351,46 @@ bool Session::steal_tile(RenderTile &rtile, Device *tile_device, thread_scoped_l
|
||||
{
|
||||
/* Devices that can get their tiles stolen don't steal tiles themselves.
|
||||
* Additionally, if there are no stealable tiles in flight, give up here. */
|
||||
if (tile_device->info.type == DEVICE_CPU || stealable_tiles == 0) {
|
||||
if (tile_device->info.type == DEVICE_CPU || stealable_tiles_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Wait until no other thread is trying to steal a tile. */
|
||||
while (tile_stealing_state != NOT_STEALING && stealable_tiles > 0) {
|
||||
while (tile_stealing_state_ != NOT_STEALING && stealable_tiles_ > 0) {
|
||||
/* Someone else is currently trying to get a tile.
|
||||
* Wait on the condition variable and try later. */
|
||||
tile_steal_cond.wait(tile_lock);
|
||||
tile_steal_cond_.wait(tile_lock);
|
||||
}
|
||||
/* If another thread stole the last stealable tile in the meantime, give up. */
|
||||
if (stealable_tiles == 0) {
|
||||
if (stealable_tiles_ == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* There are stealable tiles in flight, so signal that one should be released. */
|
||||
tile_stealing_state = WAITING_FOR_TILE;
|
||||
tile_stealing_state_ = WAITING_FOR_TILE;
|
||||
|
||||
/* Wait until a device notices the signal and releases its tile. */
|
||||
while (tile_stealing_state != GOT_TILE && stealable_tiles > 0) {
|
||||
tile_steal_cond.wait(tile_lock);
|
||||
while (tile_stealing_state_ != GOT_TILE && stealable_tiles_ > 0) {
|
||||
tile_steal_cond_.wait(tile_lock);
|
||||
}
|
||||
/* If the last stealable tile finished on its own, give up. */
|
||||
if (tile_stealing_state != GOT_TILE) {
|
||||
tile_stealing_state = NOT_STEALING;
|
||||
if (tile_stealing_state_ != GOT_TILE) {
|
||||
tile_stealing_state_ = NOT_STEALING;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Successfully stole a tile, now move it to the new device. */
|
||||
rtile = stolen_tile;
|
||||
rtile = stolen_tile_;
|
||||
rtile.buffers->buffer.move_device(tile_device);
|
||||
rtile.buffer = rtile.buffers->buffer.device_pointer;
|
||||
rtile.stealing_state = RenderTile::NO_STEALING;
|
||||
rtile.num_samples -= (rtile.sample - rtile.start_sample);
|
||||
rtile.start_sample = rtile.sample;
|
||||
|
||||
tile_stealing_state = NOT_STEALING;
|
||||
tile_stealing_state_ = NOT_STEALING;
|
||||
|
||||
/* Poke any threads which might be waiting for NOT_STEALING above. */
|
||||
tile_steal_cond.notify_one();
|
||||
tile_steal_cond_.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -394,7 +400,7 @@ bool Session::get_tile_stolen()
|
||||
/* If tile_stealing_state is WAITING_FOR_TILE, atomically set it to RELEASING_TILE
|
||||
* and return true. */
|
||||
TileStealingState expected = WAITING_FOR_TILE;
|
||||
return tile_stealing_state.compare_exchange_weak(expected, RELEASING_TILE);
|
||||
return tile_stealing_state_.compare_exchange_weak(expected, RELEASING_TILE);
|
||||
}
|
||||
|
||||
bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_types)
|
||||
@@ -406,7 +412,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
}
|
||||
}
|
||||
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
|
||||
/* get next tile from manager */
|
||||
Tile *tile;
|
||||
@@ -423,7 +429,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
|
||||
/* Wait for denoising tiles to become available */
|
||||
if ((tile_types & RenderTile::DENOISE) && !progress.get_cancel() && tile_manager.has_tiles()) {
|
||||
denoising_cond.wait(tile_lock);
|
||||
denoising_cond_.wait(tile_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -446,7 +452,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
}
|
||||
else {
|
||||
if (tile_device->info.type == DEVICE_CPU) {
|
||||
stealable_tiles++;
|
||||
stealable_tiles_++;
|
||||
rtile.stealing_state = RenderTile::CAN_BE_STOLEN;
|
||||
}
|
||||
|
||||
@@ -515,7 +521,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
/* This will read any passes needed as input for baking. */
|
||||
if (tile_manager.state.sample == tile_manager.range_start_sample) {
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
read_bake_tile_cb(rtile);
|
||||
}
|
||||
rtile.buffers->buffer.copy_to_device();
|
||||
@@ -533,7 +539,7 @@ bool Session::acquire_tile(RenderTile &rtile, Device *tile_device, uint tile_typ
|
||||
|
||||
void Session::update_tile_sample(RenderTile &rtile)
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
|
||||
if (update_render_tile_cb) {
|
||||
if (params.progressive_refine == false) {
|
||||
@@ -548,25 +554,25 @@ void Session::update_tile_sample(RenderTile &rtile)
|
||||
|
||||
void Session::release_tile(RenderTile &rtile, const bool need_denoise)
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
|
||||
if (rtile.stealing_state != RenderTile::NO_STEALING) {
|
||||
stealable_tiles--;
|
||||
stealable_tiles_--;
|
||||
if (rtile.stealing_state == RenderTile::WAS_STOLEN) {
|
||||
/* If the tile is being stolen, don't release it here - the new device will pick up where
|
||||
* the old one left off. */
|
||||
|
||||
assert(tile_stealing_state == RELEASING_TILE);
|
||||
assert(tile_stealing_state_ == RELEASING_TILE);
|
||||
assert(rtile.sample < rtile.start_sample + rtile.num_samples);
|
||||
|
||||
tile_stealing_state = GOT_TILE;
|
||||
stolen_tile = rtile;
|
||||
tile_steal_cond.notify_all();
|
||||
tile_stealing_state_ = GOT_TILE;
|
||||
stolen_tile_ = rtile;
|
||||
tile_steal_cond_.notify_all();
|
||||
return;
|
||||
}
|
||||
else if (stealable_tiles == 0) {
|
||||
else if (stealable_tiles_ == 0) {
|
||||
/* If this was the last stealable tile, wake up any threads still waiting for one. */
|
||||
tile_steal_cond.notify_all();
|
||||
tile_steal_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -595,12 +601,12 @@ void Session::release_tile(RenderTile &rtile, const bool need_denoise)
|
||||
update_status_time();
|
||||
|
||||
/* Notify denoising thread that a tile was finished. */
|
||||
denoising_cond.notify_all();
|
||||
denoising_cond_.notify_all();
|
||||
}
|
||||
|
||||
void Session::map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
|
||||
const int4 image_region = make_int4(
|
||||
tile_manager.state.buffer.full_x,
|
||||
@@ -677,7 +683,7 @@ void Session::map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_de
|
||||
|
||||
void Session::unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device)
|
||||
{
|
||||
thread_scoped_lock tile_lock(tile_mutex);
|
||||
thread_scoped_lock tile_lock(tile_mutex_);
|
||||
device->unmap_neighbor_tiles(tile_device, neighbors);
|
||||
}
|
||||
|
||||
@@ -685,8 +691,8 @@ void Session::run_cpu()
|
||||
{
|
||||
bool tiles_written = false;
|
||||
|
||||
last_update_time = time_dt();
|
||||
last_display_time = last_update_time;
|
||||
last_update_time_ = time_dt();
|
||||
last_display_time_ = last_update_time_;
|
||||
|
||||
while (!progress.get_cancel()) {
|
||||
const bool no_tiles = !run_update_for_next_iteration();
|
||||
@@ -718,7 +724,7 @@ void Session::run_cpu()
|
||||
/* buffers mutex is locked entirely while rendering each
|
||||
* sample, and released/reacquired on each iteration to allow
|
||||
* reset and draw in between */
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
|
||||
/* update status and timing */
|
||||
update_status_time();
|
||||
@@ -741,14 +747,14 @@ void Session::run_cpu()
|
||||
device->task_wait();
|
||||
|
||||
{
|
||||
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
thread_scoped_lock display_lock(display_mutex);
|
||||
thread_scoped_lock reset_lock(delayed_reset_.mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
thread_scoped_lock display_lock(display_mutex_);
|
||||
|
||||
if (delayed_reset.do_reset) {
|
||||
if (delayed_reset_.do_reset) {
|
||||
/* reset rendering if request from main thread */
|
||||
delayed_reset.do_reset = false;
|
||||
reset_(delayed_reset.params, delayed_reset.samples);
|
||||
delayed_reset_.do_reset = false;
|
||||
reset_(delayed_reset_.params, delayed_reset_.samples);
|
||||
}
|
||||
else if (need_copy_to_display_buffer) {
|
||||
/* Only copy to display_buffer if we do not reset, we don't
|
||||
@@ -783,7 +789,7 @@ void Session::run()
|
||||
/* reset number of rendered samples */
|
||||
progress.reset_sample();
|
||||
|
||||
if (device_use_gl)
|
||||
if (device_use_gl_)
|
||||
run_gpu();
|
||||
else
|
||||
run_cpu();
|
||||
@@ -801,12 +807,12 @@ void Session::run()
|
||||
bool Session::run_update_for_next_iteration()
|
||||
{
|
||||
thread_scoped_lock scene_lock(scene->mutex);
|
||||
thread_scoped_lock reset_lock(delayed_reset.mutex);
|
||||
thread_scoped_lock reset_lock(delayed_reset_.mutex);
|
||||
|
||||
if (delayed_reset.do_reset) {
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
reset_(delayed_reset.params, delayed_reset.samples);
|
||||
delayed_reset.do_reset = false;
|
||||
if (delayed_reset_.do_reset) {
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
reset_(delayed_reset_.params, delayed_reset_.samples);
|
||||
delayed_reset_.do_reset = false;
|
||||
}
|
||||
|
||||
const bool have_tiles = tile_manager.next();
|
||||
@@ -829,35 +835,43 @@ bool Session::run_wait_for_work(bool no_tiles)
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_scoped_lock pause_lock(pause_mutex);
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
|
||||
if (!pause && !no_tiles) {
|
||||
if (!pause_ && !no_tiles) {
|
||||
/* Rendering is not paused and there is work to be done. No need to wait for anything. */
|
||||
return false;
|
||||
}
|
||||
|
||||
update_status_time(pause, no_tiles);
|
||||
update_status_time(pause_, no_tiles);
|
||||
|
||||
while (true) {
|
||||
/* Only leave the loop when rendering is not paused. But even if the current render is un-paused
|
||||
* but there is nothing to render keep waiting until new work is added. */
|
||||
while (!cancel_) {
|
||||
scoped_timer pause_timer;
|
||||
pause_cond.wait(pause_lock);
|
||||
if (pause) {
|
||||
|
||||
if (!pause_ && (!no_tiles || new_work_added_ || delayed_reset_.do_reset)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait for either pause state changed, or extra samples added to render. */
|
||||
pause_cond_.wait(pause_lock);
|
||||
|
||||
if (pause_) {
|
||||
progress.add_skip_time(pause_timer, params.background);
|
||||
}
|
||||
|
||||
update_status_time(pause, no_tiles);
|
||||
update_status_time(pause_, no_tiles);
|
||||
progress.set_update();
|
||||
|
||||
if (!pause) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new_work_added_ = false;
|
||||
|
||||
return no_tiles;
|
||||
}
|
||||
|
||||
bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params)
|
||||
{
|
||||
if (device_use_gl)
|
||||
if (device_use_gl_)
|
||||
return draw_gpu(buffer_params, draw_params);
|
||||
else
|
||||
return draw_cpu(buffer_params, draw_params);
|
||||
@@ -866,7 +880,7 @@ bool Session::draw(BufferParams &buffer_params, DeviceDrawParams &draw_params)
|
||||
void Session::reset_(BufferParams &buffer_params, int samples)
|
||||
{
|
||||
if (buffers && buffer_params.modified(tile_manager.params)) {
|
||||
gpu_draw_ready = false;
|
||||
gpu_draw_ready_ = false;
|
||||
buffers->reset(buffer_params);
|
||||
if (display) {
|
||||
display->reset(buffer_params);
|
||||
@@ -874,8 +888,8 @@ void Session::reset_(BufferParams &buffer_params, int samples)
|
||||
}
|
||||
|
||||
tile_manager.reset(buffer_params, samples);
|
||||
stealable_tiles = 0;
|
||||
tile_stealing_state = NOT_STEALING;
|
||||
stealable_tiles_ = 0;
|
||||
tile_stealing_state_ = NOT_STEALING;
|
||||
progress.reset_sample();
|
||||
|
||||
bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX;
|
||||
@@ -888,7 +902,7 @@ void Session::reset_(BufferParams &buffer_params, int samples)
|
||||
|
||||
void Session::reset(BufferParams &buffer_params, int samples)
|
||||
{
|
||||
if (device_use_gl)
|
||||
if (device_use_gl_)
|
||||
reset_gpu(buffer_params, samples);
|
||||
else
|
||||
reset_cpu(buffer_params, samples);
|
||||
@@ -896,30 +910,37 @@ void Session::reset(BufferParams &buffer_params, int samples)
|
||||
|
||||
void Session::set_samples(int samples)
|
||||
{
|
||||
if (samples != params.samples) {
|
||||
params.samples = samples;
|
||||
tile_manager.set_samples(samples);
|
||||
|
||||
pause_cond.notify_all();
|
||||
if (samples == params.samples) {
|
||||
return;
|
||||
}
|
||||
|
||||
params.samples = samples;
|
||||
tile_manager.set_samples(samples);
|
||||
|
||||
{
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
new_work_added_ = true;
|
||||
}
|
||||
|
||||
pause_cond_.notify_all();
|
||||
}
|
||||
|
||||
void Session::set_pause(bool pause_)
|
||||
void Session::set_pause(bool pause)
|
||||
{
|
||||
bool notify = false;
|
||||
|
||||
{
|
||||
thread_scoped_lock pause_lock(pause_mutex);
|
||||
thread_scoped_lock pause_lock(pause_mutex_);
|
||||
|
||||
if (pause != pause_) {
|
||||
pause = pause_;
|
||||
pause_ = pause;
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (session_thread) {
|
||||
if (session_thread_) {
|
||||
if (notify) {
|
||||
pause_cond.notify_all();
|
||||
pause_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
else if (pause_) {
|
||||
@@ -932,7 +953,7 @@ void Session::set_denoising(const DenoiseParams &denoising)
|
||||
bool need_denoise = denoising.need_denoising_task();
|
||||
|
||||
/* Lock buffers so no denoising operation is triggered while the settings are changed here. */
|
||||
thread_scoped_lock buffers_lock(buffers_mutex);
|
||||
thread_scoped_lock buffers_lock(buffers_mutex_);
|
||||
params.denoising = denoising;
|
||||
|
||||
if (!(params.device.denoisers & denoising.type)) {
|
||||
@@ -957,18 +978,18 @@ void Session::set_denoising_start_sample(int sample)
|
||||
if (sample != params.denoising.start_sample) {
|
||||
params.denoising.start_sample = sample;
|
||||
|
||||
pause_cond.notify_all();
|
||||
pause_cond_.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void Session::wait()
|
||||
{
|
||||
if (session_thread) {
|
||||
session_thread->join();
|
||||
delete session_thread;
|
||||
if (session_thread_) {
|
||||
session_thread_->join();
|
||||
delete session_thread_;
|
||||
}
|
||||
|
||||
session_thread = NULL;
|
||||
session_thread_ = NULL;
|
||||
}
|
||||
|
||||
bool Session::update_scene()
|
||||
@@ -1099,7 +1120,7 @@ bool Session::render_need_denoise(bool &delayed)
|
||||
|
||||
/* Avoid excessive denoising in viewport after reaching a certain amount of samples. */
|
||||
delayed = (tile_manager.state.sample >= 20 &&
|
||||
(time_dt() - last_display_time) < params.progressive_update_timeout);
|
||||
(time_dt() - last_display_time_) < params.progressive_update_timeout);
|
||||
return !delayed;
|
||||
}
|
||||
|
||||
@@ -1197,10 +1218,10 @@ void Session::copy_to_display_buffer(int sample)
|
||||
/* set display to new size */
|
||||
display->draw_set(task.w, task.h);
|
||||
|
||||
last_display_time = time_dt();
|
||||
last_display_time_ = time_dt();
|
||||
}
|
||||
|
||||
display_outdated = false;
|
||||
display_outdated_ = false;
|
||||
}
|
||||
|
||||
bool Session::update_progressive_refine(bool cancel)
|
||||
@@ -1210,7 +1231,7 @@ bool Session::update_progressive_refine(bool cancel)
|
||||
|
||||
double current_time = time_dt();
|
||||
|
||||
if (current_time - last_update_time < params.progressive_update_timeout) {
|
||||
if (current_time - last_update_time_ < params.progressive_update_timeout) {
|
||||
/* If last sample was processed, we need to write buffers anyway. */
|
||||
if (!write && sample != 1)
|
||||
return false;
|
||||
@@ -1241,7 +1262,7 @@ bool Session::update_progressive_refine(bool cancel)
|
||||
}
|
||||
}
|
||||
|
||||
last_update_time = current_time;
|
||||
last_update_time_ = current_time;
|
||||
|
||||
return write;
|
||||
}
|
||||
|
@@ -174,7 +174,7 @@ class Session {
|
||||
bool do_reset;
|
||||
BufferParams params;
|
||||
int samples;
|
||||
} delayed_reset;
|
||||
} delayed_reset_;
|
||||
|
||||
void run();
|
||||
|
||||
@@ -207,38 +207,41 @@ class Session {
|
||||
void map_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
|
||||
void unmap_neighbor_tiles(RenderTileNeighbors &neighbors, Device *tile_device);
|
||||
|
||||
bool device_use_gl;
|
||||
bool device_use_gl_;
|
||||
|
||||
thread *session_thread;
|
||||
thread *session_thread_;
|
||||
|
||||
volatile bool display_outdated;
|
||||
volatile bool display_outdated_;
|
||||
|
||||
volatile bool gpu_draw_ready;
|
||||
volatile bool gpu_need_display_buffer_update;
|
||||
thread_condition_variable gpu_need_display_buffer_update_cond;
|
||||
volatile bool gpu_draw_ready_;
|
||||
volatile bool gpu_need_display_buffer_update_;
|
||||
thread_condition_variable gpu_need_display_buffer_update_cond_;
|
||||
|
||||
bool pause;
|
||||
thread_condition_variable pause_cond;
|
||||
thread_mutex pause_mutex;
|
||||
thread_mutex tile_mutex;
|
||||
thread_mutex buffers_mutex;
|
||||
thread_mutex display_mutex;
|
||||
thread_condition_variable denoising_cond;
|
||||
thread_condition_variable tile_steal_cond;
|
||||
bool pause_;
|
||||
bool cancel_;
|
||||
bool new_work_added_;
|
||||
|
||||
double reset_time;
|
||||
double last_update_time;
|
||||
double last_display_time;
|
||||
thread_condition_variable pause_cond_;
|
||||
thread_mutex pause_mutex_;
|
||||
thread_mutex tile_mutex_;
|
||||
thread_mutex buffers_mutex_;
|
||||
thread_mutex display_mutex_;
|
||||
thread_condition_variable denoising_cond_;
|
||||
thread_condition_variable tile_steal_cond_;
|
||||
|
||||
RenderTile stolen_tile;
|
||||
double reset_time_;
|
||||
double last_update_time_;
|
||||
double last_display_time_;
|
||||
|
||||
RenderTile stolen_tile_;
|
||||
typedef enum {
|
||||
NOT_STEALING, /* There currently is no tile stealing in progress. */
|
||||
WAITING_FOR_TILE, /* A device is waiting for another device to release a tile. */
|
||||
RELEASING_TILE, /* A device has releasing a stealable tile. */
|
||||
GOT_TILE /* A device has released a stealable tile, which is now stored in stolen_tile. */
|
||||
} TileStealingState;
|
||||
std::atomic<TileStealingState> tile_stealing_state;
|
||||
int stealable_tiles;
|
||||
std::atomic<TileStealingState> tile_stealing_state_;
|
||||
int stealable_tiles_;
|
||||
|
||||
/* progressive refine */
|
||||
bool update_progressive_refine(bool cancel);
|
||||
|
@@ -154,6 +154,14 @@ class Shader : public Node {
|
||||
void tag_update(Scene *scene);
|
||||
void tag_used(Scene *scene);
|
||||
|
||||
/* Return true when either of the surface or displacement socket of the output node is linked.
|
||||
* This should be used to ensure that surface attributes are also requested even when only the
|
||||
* displacement socket is linked. */
|
||||
bool has_surface_link() const
|
||||
{
|
||||
return has_surface || has_displacement;
|
||||
}
|
||||
|
||||
bool need_update_geometry() const;
|
||||
};
|
||||
|
||||
|
@@ -1066,22 +1066,6 @@ void GHOST_XrDestroyActions(GHOST_XrContextHandle xr_context,
|
||||
uint32_t count,
|
||||
const char *const *action_names);
|
||||
|
||||
/**
|
||||
* Create spaces for pose-based OpenXR actions.
|
||||
*/
|
||||
int GHOST_XrCreateActionSpaces(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos);
|
||||
|
||||
/**
|
||||
* Destroy previously created spaces for OpenXR actions.
|
||||
*/
|
||||
void GHOST_XrDestroyActionSpaces(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos);
|
||||
|
||||
/**
|
||||
* Create input/output path bindings for OpenXR actions.
|
||||
*/
|
||||
@@ -1096,7 +1080,8 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_context,
|
||||
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos);
|
||||
const char *const *action_names,
|
||||
const char *const *profile_paths);
|
||||
|
||||
/**
|
||||
* Attach all created action sets to the current OpenXR session.
|
||||
@@ -1117,6 +1102,7 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_context, const char *action_set
|
||||
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const int64_t *duration,
|
||||
const float *frequency,
|
||||
const float *amplitude);
|
||||
@@ -1126,7 +1112,8 @@ int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
|
||||
*/
|
||||
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
const char *action_name);
|
||||
const char *action_name,
|
||||
const char *subaction_path);
|
||||
|
||||
/**
|
||||
* Get action set custom data (owned by Blender, not GHOST).
|
||||
@@ -1141,6 +1128,18 @@ void *GHOST_XrGetActionCustomdata(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
const char *action_name);
|
||||
|
||||
/**
|
||||
* Get the number of actions in an action set.
|
||||
*/
|
||||
unsigned int GHOST_XrGetActionCount(GHOST_XrContextHandle xr_context, const char *action_set_name);
|
||||
|
||||
/**
|
||||
* Get custom data for all actions in an action set.
|
||||
*/
|
||||
void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_context,
|
||||
const char *action_set_name,
|
||||
void **r_customdata_array);
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -669,6 +669,14 @@ typedef struct {
|
||||
void *exit_customdata;
|
||||
} GHOST_XrSessionBeginInfo;
|
||||
|
||||
/** Texture format for XR swapchain. */
|
||||
typedef enum GHOST_TXrSwapchainFormat {
|
||||
GHOST_kXrSwapchainFormatRGBA8,
|
||||
GHOST_kXrSwapchainFormatRGBA16,
|
||||
GHOST_kXrSwapchainFormatRGBA16F,
|
||||
GHOST_kXrSwapchainFormatRGB10_A2,
|
||||
} GHOST_TXrSwapchainFormat;
|
||||
|
||||
typedef struct GHOST_XrDrawViewInfo {
|
||||
int ofsx, ofsy;
|
||||
int width, height;
|
||||
@@ -681,6 +689,7 @@ typedef struct GHOST_XrDrawViewInfo {
|
||||
float angle_up, angle_down;
|
||||
} fov;
|
||||
|
||||
GHOST_TXrSwapchainFormat swapchain_format;
|
||||
/** Set if the buffer should be submitted with a SRGB transfer applied. */
|
||||
char expects_srgb_buffer;
|
||||
|
||||
@@ -719,29 +728,27 @@ typedef struct GHOST_XrActionInfo {
|
||||
const char **subaction_paths;
|
||||
/** States for each subaction path. */
|
||||
void *states;
|
||||
/** Input thresholds/regions for each subaction path. */
|
||||
float *float_thresholds;
|
||||
int16_t *axis_flags;
|
||||
|
||||
GHOST_XrCustomdataFreeFn customdata_free_fn;
|
||||
void *customdata; /* wmXrAction */
|
||||
} GHOST_XrActionInfo;
|
||||
|
||||
typedef struct GHOST_XrActionSpaceInfo {
|
||||
const char *action_name;
|
||||
uint32_t count_subaction_paths;
|
||||
const char **subaction_paths;
|
||||
/** Poses for each subaction path. */
|
||||
const GHOST_XrPose *poses;
|
||||
} GHOST_XrActionSpaceInfo;
|
||||
|
||||
typedef struct GHOST_XrActionBindingInfo {
|
||||
const char *action_name;
|
||||
uint32_t count_interaction_paths;
|
||||
/** Interaction path: User (sub-action) path + component path. */
|
||||
const char **interaction_paths;
|
||||
const char *component_path;
|
||||
float float_threshold;
|
||||
int16_t axis_flag;
|
||||
GHOST_XrPose pose;
|
||||
} GHOST_XrActionBindingInfo;
|
||||
|
||||
typedef struct GHOST_XrActionProfileInfo {
|
||||
const char *action_name;
|
||||
const char *profile_path;
|
||||
uint32_t count_bindings;
|
||||
uint32_t count_subaction_paths;
|
||||
const char **subaction_paths;
|
||||
/* Bindings for each subaction path. */
|
||||
const GHOST_XrActionBindingInfo *bindings;
|
||||
} GHOST_XrActionProfileInfo;
|
||||
|
||||
|
@@ -961,28 +961,6 @@ void GHOST_XrDestroyActions(GHOST_XrContextHandle xr_contexthandle,
|
||||
GHOST_XR_CAPI_CALL(xr_session->destroyActions(action_set_name, count, action_names), xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrCreateActionSpaces(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->createActionSpaces(action_set_name, count, infos),
|
||||
xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GHOST_XrDestroyActionSpaces(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL(xr_session->destroyActionSpaces(action_set_name, count, infos), xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
@@ -998,11 +976,14 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
||||
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos)
|
||||
const char *const *action_names,
|
||||
const char *const *profile_paths)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL(xr_session->destroyActionBindings(action_set_name, count, infos), xr_context);
|
||||
GHOST_XR_CAPI_CALL(
|
||||
xr_session->destroyActionBindings(action_set_name, count, action_names, profile_paths),
|
||||
xr_context);
|
||||
}
|
||||
|
||||
int GHOST_XrAttachActionSets(GHOST_XrContextHandle xr_contexthandle)
|
||||
@@ -1024,25 +1005,29 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_contexthandle, const char *acti
|
||||
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const int64_t *duration,
|
||||
const float *frequency,
|
||||
const float *amplitude)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->applyHapticAction(
|
||||
action_set_name, action_name, *duration, *frequency, *amplitude),
|
||||
xr_context);
|
||||
GHOST_XR_CAPI_CALL_RET(
|
||||
xr_session->applyHapticAction(
|
||||
action_set_name, action_name, subaction_path, *duration, *frequency, *amplitude),
|
||||
xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
const char *action_name)
|
||||
const char *action_name,
|
||||
const char *subaction_path)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL(xr_session->stopHapticAction(action_set_name, action_name), xr_context);
|
||||
GHOST_XR_CAPI_CALL(xr_session->stopHapticAction(action_set_name, action_name, subaction_path),
|
||||
xr_context);
|
||||
}
|
||||
|
||||
void *GHOST_XrGetActionSetCustomdata(GHOST_XrContextHandle xr_contexthandle,
|
||||
@@ -1065,4 +1050,23 @@ void *GHOST_XrGetActionCustomdata(GHOST_XrContextHandle xr_contexthandle,
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int GHOST_XrGetActionCount(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL_RET(xr_session->getActionCount(action_set_name), xr_context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_contexthandle,
|
||||
const char *action_set_name,
|
||||
void **r_customdata_array)
|
||||
{
|
||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||
GHOST_XR_CAPI_CALL(xr_session->getActionCustomdataArray(action_set_name, r_customdata_array),
|
||||
xr_context);
|
||||
}
|
||||
|
||||
#endif /* WITH_XR_OPENXR */
|
||||
|
@@ -132,6 +132,7 @@ class GHOST_SharedOpenGLResource {
|
||||
ID3D11DeviceContext *device_ctx,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
DXGI_FORMAT format,
|
||||
ID3D11RenderTargetView *render_target = nullptr)
|
||||
: m_device(device), m_device_ctx(device_ctx), m_cur_width(width), m_cur_height(height)
|
||||
{
|
||||
@@ -144,7 +145,7 @@ class GHOST_SharedOpenGLResource {
|
||||
|
||||
texDesc.Width = width;
|
||||
texDesc.Height = height;
|
||||
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
texDesc.Format = format;
|
||||
texDesc.SampleDesc.Count = 1;
|
||||
texDesc.ArraySize = 1;
|
||||
texDesc.MipLevels = 1;
|
||||
@@ -321,7 +322,10 @@ class GHOST_SharedOpenGLResource {
|
||||
};
|
||||
|
||||
GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(
|
||||
unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target)
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
DXGI_FORMAT format,
|
||||
ID3D11RenderTargetView *render_target)
|
||||
{
|
||||
if (!(WGL_NV_DX_interop && WGL_NV_DX_interop2)) {
|
||||
fprintf(stderr,
|
||||
@@ -330,14 +334,15 @@ GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(
|
||||
return nullptr;
|
||||
}
|
||||
GHOST_SharedOpenGLResource *shared_res = new GHOST_SharedOpenGLResource(
|
||||
m_device, m_device_ctx, width, height, render_target);
|
||||
m_device, m_device_ctx, width, height, format, render_target);
|
||||
|
||||
return shared_res;
|
||||
}
|
||||
GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(unsigned int width,
|
||||
unsigned int height)
|
||||
unsigned int height,
|
||||
DXGI_FORMAT format)
|
||||
{
|
||||
return createSharedOpenGLResource(width, height, nullptr);
|
||||
return createSharedOpenGLResource(width, height, format, nullptr);
|
||||
}
|
||||
|
||||
void GHOST_ContextD3D::disposeSharedOpenGLResource(GHOST_SharedOpenGLResource *shared_res)
|
||||
|
@@ -106,9 +106,13 @@ class GHOST_ContextD3D : public GHOST_Context {
|
||||
}
|
||||
|
||||
class GHOST_SharedOpenGLResource *createSharedOpenGLResource(
|
||||
unsigned int width, unsigned int height, ID3D11RenderTargetView *render_target);
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
DXGI_FORMAT format,
|
||||
ID3D11RenderTargetView *render_target);
|
||||
class GHOST_SharedOpenGLResource *createSharedOpenGLResource(unsigned int width,
|
||||
unsigned int height);
|
||||
unsigned int height,
|
||||
DXGI_FORMAT format);
|
||||
void disposeSharedOpenGLResource(class GHOST_SharedOpenGLResource *shared_res);
|
||||
GHOST_TSuccess blitFromOpenGLContext(class GHOST_SharedOpenGLResource *shared_res,
|
||||
unsigned int width,
|
||||
|
@@ -295,8 +295,8 @@ GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
|
||||
|
||||
glXMakeCurrent(m_display, m_window, m_context);
|
||||
|
||||
// Seems that this has to be called after MakeCurrent,
|
||||
// which means we cannot use glX extensions until after we create a context
|
||||
/* Seems that this has to be called after #glXMakeCurrent,
|
||||
* which means we cannot use `glX` extensions until after we create a context. */
|
||||
initContextGLXEW();
|
||||
|
||||
if (m_window) {
|
||||
|
@@ -141,22 +141,26 @@ GHOST_TSuccess GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(
|
||||
printf(" setting.frequency=%d\n", setting.frequency);
|
||||
#endif // GHOST_DEBUG
|
||||
|
||||
// Display configuration is no more available in 10.6
|
||||
/* Display configuration is no more available in 10.6. */
|
||||
|
||||
/* CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate(
|
||||
m_displayIDs[display],
|
||||
(size_t)setting.bpp,
|
||||
(size_t)setting.xPixels,
|
||||
(size_t)setting.yPixels,
|
||||
(CGRefreshRate)setting.frequency,
|
||||
NULL);*/
|
||||
#if 0
|
||||
CFDictionaryRef displayModeValues = ::CGDisplayBestModeForParametersAndRefreshRate(
|
||||
m_displayIDs[display],
|
||||
(size_t)setting.bpp,
|
||||
(size_t)setting.xPixels,
|
||||
(size_t)setting.yPixels,
|
||||
(CGRefreshRate)setting.frequency,
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
#ifdef GHOST_DEBUG
|
||||
/* printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): switching to:\n");
|
||||
# if 0
|
||||
printf("GHOST_DisplayManagerCocoa::setCurrentDisplaySetting(): switching to:\n");
|
||||
printf(" setting.xPixels=%d\n", getValue(displayModeValues, kCGDisplayWidth));
|
||||
printf(" setting.yPixels=%d\n", getValue(displayModeValues, kCGDisplayHeight));
|
||||
printf(" setting.bpp=%d\n", getValue(displayModeValues, kCGDisplayBitsPerPixel));
|
||||
printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate)); */
|
||||
printf(" setting.frequency=%d\n", getValue(displayModeValues, kCGDisplayRefreshRate));
|
||||
# endif
|
||||
#endif // GHOST_DEBUG
|
||||
|
||||
// CGDisplayErr err = ::CGDisplaySwitchToMode(m_displayIDs[display], displayModeValues);
|
||||
|
@@ -60,6 +60,7 @@ class GHOST_IXrGraphicsBinding {
|
||||
std::string *r_requirement_info) const = 0;
|
||||
virtual void initFromGhostContext(class GHOST_Context &ghost_ctx) = 0;
|
||||
virtual std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
GHOST_TXrSwapchainFormat &r_format,
|
||||
bool &r_is_rgb_format) const = 0;
|
||||
virtual std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(
|
||||
uint32_t image_count) = 0;
|
||||
|
@@ -30,10 +30,17 @@
|
||||
# include "GHOST_WindowWin32.h"
|
||||
# include "utfconv.h"
|
||||
|
||||
/* ISO_639-1 2-Letter Abbreviations. */
|
||||
# define IMELANG_ENGLISH "en"
|
||||
# define IMELANG_CHINESE "zh"
|
||||
# define IMELANG_JAPANESE "ja"
|
||||
# define IMELANG_KOREAN "ko"
|
||||
|
||||
GHOST_ImeWin32::GHOST_ImeWin32()
|
||||
: is_composing_(false),
|
||||
ime_status_(false),
|
||||
input_language_id_(LANG_USER_DEFAULT),
|
||||
language_(IMELANG_ENGLISH),
|
||||
conversion_modes_(IME_CMODE_ALPHANUMERIC),
|
||||
sentence_mode_(IME_SMODE_NONE),
|
||||
system_caret_(false),
|
||||
caret_rect_(-1, -1, 0, 0),
|
||||
is_first(true),
|
||||
@@ -45,18 +52,65 @@ GHOST_ImeWin32::~GHOST_ImeWin32()
|
||||
{
|
||||
}
|
||||
|
||||
bool GHOST_ImeWin32::SetInputLanguage()
|
||||
void GHOST_ImeWin32::UpdateInputLanguage()
|
||||
{
|
||||
/**
|
||||
* Retrieve the current keyboard layout from Windows and determine whether
|
||||
* or not the current input context has IMEs.
|
||||
* Also save its input language for language-specific operations required
|
||||
* while composing a text.
|
||||
*/
|
||||
HKL keyboard_layout = ::GetKeyboardLayout(0);
|
||||
input_language_id_ = LOWORD(keyboard_layout);
|
||||
ime_status_ = ::ImmIsIME(keyboard_layout);
|
||||
return ime_status_;
|
||||
/* Get the current input locale full name. */
|
||||
WCHAR locale[LOCALE_NAME_MAX_LENGTH];
|
||||
LCIDToLocaleName(
|
||||
MAKELCID(LOWORD(::GetKeyboardLayout(0)), SORT_DEFAULT), locale, LOCALE_NAME_MAX_LENGTH, 0);
|
||||
/* Get the 2-letter ISO-63901 abbreviation of the input locale name. */
|
||||
WCHAR language_u16[W32_ISO639_LEN];
|
||||
GetLocaleInfoEx(locale, LOCALE_SISO639LANGNAME, language_u16, W32_ISO639_LEN);
|
||||
/* Store this as a UTF-8 string. */
|
||||
WideCharToMultiByte(
|
||||
CP_UTF8, 0, language_u16, W32_ISO639_LEN, language_, W32_ISO639_LEN, NULL, NULL);
|
||||
}
|
||||
|
||||
BOOL GHOST_ImeWin32::IsLanguage(const char name[W32_ISO639_LEN])
|
||||
{
|
||||
return (strcmp(name, language_) == 0);
|
||||
}
|
||||
|
||||
void GHOST_ImeWin32::UpdateConversionStatus(HWND window_handle)
|
||||
{
|
||||
HIMC imm_context = ::ImmGetContext(window_handle);
|
||||
if (imm_context) {
|
||||
if (::ImmGetOpenStatus(imm_context)) {
|
||||
::ImmGetConversionStatus(imm_context, &conversion_modes_, &sentence_mode_);
|
||||
}
|
||||
else {
|
||||
conversion_modes_ = IME_CMODE_ALPHANUMERIC;
|
||||
sentence_mode_ = IME_SMODE_NONE;
|
||||
}
|
||||
::ImmReleaseContext(window_handle, imm_context);
|
||||
}
|
||||
else {
|
||||
conversion_modes_ = IME_CMODE_ALPHANUMERIC;
|
||||
sentence_mode_ = IME_SMODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_ImeWin32::IsEnglishMode()
|
||||
{
|
||||
return (conversion_modes_ & IME_CMODE_NOCONVERSION) ||
|
||||
!(conversion_modes_ & (IME_CMODE_NATIVE | IME_CMODE_FULLSHAPE));
|
||||
}
|
||||
|
||||
bool GHOST_ImeWin32::IsImeKeyEvent(char ascii)
|
||||
{
|
||||
if (!(IsEnglishMode())) {
|
||||
/* In Chinese, Japanese, Korean, all alpha keys are processed by IME. */
|
||||
if ((ascii >= 'A' && ascii <= 'Z') || (ascii >= 'a' && ascii <= 'z')) {
|
||||
return true;
|
||||
}
|
||||
if (IsLanguage(IMELANG_JAPANESE) && (ascii >= ' ' && ascii <= '~')) {
|
||||
return true;
|
||||
}
|
||||
else if (IsLanguage(IMELANG_CHINESE) && ascii && strchr("!\"$'(),.:;<>?[\\]^_`", ascii)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GHOST_ImeWin32::CreateImeWindow(HWND window_handle)
|
||||
@@ -73,13 +127,8 @@ void GHOST_ImeWin32::CreateImeWindow(HWND window_handle)
|
||||
* Since some third-party Japanese IME also uses ::GetCaretPos() to determine
|
||||
* their window position, we also create a caret for Japanese IMEs.
|
||||
*/
|
||||
if (PRIMARYLANGID(input_language_id_) == LANG_CHINESE ||
|
||||
PRIMARYLANGID(input_language_id_) == LANG_JAPANESE) {
|
||||
if (!system_caret_) {
|
||||
if (::CreateCaret(window_handle, NULL, 1, 1)) {
|
||||
system_caret_ = true;
|
||||
}
|
||||
}
|
||||
if (!system_caret_ && (IsLanguage(IMELANG_CHINESE) || IsLanguage(IMELANG_JAPANESE))) {
|
||||
system_caret_ = ::CreateCaret(window_handle, NULL, 1, 1);
|
||||
}
|
||||
/* Restore the positions of the IME windows. */
|
||||
UpdateImeWindow(window_handle);
|
||||
@@ -132,16 +181,9 @@ void GHOST_ImeWin32::MoveImeWindow(HWND window_handle, HIMC imm_context)
|
||||
CANDIDATEFORM candidate_position = {0, CFS_CANDIDATEPOS, {x, y}, {0, 0, 0, 0}};
|
||||
::ImmSetCandidateWindow(imm_context, &candidate_position);
|
||||
if (system_caret_) {
|
||||
switch (PRIMARYLANGID(input_language_id_)) {
|
||||
case LANG_JAPANESE:
|
||||
::SetCaretPos(x, y + caret_rect_.getHeight());
|
||||
break;
|
||||
default:
|
||||
::SetCaretPos(x, y);
|
||||
break;
|
||||
}
|
||||
::SetCaretPos(x, y);
|
||||
}
|
||||
if (PRIMARYLANGID(input_language_id_) == LANG_KOREAN) {
|
||||
if (IsLanguage(IMELANG_KOREAN)) {
|
||||
/**
|
||||
* Chinese IMEs and Japanese IMEs require the upper-left corner of
|
||||
* the caret to move the position of their candidate windows.
|
||||
@@ -231,83 +273,79 @@ void GHOST_ImeWin32::GetCaret(HIMC imm_context, LPARAM lparam, ImeComposition *c
|
||||
*/
|
||||
int target_start = -1;
|
||||
int target_end = -1;
|
||||
switch (PRIMARYLANGID(input_language_id_)) {
|
||||
case LANG_KOREAN:
|
||||
if (lparam & CS_NOMOVECARET) {
|
||||
target_start = 0;
|
||||
target_end = 1;
|
||||
}
|
||||
break;
|
||||
case LANG_CHINESE: {
|
||||
int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0);
|
||||
if (clause_size) {
|
||||
static std::vector<unsigned long> clauses;
|
||||
clause_size = clause_size / sizeof(clauses[0]);
|
||||
clauses.resize(clause_size);
|
||||
ImmGetCompositionStringW(
|
||||
imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size);
|
||||
if (composition->cursor_position == composition->ime_string.size()) {
|
||||
target_start = clauses[clause_size - 2];
|
||||
target_end = clauses[clause_size - 1];
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < clause_size - 1; i++) {
|
||||
if (clauses[i] == composition->cursor_position) {
|
||||
target_start = clauses[i];
|
||||
target_end = clauses[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsLanguage(IMELANG_KOREAN)) {
|
||||
if (lparam & CS_NOMOVECARET) {
|
||||
target_start = 0;
|
||||
target_end = 1;
|
||||
}
|
||||
}
|
||||
else if (IsLanguage(IMELANG_CHINESE)) {
|
||||
int clause_size = ImmGetCompositionStringW(imm_context, GCS_COMPCLAUSE, NULL, 0);
|
||||
if (clause_size) {
|
||||
static std::vector<unsigned long> clauses;
|
||||
clause_size = clause_size / sizeof(clauses[0]);
|
||||
clauses.resize(clause_size);
|
||||
ImmGetCompositionStringW(
|
||||
imm_context, GCS_COMPCLAUSE, &clauses[0], sizeof(clauses[0]) * clause_size);
|
||||
if (composition->cursor_position == composition->ime_string.size()) {
|
||||
target_start = clauses[clause_size - 2];
|
||||
target_end = clauses[clause_size - 1];
|
||||
}
|
||||
else {
|
||||
if (composition->cursor_position != -1) {
|
||||
target_start = composition->cursor_position;
|
||||
target_end = composition->ime_string.size();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LANG_JAPANESE:
|
||||
|
||||
/**
|
||||
* For Japanese IMEs, the robustest way to retrieve the caret
|
||||
* is scanning the attribute of the latest composition string and
|
||||
* retrieving the beginning and the end of the target clause, i.e.
|
||||
* a clause being converted.
|
||||
*/
|
||||
if (lparam & GCS_COMPATTR) {
|
||||
int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0);
|
||||
if (attribute_size > 0) {
|
||||
char *attribute_data = new char[attribute_size];
|
||||
if (attribute_data) {
|
||||
::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size);
|
||||
for (target_start = 0; target_start < attribute_size; ++target_start) {
|
||||
if (IsTargetAttribute(attribute_data[target_start]))
|
||||
break;
|
||||
}
|
||||
for (target_end = target_start; target_end < attribute_size; ++target_end) {
|
||||
if (!IsTargetAttribute(attribute_data[target_end]))
|
||||
break;
|
||||
}
|
||||
if (target_start == attribute_size) {
|
||||
/**
|
||||
* This composition clause does not contain any target clauses,
|
||||
* i.e. this clauses is an input clause.
|
||||
* We treat whole this clause as a target clause.
|
||||
*/
|
||||
target_end = target_start;
|
||||
target_start = 0;
|
||||
}
|
||||
if (target_start != -1 && target_start < attribute_size &&
|
||||
attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) {
|
||||
composition->cursor_position = target_start;
|
||||
}
|
||||
for (int i = 0; i < clause_size - 1; i++) {
|
||||
if (clauses[i] == composition->cursor_position) {
|
||||
target_start = clauses[i];
|
||||
target_end = clauses[i + 1];
|
||||
break;
|
||||
}
|
||||
delete[] attribute_data;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (composition->cursor_position != -1) {
|
||||
target_start = composition->cursor_position;
|
||||
target_end = composition->ime_string.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsLanguage(IMELANG_JAPANESE)) {
|
||||
/**
|
||||
* For Japanese IMEs, the robustest way to retrieve the caret
|
||||
* is scanning the attribute of the latest composition string and
|
||||
* retrieving the beginning and the end of the target clause, i.e.
|
||||
* a clause being converted.
|
||||
*/
|
||||
if (lparam & GCS_COMPATTR) {
|
||||
int attribute_size = ::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, NULL, 0);
|
||||
if (attribute_size > 0) {
|
||||
char *attribute_data = new char[attribute_size];
|
||||
if (attribute_data) {
|
||||
::ImmGetCompositionStringW(imm_context, GCS_COMPATTR, attribute_data, attribute_size);
|
||||
for (target_start = 0; target_start < attribute_size; ++target_start) {
|
||||
if (IsTargetAttribute(attribute_data[target_start]))
|
||||
break;
|
||||
}
|
||||
for (target_end = target_start; target_end < attribute_size; ++target_end) {
|
||||
if (!IsTargetAttribute(attribute_data[target_end]))
|
||||
break;
|
||||
}
|
||||
if (target_start == attribute_size) {
|
||||
/**
|
||||
* This composition clause does not contain any target clauses,
|
||||
* i.e. this clauses is an input clause.
|
||||
* We treat whole this clause as a target clause.
|
||||
*/
|
||||
target_end = target_start;
|
||||
target_start = 0;
|
||||
}
|
||||
if (target_start != -1 && target_start < attribute_size &&
|
||||
attribute_data[target_start] == ATTR_TARGET_NOTCONVERTED) {
|
||||
composition->cursor_position = target_start;
|
||||
}
|
||||
}
|
||||
delete[] attribute_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
composition->target_start = target_start;
|
||||
composition->target_end = target_end;
|
||||
|
@@ -36,6 +36,9 @@
|
||||
# include "GHOST_Rect.h"
|
||||
# include <vector>
|
||||
|
||||
/* MSDN LOCALE_SISO639LANGNAME states maximum length of 9, including terminating null. */
|
||||
# define W32_ISO639_LEN 9
|
||||
|
||||
class GHOST_EventIME : public GHOST_Event {
|
||||
public:
|
||||
/**
|
||||
@@ -88,7 +91,7 @@ class GHOST_EventIME : public GHOST_Event {
|
||||
* An application CAN call ::DefWindowProc().
|
||||
* 2.5. WM_INPUTLANGCHANGE (0x0051)
|
||||
* Call the functions listed below:
|
||||
* - GHOST_ImeWin32::SetInputLanguage().
|
||||
* - GHOST_ImeWin32::UpdateInputLanguage().
|
||||
* An application CAN call ::DefWindowProc().
|
||||
*/
|
||||
|
||||
@@ -146,15 +149,19 @@ class GHOST_ImeWin32 {
|
||||
return is_composing_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the input language from Windows and update it.
|
||||
* Return values
|
||||
* * true
|
||||
* The given input language has IMEs.
|
||||
* * false
|
||||
* The given input language does not have IMEs.
|
||||
*/
|
||||
bool SetInputLanguage();
|
||||
/* Retrieve the input language from Windows and store it. */
|
||||
void UpdateInputLanguage();
|
||||
|
||||
BOOL IsLanguage(const char name[W32_ISO639_LEN]);
|
||||
|
||||
/* Saves the current conversion status. */
|
||||
void UpdateConversionStatus(HWND window_handle);
|
||||
|
||||
/* Is the IME currently in conversion mode? */
|
||||
bool IsEnglishMode();
|
||||
|
||||
/* Checks a key whether IME has to do handling. */
|
||||
bool IsImeKeyEvent(char ascii);
|
||||
|
||||
/**
|
||||
* Create the IME windows, and allocate required resources for them.
|
||||
@@ -338,38 +345,14 @@ class GHOST_ImeWin32 {
|
||||
*/
|
||||
bool is_composing_;
|
||||
|
||||
/**
|
||||
* This value represents whether or not the current input context has IMEs.
|
||||
* The following table shows the list of IME status:
|
||||
* Value Description
|
||||
* false The current input language does not have IMEs.
|
||||
* true The current input language has IMEs.
|
||||
*/
|
||||
bool ime_status_;
|
||||
/* Abbreviated ISO 639-1 name of the input language, such as "en" for English. */
|
||||
char language_[W32_ISO639_LEN];
|
||||
|
||||
/**
|
||||
* The current input Language ID retrieved from Windows, which consists of:
|
||||
* * Primary Language ID (bit 0 to bit 9), which shows a natural language
|
||||
* (English, Korean, Chinese, Japanese, etc.) and;
|
||||
* * Sub-Language ID (bit 10 to bit 15), which shows a geometrical region
|
||||
* the language is spoken (For English, United States, United Kingdom,
|
||||
* Australia, Canada, etc.)
|
||||
* The following list enumerates some examples for the Language ID:
|
||||
* * "en-US" (0x0409)
|
||||
* MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||||
* * "ko-KR" (0x0412)
|
||||
* MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
|
||||
* * "zh-TW" (0x0404)
|
||||
* MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
|
||||
* * "zh-CN" (0x0804)
|
||||
* MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
|
||||
* * "ja-JP" (0x0411)
|
||||
* MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN), etc.
|
||||
* (See `winnt.h` for other available values.)
|
||||
* This Language ID is used for processing language-specific operations in
|
||||
* IME functions.
|
||||
*/
|
||||
LANGID input_language_id_;
|
||||
/* Current Conversion Mode Values. Retrieved with ImmGetConversionStatus. */
|
||||
DWORD conversion_modes_;
|
||||
|
||||
/* Current Sentence Mode. Retrieved with ImmGetConversionStatus. */
|
||||
DWORD sentence_mode_;
|
||||
|
||||
/**
|
||||
* Represents whether or not the current input context has created a system
|
||||
|
@@ -1629,7 +1629,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
|
||||
y_accum + (y_mouse - warped_y_mouse));
|
||||
|
||||
/* This is the current time that matches NSEvent timestamp. */
|
||||
m_last_warp_timestamp = mach_absolute_time() * 1e-9;
|
||||
m_last_warp_timestamp = [[NSProcessInfo processInfo] systemUptime];
|
||||
}
|
||||
|
||||
// Generate event
|
||||
|
@@ -473,7 +473,7 @@ void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
|
||||
GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
|
||||
/* NOTE: the `sdl_sub_evt.keysym.sym` is truncated,
|
||||
* for unicode support ghost has to be modified. */
|
||||
/* printf("%d\n", sym); */
|
||||
// printf("%d\n", sym);
|
||||
if (sym > 127) {
|
||||
switch (sym) {
|
||||
case SDLK_KP_DIVIDE:
|
||||
|
@@ -1219,6 +1219,12 @@ GHOST_EventKey *GHOST_SystemWin32::processKeyEvent(GHOST_WindowWin32 *window, RA
|
||||
ascii = utf8_char[0] & 0x80 ? '?' : utf8_char[0];
|
||||
}
|
||||
|
||||
#ifdef WITH_INPUT_IME
|
||||
if (window->getImeInput()->IsImeKeyEvent(ascii)) {
|
||||
return NULL;
|
||||
}
|
||||
#endif /* WITH_INPUT_IME */
|
||||
|
||||
event = new GHOST_EventKey(system->getMilliSeconds(),
|
||||
keyDown ? GHOST_kEventKeyDown : GHOST_kEventKeyUp,
|
||||
window,
|
||||
@@ -1418,7 +1424,8 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
case WM_INPUTLANGCHANGE: {
|
||||
system->handleKeyboardChange();
|
||||
#ifdef WITH_INPUT_IME
|
||||
window->getImeInput()->SetInputLanguage();
|
||||
window->getImeInput()->UpdateInputLanguage();
|
||||
window->getImeInput()->UpdateConversionStatus(hwnd);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
@@ -1455,9 +1462,16 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// IME events, processed, read more in GHOST_IME.h
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
case WM_IME_NOTIFY: {
|
||||
/* Update conversion status when IME is changed or input mode is changed. */
|
||||
if (wParam == IMN_SETOPENSTATUS || wParam == IMN_SETCONVERSIONMODE) {
|
||||
window->getImeInput()->UpdateConversionStatus(hwnd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_IME_SETCONTEXT: {
|
||||
GHOST_ImeWin32 *ime = window->getImeInput();
|
||||
ime->SetInputLanguage();
|
||||
ime->UpdateInputLanguage();
|
||||
ime->CreateImeWindow(hwnd);
|
||||
ime->CleanupComposition(hwnd);
|
||||
ime->CheckFirst(hwnd);
|
||||
@@ -1466,8 +1480,6 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam,
|
||||
case WM_IME_STARTCOMPOSITION: {
|
||||
GHOST_ImeWin32 *ime = window->getImeInput();
|
||||
eventHandled = true;
|
||||
/* remove input event before start comp event, avoid redundant input */
|
||||
eventManager->removeTypeEvents(GHOST_kEventKeyDown, window);
|
||||
ime->CreateImeWindow(hwnd);
|
||||
ime->ResetComposition(hwnd);
|
||||
event = processImeEvent(GHOST_kEventImeCompositionStart, window, &ime->eventImeData);
|
||||
|
@@ -802,8 +802,7 @@ static bool checkTabletProximity(Display *display, XDevice *device)
|
||||
|
||||
if (state) {
|
||||
XInputClass *cls = state->data;
|
||||
// printf("%d class%s :\n", state->num_classes,
|
||||
// (state->num_classes > 1) ? "es" : "");
|
||||
// printf("%d class%s :\n", state->num_classes, (state->num_classes > 1) ? "es" : "");
|
||||
for (int loop = 0; loop < state->num_classes; loop++) {
|
||||
switch (cls->c_class) {
|
||||
case ValuatorClass:
|
||||
|
@@ -403,7 +403,7 @@ GHOST_WindowX11::GHOST_WindowX11(GHOST_SystemX11 *system,
|
||||
}
|
||||
|
||||
if (natom) {
|
||||
/* printf("Register atoms: %d\n", natom); */
|
||||
// printf("Register atoms: %d\n", natom);
|
||||
XSetWMProtocols(m_display, m_window, atoms, natom);
|
||||
}
|
||||
}
|
||||
@@ -1275,15 +1275,15 @@ GHOST_Context *GHOST_WindowX11::newDrawingContext(GHOST_TDrawingContextType type
|
||||
{
|
||||
if (type == GHOST_kDrawingContextTypeOpenGL) {
|
||||
|
||||
// During development:
|
||||
// try 4.x compatibility profile
|
||||
// try 3.3 compatibility profile
|
||||
// fall back to 3.0 if needed
|
||||
//
|
||||
// Final Blender 2.8:
|
||||
// try 4.x core profile
|
||||
// try 3.3 core profile
|
||||
// no fallbacks
|
||||
/* During development:
|
||||
* - Try 4.x compatibility profile.
|
||||
* - Try 3.3 compatibility profile.
|
||||
* - Fall back to 3.0 if needed.
|
||||
*
|
||||
* Final Blender 2.8:
|
||||
* - Try 4.x core profile
|
||||
* - Try 3.3 core profile
|
||||
* - No fall-backs. */
|
||||
|
||||
#if defined(WITH_GL_PROFILE_CORE)
|
||||
{
|
||||
|
@@ -33,24 +33,22 @@
|
||||
*
|
||||
* \{ */
|
||||
|
||||
GHOST_XrActionSpace::GHOST_XrActionSpace(XrInstance instance,
|
||||
XrSession session,
|
||||
GHOST_XrActionSpace::GHOST_XrActionSpace(XrSession session,
|
||||
XrAction action,
|
||||
const GHOST_XrActionSpaceInfo &info,
|
||||
uint32_t subaction_idx)
|
||||
const char *action_name,
|
||||
const char *profile_path,
|
||||
XrPath subaction_path,
|
||||
const char *subaction_path_str,
|
||||
const GHOST_XrPose &pose)
|
||||
{
|
||||
const char *subaction_path = info.subaction_paths[subaction_idx];
|
||||
CHECK_XR(xrStringToPath(instance, subaction_path, &m_subaction_path),
|
||||
(std::string("Failed to get user path \"") + subaction_path + "\".").data());
|
||||
|
||||
XrActionSpaceCreateInfo action_space_info{XR_TYPE_ACTION_SPACE_CREATE_INFO};
|
||||
action_space_info.action = action;
|
||||
action_space_info.subactionPath = m_subaction_path;
|
||||
copy_ghost_pose_to_openxr_pose(info.poses[subaction_idx], action_space_info.poseInActionSpace);
|
||||
action_space_info.subactionPath = subaction_path;
|
||||
copy_ghost_pose_to_openxr_pose(pose, action_space_info.poseInActionSpace);
|
||||
|
||||
CHECK_XR(xrCreateActionSpace(session, &action_space_info, &m_space),
|
||||
(std::string("Failed to create space \"") + subaction_path + "\" for action \"" +
|
||||
info.action_name + "\".")
|
||||
(std::string("Failed to create space \"") + subaction_path_str + "\" for action \"" +
|
||||
action_name + "\" and profile \"" + profile_path + "\".")
|
||||
.data());
|
||||
}
|
||||
|
||||
@@ -66,11 +64,6 @@ XrSpace GHOST_XrActionSpace::getSpace() const
|
||||
return m_space;
|
||||
}
|
||||
|
||||
const XrPath &GHOST_XrActionSpace::getSubactionPath() const
|
||||
{
|
||||
return m_subaction_path;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@@ -79,13 +72,19 @@ const XrPath &GHOST_XrActionSpace::getSubactionPath() const
|
||||
* \{ */
|
||||
|
||||
GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
|
||||
XrSession session,
|
||||
XrAction action,
|
||||
const char *profile_path,
|
||||
const GHOST_XrActionBindingInfo &info)
|
||||
GHOST_XrActionType type,
|
||||
const GHOST_XrActionProfileInfo &info)
|
||||
{
|
||||
CHECK_XR(
|
||||
xrStringToPath(instance, profile_path, &m_profile),
|
||||
(std::string("Failed to get interaction profile path \"") + profile_path + "\".").data());
|
||||
CHECK_XR(xrStringToPath(instance, info.profile_path, &m_profile),
|
||||
(std::string("Failed to get interaction profile path \"") + info.profile_path + "\".")
|
||||
.data());
|
||||
|
||||
const bool is_float_action = (type == GHOST_kXrActionTypeFloatInput ||
|
||||
type == GHOST_kXrActionTypeVector2fInput);
|
||||
const bool is_button_action = (is_float_action || type == GHOST_kXrActionTypeBooleanInput);
|
||||
const bool is_pose_action = (type == GHOST_kXrActionTypePoseInput);
|
||||
|
||||
/* Create bindings. */
|
||||
XrInteractionProfileSuggestedBinding bindings_info{
|
||||
@@ -93,31 +92,80 @@ GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
|
||||
bindings_info.interactionProfile = m_profile;
|
||||
bindings_info.countSuggestedBindings = 1;
|
||||
|
||||
for (uint32_t interaction_idx = 0; interaction_idx < info.count_interaction_paths;
|
||||
++interaction_idx) {
|
||||
const char *interaction_path = info.interaction_paths[interaction_idx];
|
||||
for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
||||
const char *subaction_path_str = info.subaction_paths[subaction_idx];
|
||||
const GHOST_XrActionBindingInfo &binding_info = info.bindings[subaction_idx];
|
||||
|
||||
const std::string interaction_path = std::string(subaction_path_str) +
|
||||
binding_info.component_path;
|
||||
if (m_bindings.find(interaction_path) != m_bindings.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XrActionSuggestedBinding sbinding;
|
||||
sbinding.action = action;
|
||||
CHECK_XR(xrStringToPath(instance, interaction_path, &sbinding.binding),
|
||||
CHECK_XR(xrStringToPath(instance, interaction_path.data(), &sbinding.binding),
|
||||
(std::string("Failed to get interaction path \"") + interaction_path + "\".").data());
|
||||
bindings_info.suggestedBindings = &sbinding;
|
||||
|
||||
/* Although the bindings will be re-suggested in GHOST_XrSession::attachActionSets(), it
|
||||
* greatly improves error checking to suggest them here first. */
|
||||
CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info),
|
||||
(std::string("Failed to create binding for profile \"") + profile_path +
|
||||
"\" and action \"" + info.action_name +
|
||||
"\". Are the profile and action paths correct?")
|
||||
(std::string("Failed to create binding for action \"") + info.action_name +
|
||||
"\" and profile \"" + info.profile_path +
|
||||
"\". Are the action and profile paths correct?")
|
||||
.data());
|
||||
|
||||
m_bindings.insert({interaction_path, sbinding.binding});
|
||||
|
||||
if (m_subaction_data.find(subaction_path_str) == m_subaction_data.end()) {
|
||||
std::map<std::string, GHOST_XrSubactionData>::iterator it =
|
||||
m_subaction_data
|
||||
.emplace(
|
||||
std::piecewise_construct, std::make_tuple(subaction_path_str), std::make_tuple())
|
||||
.first;
|
||||
GHOST_XrSubactionData &subaction = it->second;
|
||||
|
||||
CHECK_XR(xrStringToPath(instance, subaction_path_str, &subaction.subaction_path),
|
||||
(std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
|
||||
|
||||
if (is_float_action || is_button_action) {
|
||||
if (is_float_action) {
|
||||
subaction.float_threshold = binding_info.float_threshold;
|
||||
}
|
||||
if (is_button_action) {
|
||||
subaction.axis_flag = binding_info.axis_flag;
|
||||
}
|
||||
}
|
||||
else if (is_pose_action) {
|
||||
/* Create action space for pose bindings. */
|
||||
subaction.space = std::make_unique<GHOST_XrActionSpace>(session,
|
||||
action,
|
||||
info.action_name,
|
||||
info.profile_path,
|
||||
subaction.subaction_path,
|
||||
subaction_path_str,
|
||||
binding_info.pose);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XrPath GHOST_XrActionProfile::getProfile() const
|
||||
{
|
||||
return m_profile;
|
||||
}
|
||||
|
||||
const GHOST_XrSubactionData *GHOST_XrActionProfile::getSubaction(XrPath subaction_path) const
|
||||
{
|
||||
for (auto &[subaction_path_str, subaction] : m_subaction_data) {
|
||||
if (subaction.subaction_path == subaction_path) {
|
||||
return &subaction;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GHOST_XrActionProfile::getBindings(
|
||||
XrAction action, std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const
|
||||
{
|
||||
@@ -152,14 +200,18 @@ GHOST_XrAction::GHOST_XrAction(XrInstance instance,
|
||||
const GHOST_XrActionInfo &info)
|
||||
: m_type(info.type),
|
||||
m_states(info.states),
|
||||
m_float_thresholds(info.float_thresholds),
|
||||
m_axis_flags(info.axis_flags),
|
||||
m_custom_data_(
|
||||
std::make_unique<GHOST_C_CustomDataWrapper>(info.customdata, info.customdata_free_fn))
|
||||
{
|
||||
m_subaction_paths.resize(info.count_subaction_paths);
|
||||
|
||||
for (uint32_t i = 0; i < info.count_subaction_paths; ++i) {
|
||||
CHECK_XR(xrStringToPath(instance, info.subaction_paths[i], &m_subaction_paths[i]),
|
||||
(std::string("Failed to get user path \"") + info.subaction_paths[i] + "\".").data());
|
||||
const char *subaction_path_str = info.subaction_paths[i];
|
||||
CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_paths[i]),
|
||||
(std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
|
||||
m_subaction_indices.insert({subaction_path_str, i});
|
||||
}
|
||||
|
||||
XrActionCreateInfo action_info{XR_TYPE_ACTION_CREATE_INFO};
|
||||
@@ -201,52 +253,25 @@ GHOST_XrAction::~GHOST_XrAction()
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_XrAction::createSpace(XrInstance instance,
|
||||
XrSession session,
|
||||
const GHOST_XrActionSpaceInfo &info)
|
||||
{
|
||||
uint32_t subaction_idx = 0;
|
||||
for (; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
||||
if (m_spaces.find(info.subaction_paths[subaction_idx]) != m_spaces.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
||||
m_spaces.emplace(std::piecewise_construct,
|
||||
std::make_tuple(info.subaction_paths[subaction_idx]),
|
||||
std::make_tuple(instance, session, m_action, info, subaction_idx));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GHOST_XrAction::destroySpace(const char *subaction_path)
|
||||
{
|
||||
if (m_spaces.find(subaction_path) != m_spaces.end()) {
|
||||
m_spaces.erase(subaction_path);
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_XrAction::createBinding(XrInstance instance,
|
||||
const char *profile_path,
|
||||
const GHOST_XrActionBindingInfo &info)
|
||||
XrSession session,
|
||||
const GHOST_XrActionProfileInfo &info)
|
||||
{
|
||||
if (m_profiles.find(profile_path) != m_profiles.end()) {
|
||||
if (m_profiles.find(info.profile_path) != m_profiles.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_profiles.emplace(std::piecewise_construct,
|
||||
std::make_tuple(profile_path),
|
||||
std::make_tuple(instance, m_action, profile_path, info));
|
||||
std::make_tuple(info.profile_path),
|
||||
std::make_tuple(instance, session, m_action, m_type, info));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GHOST_XrAction::destroyBinding(const char *interaction_profile_path)
|
||||
void GHOST_XrAction::destroyBinding(const char *profile_path)
|
||||
{
|
||||
if (m_profiles.find(interaction_profile_path) != m_profiles.end()) {
|
||||
m_profiles.erase(interaction_profile_path);
|
||||
if (m_profiles.find(profile_path) != m_profiles.end()) {
|
||||
m_profiles.erase(profile_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +280,10 @@ void GHOST_XrAction::updateState(XrSession session,
|
||||
XrSpace reference_space,
|
||||
const XrTime &predicted_display_time)
|
||||
{
|
||||
const bool is_float_action = (m_type == GHOST_kXrActionTypeFloatInput ||
|
||||
m_type == GHOST_kXrActionTypeVector2fInput);
|
||||
const bool is_button_action = (is_float_action || m_type == GHOST_kXrActionTypeBooleanInput);
|
||||
|
||||
XrActionStateGetInfo state_info{XR_TYPE_ACTION_STATE_GET_INFO};
|
||||
state_info.action = m_action;
|
||||
|
||||
@@ -262,6 +291,28 @@ void GHOST_XrAction::updateState(XrSession session,
|
||||
for (size_t subaction_idx = 0; subaction_idx < count_subaction_paths; ++subaction_idx) {
|
||||
state_info.subactionPath = m_subaction_paths[subaction_idx];
|
||||
|
||||
/* Set subaction data based on current interaction profile. */
|
||||
XrInteractionProfileState profile_state{XR_TYPE_INTERACTION_PROFILE_STATE};
|
||||
CHECK_XR(xrGetCurrentInteractionProfile(session, state_info.subactionPath, &profile_state),
|
||||
"Failed to get current interaction profile.");
|
||||
|
||||
const GHOST_XrSubactionData *subaction = nullptr;
|
||||
for (auto &[profile_path, profile] : m_profiles) {
|
||||
if (profile.getProfile() == profile_state.interactionProfile) {
|
||||
subaction = profile.getSubaction(state_info.subactionPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (subaction != nullptr) {
|
||||
if (is_float_action) {
|
||||
m_float_thresholds[subaction_idx] = subaction->float_threshold;
|
||||
}
|
||||
if (is_button_action) {
|
||||
m_axis_flags[subaction_idx] = subaction->axis_flag;
|
||||
}
|
||||
}
|
||||
|
||||
switch (m_type) {
|
||||
case GHOST_kXrActionTypeBooleanInput: {
|
||||
XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN};
|
||||
@@ -299,14 +350,9 @@ void GHOST_XrAction::updateState(XrSession session,
|
||||
xrGetActionStatePose(session, &state_info, &state),
|
||||
(std::string("Failed to get state for pose action \"") + action_name + "\".").data());
|
||||
if (state.isActive) {
|
||||
XrSpace pose_space = XR_NULL_HANDLE;
|
||||
for (auto &[path, space] : m_spaces) {
|
||||
if (space.getSubactionPath() == state_info.subactionPath) {
|
||||
pose_space = space.getSpace();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
|
||||
subaction->space->getSpace() :
|
||||
XR_NULL_HANDLE;
|
||||
if (pose_space != XR_NULL_HANDLE) {
|
||||
XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
|
||||
CHECK_XR(
|
||||
@@ -329,6 +375,7 @@ void GHOST_XrAction::updateState(XrSession session,
|
||||
|
||||
void GHOST_XrAction::applyHapticFeedback(XrSession session,
|
||||
const char *action_name,
|
||||
const char *subaction_path_str,
|
||||
const int64_t &duration,
|
||||
const float &frequency,
|
||||
const float &litude)
|
||||
@@ -342,24 +389,46 @@ void GHOST_XrAction::applyHapticFeedback(XrSession session,
|
||||
XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
|
||||
haptic_info.action = m_action;
|
||||
|
||||
for (std::vector<XrPath>::iterator it = m_subaction_paths.begin(); it != m_subaction_paths.end();
|
||||
++it) {
|
||||
haptic_info.subactionPath = *it;
|
||||
CHECK_XR(xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
|
||||
(std::string("Failed to apply haptic action \"") + action_name + "\".").data());
|
||||
if (subaction_path_str != nullptr) {
|
||||
SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
|
||||
if (it != m_subaction_indices.end()) {
|
||||
haptic_info.subactionPath = m_subaction_paths[it->second];
|
||||
CHECK_XR(
|
||||
xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
|
||||
(std::string("Failed to apply haptic action \"") + action_name + "\".").data());
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const XrPath &subaction_path : m_subaction_paths) {
|
||||
haptic_info.subactionPath = subaction_path;
|
||||
CHECK_XR(
|
||||
xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
|
||||
(std::string("Failed to apply haptic action \"") + action_name + "\".").data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrAction::stopHapticFeedback(XrSession session, const char *action_name)
|
||||
void GHOST_XrAction::stopHapticFeedback(XrSession session,
|
||||
const char *action_name,
|
||||
const char *subaction_path_str)
|
||||
{
|
||||
XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
|
||||
haptic_info.action = m_action;
|
||||
|
||||
for (std::vector<XrPath>::iterator it = m_subaction_paths.begin(); it != m_subaction_paths.end();
|
||||
++it) {
|
||||
haptic_info.subactionPath = *it;
|
||||
CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
|
||||
(std::string("Failed to stop haptic action \"") + action_name + "\".").data());
|
||||
if (subaction_path_str != nullptr) {
|
||||
SubactionIndexMap::iterator it = m_subaction_indices.find(subaction_path_str);
|
||||
if (it != m_subaction_indices.end()) {
|
||||
haptic_info.subactionPath = m_subaction_paths[it->second];
|
||||
CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
|
||||
(std::string("Failed to stop haptic action \"") + action_name + "\".").data());
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const XrPath &subaction_path : m_subaction_paths) {
|
||||
haptic_info.subactionPath = subaction_path;
|
||||
CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
|
||||
(std::string("Failed to stop haptic action \"") + action_name + "\".").data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +536,19 @@ void *GHOST_XrActionSet::getCustomdata()
|
||||
return m_custom_data_->custom_data_;
|
||||
}
|
||||
|
||||
uint32_t GHOST_XrActionSet::getActionCount() const
|
||||
{
|
||||
return (uint32_t)m_actions.size();
|
||||
}
|
||||
|
||||
void GHOST_XrActionSet::getActionCustomdataArray(void **r_customdata_array)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for (auto &[name, action] : m_actions) {
|
||||
r_customdata_array[i++] = action.getCustomdata();
|
||||
}
|
||||
}
|
||||
|
||||
void GHOST_XrActionSet::getBindings(
|
||||
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const
|
||||
{
|
||||
|
@@ -18,8 +18,8 @@
|
||||
* \ingroup GHOST
|
||||
*/
|
||||
|
||||
/* Note: Requires OpenXR headers to be included before this one for OpenXR types (XrSpace, XrPath,
|
||||
* etc.). */
|
||||
/* NOTE: Requires OpenXR headers to be included before this one for OpenXR types
|
||||
* (XrSpace, XrPath, etc.). */
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -34,38 +34,53 @@
|
||||
class GHOST_XrActionSpace {
|
||||
public:
|
||||
GHOST_XrActionSpace() = delete; /* Default constructor for map storage. */
|
||||
GHOST_XrActionSpace(XrInstance instance,
|
||||
XrSession session,
|
||||
GHOST_XrActionSpace(XrSession session,
|
||||
XrAction action,
|
||||
const GHOST_XrActionSpaceInfo &info,
|
||||
uint32_t subaction_idx);
|
||||
const char *action_name,
|
||||
const char *profile_path,
|
||||
XrPath subaction_path,
|
||||
const char *subaction_path_str,
|
||||
const GHOST_XrPose &pose);
|
||||
~GHOST_XrActionSpace();
|
||||
|
||||
XrSpace getSpace() const;
|
||||
const XrPath &getSubactionPath() const;
|
||||
|
||||
private:
|
||||
XrSpace m_space = XR_NULL_HANDLE;
|
||||
XrPath m_subaction_path = XR_NULL_PATH;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
typedef struct GHOST_XrSubactionData {
|
||||
XrPath subaction_path = XR_NULL_PATH;
|
||||
float float_threshold;
|
||||
int16_t axis_flag;
|
||||
std::unique_ptr<GHOST_XrActionSpace> space = nullptr;
|
||||
} GHOST_XrSubactionData;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
class GHOST_XrActionProfile {
|
||||
public:
|
||||
GHOST_XrActionProfile() = delete; /* Default constructor for map storage. */
|
||||
GHOST_XrActionProfile(XrInstance instance,
|
||||
XrSession session,
|
||||
XrAction action,
|
||||
const char *profile_path,
|
||||
const GHOST_XrActionBindingInfo &info);
|
||||
GHOST_XrActionType type,
|
||||
const GHOST_XrActionProfileInfo &info);
|
||||
~GHOST_XrActionProfile() = default;
|
||||
|
||||
XrPath getProfile() const;
|
||||
const GHOST_XrSubactionData *getSubaction(XrPath subaction_path) const;
|
||||
void getBindings(XrAction action,
|
||||
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
||||
|
||||
private:
|
||||
XrPath m_profile = XR_NULL_PATH;
|
||||
/* Bindings identified by interaction (user (subaction) + component) path. */
|
||||
|
||||
/** Sub-action data identified by user `subaction` path. */
|
||||
std::map<std::string, GHOST_XrSubactionData> m_subaction_data;
|
||||
/** Bindings identified by interaction (user `subaction` + component) path. */
|
||||
std::map<std::string, XrPath> m_bindings;
|
||||
};
|
||||
|
||||
@@ -77,12 +92,9 @@ class GHOST_XrAction {
|
||||
GHOST_XrAction(XrInstance instance, XrActionSet action_set, const GHOST_XrActionInfo &info);
|
||||
~GHOST_XrAction();
|
||||
|
||||
bool createSpace(XrInstance instance, XrSession session, const GHOST_XrActionSpaceInfo &info);
|
||||
void destroySpace(const char *subaction_path);
|
||||
|
||||
bool createBinding(XrInstance instance,
|
||||
const char *profile_path,
|
||||
const GHOST_XrActionBindingInfo &info);
|
||||
XrSession session,
|
||||
const GHOST_XrActionProfileInfo &info);
|
||||
void destroyBinding(const char *profile_path);
|
||||
|
||||
void updateState(XrSession session,
|
||||
@@ -91,26 +103,31 @@ class GHOST_XrAction {
|
||||
const XrTime &predicted_display_time);
|
||||
void applyHapticFeedback(XrSession session,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const int64_t &duration,
|
||||
const float &frequency,
|
||||
const float &litude);
|
||||
void stopHapticFeedback(XrSession session, const char *action_name);
|
||||
void stopHapticFeedback(XrSession session, const char *action_name, const char *subaction_path);
|
||||
|
||||
void *getCustomdata();
|
||||
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
||||
|
||||
private:
|
||||
using SubactionIndexMap = std::map<std::string, uint32_t>;
|
||||
|
||||
XrAction m_action = XR_NULL_HANDLE;
|
||||
GHOST_XrActionType m_type;
|
||||
SubactionIndexMap m_subaction_indices;
|
||||
std::vector<XrPath> m_subaction_paths;
|
||||
/** States for each subaction path. */
|
||||
void *m_states;
|
||||
/** Input thresholds/regions for each subaction path. */
|
||||
float *m_float_thresholds;
|
||||
int16_t *m_axis_flags;
|
||||
|
||||
std::unique_ptr<GHOST_C_CustomDataWrapper> m_custom_data_ = nullptr; /* wmXrAction */
|
||||
|
||||
/* Spaces identified by user (subaction) path. */
|
||||
std::map<std::string, GHOST_XrActionSpace> m_spaces;
|
||||
/* Profiles identified by interaction profile path. */
|
||||
/** Profiles identified by interaction profile path. */
|
||||
std::map<std::string, GHOST_XrActionProfile> m_profiles;
|
||||
};
|
||||
|
||||
@@ -132,6 +149,8 @@ class GHOST_XrActionSet {
|
||||
|
||||
XrActionSet getActionSet() const;
|
||||
void *getCustomdata();
|
||||
uint32_t getActionCount() const;
|
||||
void getActionCustomdataArray(void **r_customdata_array);
|
||||
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
||||
|
||||
private:
|
||||
|
@@ -38,6 +38,7 @@
|
||||
# include "GHOST_SystemWin32.h"
|
||||
#endif
|
||||
#include "GHOST_C-api.h"
|
||||
#include "GHOST_XrException.h"
|
||||
#include "GHOST_Xr_intern.h"
|
||||
|
||||
#include "GHOST_IXrGraphicsBinding.h"
|
||||
@@ -160,16 +161,41 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
|
||||
}
|
||||
|
||||
std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
GHOST_TXrSwapchainFormat &r_format,
|
||||
bool &r_is_srgb_format) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {
|
||||
GL_RGB10_A2,
|
||||
GL_RGBA16,
|
||||
GL_RGBA16F,
|
||||
GL_RGBA8,
|
||||
GL_SRGB8_ALPHA8,
|
||||
};
|
||||
|
||||
std::optional result = choose_swapchain_format_from_candidates(gpu_binding_formats,
|
||||
runtime_formats);
|
||||
r_is_srgb_format = result ? (*result == GL_SRGB8_ALPHA8) : false;
|
||||
if (result) {
|
||||
switch (*result) {
|
||||
case GL_RGB10_A2:
|
||||
r_format = GHOST_kXrSwapchainFormatRGB10_A2;
|
||||
break;
|
||||
case GL_RGBA16:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA16;
|
||||
break;
|
||||
case GL_RGBA16F:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA16F;
|
||||
break;
|
||||
case GL_RGBA8:
|
||||
case GL_SRGB8_ALPHA8:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA8;
|
||||
break;
|
||||
}
|
||||
r_is_srgb_format = (*result == GL_SRGB8_ALPHA8);
|
||||
}
|
||||
else {
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA8;
|
||||
r_is_srgb_format = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -228,6 +254,33 @@ class GHOST_XrGraphicsBindingOpenGL : public GHOST_IXrGraphicsBinding {
|
||||
};
|
||||
|
||||
#ifdef WIN32
|
||||
static void ghost_format_to_dx_format(GHOST_TXrSwapchainFormat ghost_format,
|
||||
bool expects_srgb_buffer,
|
||||
DXGI_FORMAT &r_dx_format)
|
||||
{
|
||||
r_dx_format = DXGI_FORMAT_UNKNOWN;
|
||||
|
||||
switch (ghost_format) {
|
||||
case GHOST_kXrSwapchainFormatRGBA8:
|
||||
r_dx_format = expects_srgb_buffer ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB :
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
case GHOST_kXrSwapchainFormatRGBA16:
|
||||
r_dx_format = DXGI_FORMAT_R16G16B16A16_UNORM;
|
||||
break;
|
||||
case GHOST_kXrSwapchainFormatRGBA16F:
|
||||
r_dx_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
break;
|
||||
case GHOST_kXrSwapchainFormatRGB10_A2:
|
||||
r_dx_format = DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
break;
|
||||
}
|
||||
|
||||
if (r_dx_format == DXGI_FORMAT_UNKNOWN) {
|
||||
throw GHOST_XrException("No supported DirectX swapchain format found.");
|
||||
}
|
||||
}
|
||||
|
||||
class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
|
||||
public:
|
||||
GHOST_XrGraphicsBindingD3D(GHOST_Context &ghost_ctx)
|
||||
@@ -284,16 +337,48 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
|
||||
}
|
||||
|
||||
std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
|
||||
GHOST_TXrSwapchainFormat &r_format,
|
||||
bool &r_is_srgb_format) const override
|
||||
{
|
||||
std::vector<int64_t> gpu_binding_formats = {
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||||
# if 0 /* RGB10A2 doesn't seem to work with Oculus head-sets, \
|
||||
* so move it after RGB16AF for the time being. */
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
# endif
|
||||
DXGI_FORMAT_R16G16B16A16_UNORM,
|
||||
DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
# if 1
|
||||
DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
# endif
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||||
};
|
||||
|
||||
std::optional result = choose_swapchain_format_from_candidates(gpu_binding_formats,
|
||||
runtime_formats);
|
||||
r_is_srgb_format = result ? (*result == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB) : false;
|
||||
if (result) {
|
||||
switch (*result) {
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM:
|
||||
r_format = GHOST_kXrSwapchainFormatRGB10_A2;
|
||||
break;
|
||||
case DXGI_FORMAT_R16G16B16A16_UNORM:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA16;
|
||||
break;
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA16F;
|
||||
break;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA8;
|
||||
break;
|
||||
}
|
||||
r_is_srgb_format = (*result == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
|
||||
}
|
||||
else {
|
||||
r_format = GHOST_kXrSwapchainFormatRGBA8;
|
||||
r_is_srgb_format = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -334,14 +419,18 @@ class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
|
||||
|
||||
m_ghost_ctx->m_device->CreateRenderTargetView(d3d_swapchain_image.texture, &rtv_desc, &rtv);
|
||||
if (!m_shared_resource) {
|
||||
DXGI_FORMAT format;
|
||||
ghost_format_to_dx_format(draw_info.swapchain_format, draw_info.expects_srgb_buffer, format);
|
||||
m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(
|
||||
draw_info.width, draw_info.height, rtv);
|
||||
draw_info.width, draw_info.height, format, rtv);
|
||||
}
|
||||
m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info.width, draw_info.height);
|
||||
# else
|
||||
if (!m_shared_resource) {
|
||||
m_shared_resource = m_ghost_d3d_ctx->createSharedOpenGLResource(draw_info.width,
|
||||
draw_info.height);
|
||||
DXGI_FORMAT format;
|
||||
ghost_format_to_dx_format(draw_info.swapchain_format, draw_info.expects_srgb_buffer, format);
|
||||
m_shared_resource = m_ghost_d3d_ctx->createSharedOpenGLResource(
|
||||
draw_info.width, draw_info.height, format);
|
||||
}
|
||||
m_ghost_d3d_ctx->blitFromOpenGLContext(m_shared_resource, draw_info.width, draw_info.height);
|
||||
|
||||
|
@@ -422,6 +422,7 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
|
||||
|
||||
assert(view_idx < 256);
|
||||
draw_view_info.view_idx = (char)view_idx;
|
||||
draw_view_info.swapchain_format = swapchain.getFormat();
|
||||
draw_view_info.expects_srgb_buffer = swapchain.isBufferSRGB();
|
||||
draw_view_info.ofsx = r_proj_layer_view.subImage.imageRect.offset.x;
|
||||
draw_view_info.ofsy = r_proj_layer_view.subImage.imageRect.offset.y;
|
||||
@@ -610,57 +611,6 @@ void GHOST_XrSession::destroyActions(const char *action_set_name,
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_XrSession::createActionSpaces(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XrInstance instance = m_context->getInstance();
|
||||
XrSession session = m_oxr->session;
|
||||
|
||||
for (uint32_t action_idx = 0; action_idx < count; ++action_idx) {
|
||||
const GHOST_XrActionSpaceInfo &info = infos[action_idx];
|
||||
|
||||
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!action->createSpace(instance, session, info)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GHOST_XrSession::destroyActionSpaces(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t action_idx = 0; action_idx < count; ++action_idx) {
|
||||
const GHOST_XrActionSpaceInfo &info = infos[action_idx];
|
||||
|
||||
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
||||
action->destroySpace(info.subaction_paths[subaction_idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos)
|
||||
@@ -671,21 +621,17 @@ bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
||||
}
|
||||
|
||||
XrInstance instance = m_context->getInstance();
|
||||
XrSession session = m_oxr->session;
|
||||
|
||||
for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
|
||||
const GHOST_XrActionProfileInfo &info = infos[profile_idx];
|
||||
const char *profile_path = info.profile_path;
|
||||
|
||||
for (uint32_t binding_idx = 0; binding_idx < info.count_bindings; ++binding_idx) {
|
||||
const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
|
||||
|
||||
GHOST_XrAction *action = action_set->findAction(binding.action_name);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
action->createBinding(instance, profile_path, binding);
|
||||
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
action->createBinding(instance, session, info);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -693,27 +639,21 @@ bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
||||
|
||||
void GHOST_XrSession::destroyActionBindings(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos)
|
||||
const char *const *action_names,
|
||||
const char *const *profile_paths)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
|
||||
const GHOST_XrActionProfileInfo &info = infos[profile_idx];
|
||||
const char *profile_path = info.profile_path;
|
||||
|
||||
for (uint32_t binding_idx = 0; binding_idx < info.count_bindings; ++binding_idx) {
|
||||
const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
|
||||
|
||||
GHOST_XrAction *action = action_set->findAction(binding.action_name);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
action->destroyBinding(profile_path);
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
GHOST_XrAction *action = action_set->findAction(action_names[i]);
|
||||
if (action == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
action->destroyBinding(profile_paths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,6 +755,7 @@ bool GHOST_XrSession::syncActions(const char *action_set_name)
|
||||
|
||||
bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const int64_t &duration,
|
||||
const float &frequency,
|
||||
const float &litude)
|
||||
@@ -829,12 +770,15 @@ bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
|
||||
return false;
|
||||
}
|
||||
|
||||
action->applyHapticFeedback(m_oxr->session, action_name, duration, frequency, amplitude);
|
||||
action->applyHapticFeedback(
|
||||
m_oxr->session, action_name, subaction_path, duration, frequency, amplitude);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GHOST_XrSession::stopHapticAction(const char *action_set_name, const char *action_name)
|
||||
void GHOST_XrSession::stopHapticAction(const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
@@ -846,7 +790,7 @@ void GHOST_XrSession::stopHapticAction(const char *action_set_name, const char *
|
||||
return;
|
||||
}
|
||||
|
||||
action->stopHapticFeedback(m_oxr->session, action_name);
|
||||
action->stopHapticFeedback(m_oxr->session, action_name, subaction_path);
|
||||
}
|
||||
|
||||
void *GHOST_XrSession::getActionSetCustomdata(const char *action_set_name)
|
||||
@@ -874,4 +818,25 @@ void *GHOST_XrSession::getActionCustomdata(const char *action_set_name, const ch
|
||||
return action->getCustomdata();
|
||||
}
|
||||
|
||||
uint32_t GHOST_XrSession::getActionCount(const char *action_set_name)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return action_set->getActionCount();
|
||||
}
|
||||
|
||||
void GHOST_XrSession::getActionCustomdataArray(const char *action_set_name,
|
||||
void **r_customdata_array)
|
||||
{
|
||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||
if (action_set == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
action_set->getActionCustomdataArray(r_customdata_array);
|
||||
}
|
||||
|
||||
/** \} */ /* Actions */
|
||||
|
@@ -60,18 +60,13 @@ class GHOST_XrSession {
|
||||
void destroyActions(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const char *const *action_names);
|
||||
bool createActionSpaces(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos);
|
||||
void destroyActionSpaces(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionSpaceInfo *infos);
|
||||
bool createActionBindings(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos);
|
||||
void destroyActionBindings(const char *action_set_name,
|
||||
uint32_t count,
|
||||
const GHOST_XrActionProfileInfo *infos);
|
||||
const char *const *action_names,
|
||||
const char *const *profile_paths);
|
||||
bool attachActionSets();
|
||||
|
||||
/**
|
||||
@@ -81,14 +76,19 @@ class GHOST_XrSession {
|
||||
bool syncActions(const char *action_set_name = nullptr);
|
||||
bool applyHapticAction(const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const int64_t &duration,
|
||||
const float &frequency,
|
||||
const float &litude);
|
||||
void stopHapticAction(const char *action_set_name, const char *action_name);
|
||||
void stopHapticAction(const char *action_set_name,
|
||||
const char *action_name,
|
||||
const char *subaction_path);
|
||||
|
||||
/* Custom data (owned by Blender, not GHOST) accessors. */
|
||||
void *getActionSetCustomdata(const char *action_set_name);
|
||||
void *getActionCustomdata(const char *action_set_name, const char *action_name);
|
||||
uint32_t getActionCount(const char *action_set_name);
|
||||
void getActionCustomdataArray(const char *action_set_name, void **r_customdata_array);
|
||||
|
||||
private:
|
||||
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
|
||||
|
@@ -67,8 +67,8 @@ GHOST_XrSwapchain::GHOST_XrSwapchain(GHOST_IXrGraphicsBinding &gpu_binding,
|
||||
"Failed to get swapchain image formats.");
|
||||
assert(swapchain_formats.size() == format_count);
|
||||
|
||||
std::optional chosen_format = gpu_binding.chooseSwapchainFormat(swapchain_formats,
|
||||
m_is_srgb_buffer);
|
||||
std::optional chosen_format = gpu_binding.chooseSwapchainFormat(
|
||||
swapchain_formats, m_format, m_is_srgb_buffer);
|
||||
if (!chosen_format) {
|
||||
throw GHOST_XrException(
|
||||
"Error: No format matching OpenXR runtime supported swapchain formats found.");
|
||||
@@ -97,6 +97,7 @@ GHOST_XrSwapchain::GHOST_XrSwapchain(GHOST_XrSwapchain &&other)
|
||||
: m_oxr(std::move(other.m_oxr)),
|
||||
m_image_width(other.m_image_width),
|
||||
m_image_height(other.m_image_height),
|
||||
m_format(other.m_format),
|
||||
m_is_srgb_buffer(other.m_is_srgb_buffer)
|
||||
{
|
||||
/* Prevent xrDestroySwapchain call for the moved out item. */
|
||||
@@ -134,7 +135,12 @@ void GHOST_XrSwapchain::updateCompositionLayerProjectViewSubImage(XrSwapchainSub
|
||||
r_sub_image.imageRect.extent = {m_image_width, m_image_height};
|
||||
}
|
||||
|
||||
bool GHOST_XrSwapchain::isBufferSRGB()
|
||||
GHOST_TXrSwapchainFormat GHOST_XrSwapchain::getFormat() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
bool GHOST_XrSwapchain::isBufferSRGB() const
|
||||
{
|
||||
return m_is_srgb_buffer;
|
||||
}
|
||||
|
@@ -37,10 +37,12 @@ class GHOST_XrSwapchain {
|
||||
|
||||
void updateCompositionLayerProjectViewSubImage(XrSwapchainSubImage &r_sub_image);
|
||||
|
||||
bool isBufferSRGB();
|
||||
GHOST_TXrSwapchainFormat getFormat() const;
|
||||
bool isBufferSRGB() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<OpenXRSwapchainData> m_oxr; /* Could use stack, but PImpl is preferable. */
|
||||
int32_t m_image_width, m_image_height;
|
||||
GHOST_TXrSwapchainFormat m_format;
|
||||
bool m_is_srgb_buffer = false;
|
||||
};
|
||||
|
@@ -871,7 +871,7 @@ void MEM_guarded_freeN(void *vmemh)
|
||||
|
||||
if (memh == NULL) {
|
||||
MemorY_ErroR("free", "attempt to free NULL pointer");
|
||||
/* print_error(err_stream, "%d\n", (memh+4000)->tag1); */
|
||||
// print_error(err_stream, "%d\n", (memh+4000)->tag1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,6 @@
|
||||
|
||||
set(INC
|
||||
.
|
||||
intern
|
||||
../guardedalloc
|
||||
)
|
||||
|
||||
@@ -42,14 +41,7 @@ if(WITH_OPENVDB)
|
||||
)
|
||||
|
||||
list(APPEND SRC
|
||||
intern/openvdb_level_set.cc
|
||||
intern/openvdb_transform.cc
|
||||
openvdb_capi.cc
|
||||
openvdb_util.cc
|
||||
|
||||
intern/openvdb_level_set.h
|
||||
intern/openvdb_transform.h
|
||||
openvdb_util.h
|
||||
)
|
||||
|
||||
list(APPEND LIB
|
||||
|
@@ -1,173 +0,0 @@
|
||||
/*
|
||||
* 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) 2015 Blender Foundation.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "openvdb_level_set.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "openvdb/tools/Composite.h"
|
||||
#include "openvdb_capi.h"
|
||||
#include "openvdb_util.h"
|
||||
|
||||
OpenVDBLevelSet::OpenVDBLevelSet()
|
||||
{
|
||||
openvdb::initialize();
|
||||
}
|
||||
|
||||
OpenVDBLevelSet::~OpenVDBLevelSet()
|
||||
{
|
||||
}
|
||||
|
||||
void OpenVDBLevelSet::mesh_to_level_set(const float *vertices,
|
||||
const int *faces,
|
||||
const int totvertices,
|
||||
const int totfaces,
|
||||
const openvdb::math::Transform::Ptr &xform)
|
||||
{
|
||||
std::vector<openvdb::Vec3s> points(totvertices);
|
||||
std::vector<openvdb::Vec3I> triangles(totfaces);
|
||||
std::vector<openvdb::Vec4I> quads;
|
||||
|
||||
for (int i = 0; i < totvertices; i++) {
|
||||
points[i] = openvdb::Vec3s(vertices[i * 3], vertices[i * 3 + 1], vertices[i * 3 + 2]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < totfaces; i++) {
|
||||
triangles[i] = openvdb::Vec3I(faces[i * 3], faces[i * 3 + 1], faces[i * 3 + 2]);
|
||||
}
|
||||
|
||||
this->grid = openvdb::tools::meshToLevelSet<openvdb::FloatGrid>(
|
||||
*xform, points, triangles, quads, 1);
|
||||
}
|
||||
|
||||
void OpenVDBLevelSet::volume_to_mesh(OpenVDBVolumeToMeshData *mesh,
|
||||
const double isovalue,
|
||||
const double adaptivity,
|
||||
const bool relax_disoriented_triangles)
|
||||
{
|
||||
std::vector<openvdb::Vec3s> out_points;
|
||||
std::vector<openvdb::Vec4I> out_quads;
|
||||
std::vector<openvdb::Vec3I> out_tris;
|
||||
openvdb::tools::volumeToMesh<openvdb::FloatGrid>(*this->grid,
|
||||
out_points,
|
||||
out_tris,
|
||||
out_quads,
|
||||
isovalue,
|
||||
adaptivity,
|
||||
relax_disoriented_triangles);
|
||||
mesh->vertices = (float *)MEM_malloc_arrayN(out_points.size(), sizeof(float[3]), __func__);
|
||||
mesh->quads = (int *)MEM_malloc_arrayN(out_quads.size(), sizeof(int[4]), __func__);
|
||||
mesh->triangles = NULL;
|
||||
if (out_tris.size() > 0) {
|
||||
mesh->triangles = (int *)MEM_malloc_arrayN(out_tris.size(), sizeof(int[3]), __func__);
|
||||
}
|
||||
|
||||
mesh->totvertices = out_points.size();
|
||||
mesh->tottriangles = out_tris.size();
|
||||
mesh->totquads = out_quads.size();
|
||||
|
||||
for (size_t i = 0; i < out_points.size(); i++) {
|
||||
mesh->vertices[i * 3] = out_points[i].x();
|
||||
mesh->vertices[i * 3 + 1] = out_points[i].y();
|
||||
mesh->vertices[i * 3 + 2] = out_points[i].z();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < out_quads.size(); i++) {
|
||||
mesh->quads[i * 4] = out_quads[i].x();
|
||||
mesh->quads[i * 4 + 1] = out_quads[i].y();
|
||||
mesh->quads[i * 4 + 2] = out_quads[i].z();
|
||||
mesh->quads[i * 4 + 3] = out_quads[i].w();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < out_tris.size(); i++) {
|
||||
mesh->triangles[i * 3] = out_tris[i].x();
|
||||
mesh->triangles[i * 3 + 1] = out_tris[i].y();
|
||||
mesh->triangles[i * 3 + 2] = out_tris[i].z();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenVDBLevelSet::filter(OpenVDBLevelSet_FilterType filter_type,
|
||||
int width,
|
||||
float distance,
|
||||
OpenVDBLevelSet_FilterBias filter_bias)
|
||||
{
|
||||
|
||||
if (!this->grid) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->grid->getGridClass() != openvdb::GRID_LEVEL_SET) {
|
||||
return;
|
||||
}
|
||||
|
||||
openvdb::tools::LevelSetFilter<openvdb::FloatGrid> filter(*this->grid);
|
||||
filter.setSpatialScheme((openvdb::math::BiasedGradientScheme)filter_bias);
|
||||
switch (filter_type) {
|
||||
case OPENVDB_LEVELSET_FILTER_GAUSSIAN:
|
||||
filter.gaussian(width);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_MEDIAN:
|
||||
filter.median(width);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_MEAN:
|
||||
filter.mean(width);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_MEAN_CURVATURE:
|
||||
filter.meanCurvature();
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_LAPLACIAN:
|
||||
filter.laplacian();
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_DILATE:
|
||||
filter.offset(distance);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_ERODE:
|
||||
filter.offset(distance);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_FILTER_NONE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
openvdb::FloatGrid::Ptr OpenVDBLevelSet::CSG_operation_apply(
|
||||
const openvdb::FloatGrid::Ptr &gridA,
|
||||
const openvdb::FloatGrid::Ptr &gridB,
|
||||
OpenVDBLevelSet_CSGOperation operation)
|
||||
{
|
||||
switch (operation) {
|
||||
case OPENVDB_LEVELSET_CSG_UNION:
|
||||
openvdb::tools::csgUnion(*gridA, *gridB);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_CSG_DIFFERENCE:
|
||||
openvdb::tools::csgDifference(*gridA, *gridB);
|
||||
break;
|
||||
case OPENVDB_LEVELSET_CSG_INTERSECTION:
|
||||
openvdb::tools::csgIntersection(*gridA, *gridB);
|
||||
break;
|
||||
}
|
||||
|
||||
return gridA;
|
||||
}
|
||||
|
||||
const openvdb::FloatGrid::Ptr &OpenVDBLevelSet::get_grid()
|
||||
{
|
||||
return this->grid;
|
||||
}
|
||||
|
||||
void OpenVDBLevelSet::set_grid(const openvdb::FloatGrid::Ptr &grid)
|
||||
{
|
||||
this->grid = grid;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user