Merge branch 'master' into asset-browser-grid-view

This commit is contained in:
Julian Eisel 2022-02-17 21:43:07 +01:00
commit 9bac0894f6
77 changed files with 5305 additions and 757 deletions

View File

@ -79,4 +79,6 @@ mark_as_advanced(
unset(_ffmpeg_SEARCH_DIRS)
unset(_ffmpeg_LIBRARIES)
unset(_ffmpeg_INCLUDE_DIR)
# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
# find_path so we don't need to clear it from the cache here.
unset(_ffmpeg_INCLUDE_DIR CACHE)

View File

@ -72,6 +72,7 @@ FIND_PATH(OSL_SHADER_DIR
/usr/include/OSL/
PATH_SUFFIXES
share/OSL/shaders
shaders
)
# handle the QUIETLY and REQUIRED arguments and set OSL_FOUND to TRUE if
@ -95,6 +96,7 @@ ENDIF()
MARK_AS_ADVANCED(
OSL_INCLUDE_DIR
OSL_SHADER_DIR
)
FOREACH(COMPONENT ${_osl_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)

View File

@ -83,12 +83,14 @@ ENDIF()
MARK_AS_ADVANCED(
OPENCOLORIO_INCLUDE_DIR
OPENCOLORIO_LIBRARY
OPENCOLORIO_OPENCOLORIO_LIBRARY
OPENCOLORIO_TINYXML_LIBRARY
OPENCOLORIO_YAML-CPP_LIBRARY
OPENCOLORIO_VERSION
)
FOREACH(COMPONENT ${_opencolorio_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
MARK_AS_ADVANCED(OPENCOLORIO_${UPPERCOMPONENT}_LIBRARY)
ENDFOREACH()
UNSET(COMPONENT)
UNSET(UPPERCOMPONENT)
UNSET(_opencolorio_FIND_COMPONENTS)

View File

@ -29,14 +29,6 @@ ENDIF()
# Old versions (before 2.0?) do not have any version string, just assuming this should be fine though.
SET(_openexr_libs_ver_init "2.0")
SET(_openexr_FIND_COMPONENTS
Half
Iex
IlmImf
IlmThread
Imath
)
SET(_openexr_SEARCH_DIRS
${OPENEXR_ROOT_DIR}
/opt/lib/openexr
@ -89,6 +81,24 @@ UNSET(_openexr_libs_ver_init)
STRING(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _openexr_libs_ver ${OPENEXR_VERSION})
# Different library names in 3.0, and Imath and Half moved out.
IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
SET(_openexr_FIND_COMPONENTS
Iex
IlmThread
OpenEXR
OpenEXRCore
)
ELSE()
SET(_openexr_FIND_COMPONENTS
Half
Iex
IlmImf
IlmThread
Imath
)
ENDIF()
SET(_openexr_LIBRARIES)
FOREACH(COMPONENT ${_openexr_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)
@ -107,6 +117,57 @@ ENDFOREACH()
UNSET(_openexr_libs_ver)
IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
# For OpenEXR 3.x, we also need to find the now separate Imath library.
# For simplicity we add it to the OpenEXR includes and libraries, as we
# have no direct dependency on Imath and it's simpler to support both
# 2.x and 3.x this way.
# Find include directory
FIND_PATH(IMATH_INCLUDE_DIR
NAMES
Imath/ImathMath.h
HINTS
${_openexr_SEARCH_DIRS}
PATH_SUFFIXES
include
)
# Find version
FIND_FILE(_imath_config
NAMES
ImathConfig.h
PATHS
${IMATH_INCLUDE_DIR}/Imath
NO_DEFAULT_PATH
)
# Find line with version, extract string, and format for library suffix.
FILE(STRINGS "${_imath_config}" _imath_build_specification
REGEX "^[ \t]*#define[ \t]+IMATH_VERSION_STRING[ \t]+\"[.0-9]+\".*$")
STRING(REGEX REPLACE ".*#define[ \t]+IMATH_VERSION_STRING[ \t]+\"([.0-9]+)\".*"
"\\1" _imath_libs_ver ${_imath_build_specification})
STRING(REGEX REPLACE "([0-9]+)[.]([0-9]+).*" "\\1_\\2" _imath_libs_ver ${_imath_libs_ver})
# Find library, with or without version number.
FIND_LIBRARY(IMATH_LIBRARY
NAMES
Imath-${_imath_libs_ver} Imath
NAMES_PER_DIR
HINTS
${_openexr_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
LIST(APPEND _openexr_LIBRARIES "${IMATH_LIBRARY}")
# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
# FIND_FILE so we don't need to clear it from the cache here.
UNSET(_imath_config CACHE)
UNSET(_imath_libs_ver)
UNSET(_imath_build_specification)
ENDIF()
# handle the QUIETLY and REQUIRED arguments and set OPENEXR_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
@ -115,13 +176,25 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenEXR DEFAULT_MSG
IF(OPENEXR_FOUND)
SET(OPENEXR_LIBRARIES ${_openexr_LIBRARIES})
# Both include paths are needed because of dummy OSL headers mixing #include <OpenEXR/foo.h> and #include <foo.h> :(
SET(OPENEXR_INCLUDE_DIRS ${OPENEXR_INCLUDE_DIR} ${OPENEXR_INCLUDE_DIR}/OpenEXR)
# Both include paths are needed because of dummy OSL headers mixing
# #include <OpenEXR/foo.h> and #include <foo.h>, as well as Alembic
# include <half.h> directly.
SET(OPENEXR_INCLUDE_DIRS
${OPENEXR_INCLUDE_DIR}
${OPENEXR_INCLUDE_DIR}/OpenEXR)
IF(OPENEXR_VERSION VERSION_GREATER_EQUAL "3.0.0")
LIST(APPEND OPENEXR_INCLUDE_DIRS
${IMATH_INCLUDE_DIR}
${IMATH_INCLUDE_DIR}/Imath)
ENDIF()
ENDIF()
MARK_AS_ADVANCED(
OPENEXR_INCLUDE_DIR
OPENEXR_VERSION
IMATH_INCLUDE_DIR
IMATH_LIBRARY
)
FOREACH(COMPONENT ${_openexr_FIND_COMPONENTS})
STRING(TOUPPER ${COMPONENT} UPPERCOMPONENT)

View File

@ -106,6 +106,7 @@ ENDIF()
MARK_AS_ADVANCED(
OPENIMAGEDENOISE_INCLUDE_DIR
OPENIMAGEDENOISE_LIBRARY
)
FOREACH(COMPONENT ${_openimagedenoise_FIND_COMPONENTS})

View File

@ -44,6 +44,8 @@ FIND_LIBRARY(OPENIMAGEIO_LIBRARY
lib64 lib
)
set(_openimageio_LIBRARIES ${OPENIMAGEIO_LIBRARY})
FIND_FILE(OPENIMAGEIO_IDIFF
NAMES
idiff
@ -53,14 +55,47 @@ FIND_FILE(OPENIMAGEIO_IDIFF
bin
)
# Additionally find util library if needed. In old versions this library was
# included in libOpenImageIO and linking to both would duplicate symbols. In
# new versions we need to link to both.
FIND_FILE(_openimageio_export
NAMES
export.h
PATHS
${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO
NO_DEFAULT_PATH
)
# Use existence of OIIO_UTIL_API to check if it's a separate lib.
FILE(STRINGS "${_openimageio_export}" _openimageio_util_define
REGEX "^[ \t]*#[ \t]*define[ \t]+OIIO_UTIL_API.*$")
IF(_openimageio_util_define)
FIND_LIBRARY(OPENIMAGEIO_UTIL_LIBRARY
NAMES
OpenImageIO_Util
HINTS
${_openimageio_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
LIST(APPEND _openimageio_LIBRARIES ${OPENIMAGEIO_UTIL_LIBRARY})
ENDIF()
# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
# FIND_FILE so we don't need to clear it from the cache here.
UNSET(_openimageio_export CACHE)
UNSET(_openimageio_util_define)
# handle the QUIETLY and REQUIRED arguments and set OPENIMAGEIO_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(OpenImageIO DEFAULT_MSG
OPENIMAGEIO_LIBRARY OPENIMAGEIO_INCLUDE_DIR)
_openimageio_LIBRARIES OPENIMAGEIO_INCLUDE_DIR)
IF(OPENIMAGEIO_FOUND)
SET(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARY})
SET(OPENIMAGEIO_LIBRARIES ${_openimageio_LIBRARIES})
SET(OPENIMAGEIO_INCLUDE_DIRS ${OPENIMAGEIO_INCLUDE_DIR})
IF(EXISTS ${OPENIMAGEIO_INCLUDE_DIR}/OpenImageIO/pugixml.hpp)
SET(OPENIMAGEIO_PUGIXML_FOUND TRUE)
@ -74,7 +109,9 @@ ENDIF()
MARK_AS_ADVANCED(
OPENIMAGEIO_INCLUDE_DIR
OPENIMAGEIO_LIBRARY
OPENIMAGEIO_UTIL_LIBRARY
OPENIMAGEIO_IDIFF
)
UNSET(_openimageio_SEARCH_DIRS)
UNSET(_openimageio_LIBRARIES)

View File

@ -345,6 +345,7 @@ if(WITH_BOOST)
find_package(IcuLinux)
endif()
mark_as_advanced(Boost_DIR) # why doesn't boost do this?
mark_as_advanced(Boost_INCLUDE_DIR) # why doesn't boost do this?
endif()
set(BOOST_INCLUDE_DIR ${Boost_INCLUDE_DIRS})

View File

@ -32,7 +32,8 @@ typedef map<string, ConvertNode *> ProxyMap;
void BlenderSync::find_shader(BL::ID &id, array<Node *> &used_shaders, Shader *default_shader)
{
Shader *shader = (id) ? shader_map.find(id) : default_shader;
Shader *synced_shader = (id) ? shader_map.find(id) : nullptr;
Shader *shader = (synced_shader) ? synced_shader : default_shader;
used_shaders.push_back_slow(shader);
shader->tag_used(scene);

View File

@ -817,28 +817,28 @@ void ShaderManager::init_xyz_transforms()
Transform xyz_to_rgb;
if (config->hasRole("aces_interchange")) {
/* Standard OpenColorIO role, defined as ACES2065-1. */
const Transform xyz_E_to_aces = make_transform(1.0498110175f,
0.0f,
-0.0000974845f,
0.0f,
-0.4959030231f,
1.3733130458f,
0.0982400361f,
0.0f,
0.0f,
0.0f,
0.9912520182f,
0.0f);
const Transform xyz_D65_to_E = make_transform(
1.0521111f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.9184170f, 0.0f);
/* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
Transform aces_to_rgb;
if (!to_scene_linear_transform(config, "aces_interchange", aces_to_rgb)) {
return;
}
xyz_to_rgb = aces_to_rgb * xyz_E_to_aces * xyz_D65_to_E;
/* This is the OpenColorIO builtin transform:
* UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
const Transform ACES_AP0_to_xyz_D65 = make_transform(0.938280f,
-0.004451f,
0.016628f,
0.000000f,
0.337369f,
0.729522f,
-0.066890f,
0.000000f,
0.001174f,
-0.003711f,
1.091595f,
0.000000f);
const Transform xyz_to_aces = transform_inverse(ACES_AP0_to_xyz_D65);
xyz_to_rgb = aces_to_rgb * xyz_to_aces;
}
else if (config->hasRole("XYZ")) {
/* Custom role used before the standard existed. */

View File

@ -110,9 +110,11 @@ class GHOST_SharedOpenGLResource {
struct SharedData {
HANDLE device;
GLuint fbo;
HANDLE render_buf{nullptr};
HANDLE render_target{nullptr};
} m_shared;
enum RenderTarget { TARGET_RENDERBUF, TARGET_TEX2D };
public:
GHOST_SharedOpenGLResource(ID3D11Device *device,
ID3D11DeviceContext *device_ctx,
@ -179,37 +181,64 @@ class GHOST_SharedOpenGLResource {
}
if (m_is_initialized) {
if (m_shared.render_buf) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
if (m_shared.render_target
#if 1
/* TODO: #wglDXUnregisterObjectNV() causes an access violation on AMD when the shared
* resource is a GL texture. Since there is currently no good alternative, just skip
* unregistering the shared resource. */
&& !m_use_gl_texture2d
#endif
) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_target);
}
if (m_shared.device) {
wglDXCloseDeviceNV(m_shared.device);
}
glDeleteFramebuffers(1, &m_shared.fbo);
glDeleteRenderbuffers(1, &m_gl_render_buf);
if (m_use_gl_texture2d) {
glDeleteTextures(1, &m_gl_render_target);
}
else {
glDeleteRenderbuffers(1, &m_gl_render_target);
}
}
}
void reregisterSharedObject()
/* Returns true if the shared object was successfully registered, false otherwise. */
bool reregisterSharedObject(RenderTarget target)
{
if (m_shared.render_buf) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_buf);
if (m_shared.render_target) {
wglDXUnregisterObjectNV(m_shared.device, m_shared.render_target);
}
if (!m_render_target_tex) {
return;
return false;
}
m_shared.render_buf = wglDXRegisterObjectNV(m_shared.device,
m_render_target_tex,
m_gl_render_buf,
GL_RENDERBUFFER,
WGL_ACCESS_READ_WRITE_NV);
if (target == TARGET_TEX2D) {
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA8,
m_cur_width,
m_cur_height,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
nullptr);
}
if (!m_shared.render_buf) {
m_shared.render_target = wglDXRegisterObjectNV(m_shared.device,
m_render_target_tex,
m_gl_render_target,
(target == TARGET_TEX2D) ? GL_TEXTURE_2D :
GL_RENDERBUFFER,
WGL_ACCESS_READ_WRITE_NV);
if (!m_shared.render_target) {
fprintf(stderr, "Error registering shared object using wglDXRegisterObjectNV()\n");
return;
return false;
}
return true;
}
GHOST_TSuccess initialize()
@ -221,16 +250,33 @@ class GHOST_SharedOpenGLResource {
}
/* Build the renderbuffer. */
glGenRenderbuffers(1, &m_gl_render_buf);
glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_buf);
glGenRenderbuffers(1, &m_gl_render_target);
glBindRenderbuffer(GL_RENDERBUFFER, m_gl_render_target);
reregisterSharedObject();
if (!reregisterSharedObject(TARGET_RENDERBUF)) {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
if (m_gl_render_target) {
glDeleteRenderbuffers(1, &m_gl_render_target);
}
/* Fall back to texture 2d. */
m_use_gl_texture2d = true;
glGenTextures(1, &m_gl_render_target);
glBindTexture(GL_TEXTURE_2D, m_gl_render_target);
reregisterSharedObject(TARGET_TEX2D);
}
/* Build the framebuffer */
glGenFramebuffers(1, &m_shared.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, m_shared.fbo);
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_buf);
if (m_use_gl_texture2d) {
glFramebufferTexture2D(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_gl_render_target, 0);
}
else {
glFramebufferRenderbuffer(
GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_gl_render_target);
}
m_is_initialized = true;
return GHOST_kSuccess;
@ -245,7 +291,7 @@ class GHOST_SharedOpenGLResource {
if ((m_cur_width != width) || (m_cur_height != height)) {
m_cur_width = width;
m_cur_height = height;
reregisterSharedObject();
reregisterSharedObject(m_use_gl_texture2d ? TARGET_TEX2D : TARGET_RENDERBUF);
}
}
@ -293,18 +339,19 @@ class GHOST_SharedOpenGLResource {
private:
void beginGLOnly()
{
wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
wglDXLockObjectsNV(m_shared.device, 1, &m_shared.render_target);
}
void endGLOnly()
{
wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_buf);
wglDXUnlockObjectsNV(m_shared.device, 1, &m_shared.render_target);
}
ID3D11Device *m_device;
ID3D11DeviceContext *m_device_ctx;
GLuint m_gl_render_buf;
GLuint m_gl_render_target;
unsigned int m_cur_width, m_cur_height;
bool m_is_initialized{false};
bool m_use_gl_texture2d{false};
};
GHOST_SharedOpenGLResource *GHOST_ContextD3D::createSharedOpenGLResource(

View File

@ -7,6 +7,7 @@ set(INC
../guardedalloc
../../source/blender/blenlib
../../source/blender/gpu
../../source/blender/gpu/intern
../../source/blender/makesdna
)
@ -20,6 +21,7 @@ set(SRC
ocio_capi.h
ocio_impl.h
ocio_shader_shared.hh
)
set(LIB
@ -56,8 +58,38 @@ if(WITH_OPENCOLORIO)
)
endif()
data_to_c_simple(gpu_shader_display_transform.glsl SRC)
data_to_c_simple(gpu_shader_display_transform_vertex.glsl SRC)
set(GLSL_SRC
gpu_shader_display_transform_vert.glsl
gpu_shader_display_transform_frag.glsl
ocio_shader_shared.hh
)
set(GLSL_C)
foreach(GLSL_FILE ${GLSL_SRC})
data_to_c_simple(${GLSL_FILE} GLSL_C)
endforeach()
blender_add_lib(bf_ocio_shaders "${GLSL_C}" "" "" "")
list(APPEND LIB
bf_ocio_shaders
)
set(GLSL_SOURCE_CONTENT "")
foreach(GLSL_FILE ${GLSL_SRC})
get_filename_component(GLSL_FILE_NAME ${GLSL_FILE} NAME)
string(REPLACE "." "_" GLSL_FILE_NAME_UNDERSCORES ${GLSL_FILE_NAME})
string(APPEND GLSL_SOURCE_CONTENT "SHADER_SOURCE\(datatoc_${GLSL_FILE_NAME_UNDERSCORES}, \"${GLSL_FILE_NAME}\", \"${GLSL_FILE}\"\)\n")
endforeach()
set(glsl_source_list_file "${CMAKE_CURRENT_BINARY_DIR}/glsl_ocio_source_list.h")
file(GENERATE OUTPUT ${glsl_source_list_file} CONTENT "${GLSL_SOURCE_CONTENT}")
list(APPEND SRC ${glsl_source_list_file})
list(APPEND INC ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(bf_ocio_shaders PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
endif()

View File

@ -1,39 +1,10 @@
/* Blender OpenColorIO implementation */
uniform sampler2D image_texture;
uniform sampler2D overlay_texture;
uniform float dither;
uniform float scale;
uniform float exponent;
uniform bool predivide;
uniform bool overlay;
/* -------------------------------------------------------------------- */
/** \name Curve Mapping Implementation
* \{ */
#ifdef USE_CURVE_MAPPING
uniform sampler1D curve_mapping_texture;
layout(std140) uniform OCIO_GPUCurveMappingParameters
{
/* Curve mapping parameters
*
* See documentation for OCIO_CurveMappingSettings to get fields descriptions.
* (this ones pretty much copies stuff from C structure.)
*/
vec4 curve_mapping_mintable;
vec4 curve_mapping_range;
vec4 curve_mapping_ext_in_x;
vec4 curve_mapping_ext_in_y;
vec4 curve_mapping_ext_out_x;
vec4 curve_mapping_ext_out_y;
vec4 curve_mapping_first_x;
vec4 curve_mapping_first_y;
vec4 curve_mapping_last_x;
vec4 curve_mapping_last_y;
vec4 curve_mapping_black;
vec4 curve_mapping_bwmul;
int curve_mapping_lut_size;
int curve_mapping_use_extend_extrapolate;
};
float read_curve_mapping(int table, int index)
{
@ -43,27 +14,27 @@ float read_curve_mapping(int table, int index)
float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
{
if (x <= first[0]) {
if (curve_mapping_use_extend_extrapolate == 0) {
if (curve_mapping.use_extend_extrapolate == 0) {
/* horizontal extrapolation */
return first[1];
}
else {
float fac = (curve_mapping_ext_in_x[table] != 0.0) ?
((x - first[0]) / curve_mapping_ext_in_x[table]) :
float fac = (curve_mapping.ext_in_x[table] != 0.0) ?
((x - first[0]) / curve_mapping.ext_in_x[table]) :
10000.0;
return first[1] + curve_mapping_ext_in_y[table] * fac;
return first[1] + curve_mapping.ext_in_y[table] * fac;
}
}
else if (x >= last[0]) {
if (curve_mapping_use_extend_extrapolate == 0) {
if (curve_mapping.use_extend_extrapolate == 0) {
/* horizontal extrapolation */
return last[1];
}
else {
float fac = (curve_mapping_ext_out_x[table] != 0.0) ?
((x - last[0]) / curve_mapping_ext_out_x[table]) :
float fac = (curve_mapping.ext_out_x[table] != 0.0) ?
((x - last[0]) / curve_mapping.ext_out_x[table]) :
-10000.0;
return last[1] + curve_mapping_ext_out_y[table] * fac;
return last[1] + curve_mapping.ext_out_y[table] * fac;
}
}
return 0.0;
@ -71,10 +42,10 @@ float curvemap_calc_extend(int table, float x, vec2 first, vec2 last)
float curvemap_evaluateF(int table, float value)
{
float mintable_ = curve_mapping_mintable[table];
float range = curve_mapping_range[table];
float mintable_ = curve_mapping.mintable[table];
float range = curve_mapping.range[table];
float mintable = 0.0;
int CM_TABLE = curve_mapping_lut_size - 1;
int CM_TABLE = curve_mapping.lut_size - 1;
float fi;
int i;
@ -87,8 +58,8 @@ float curvemap_evaluateF(int table, float value)
if (fi < 0.0 || fi > float(CM_TABLE)) {
return curvemap_calc_extend(table,
value,
vec2(curve_mapping_first_x[table], curve_mapping_first_y[table]),
vec2(curve_mapping_last_x[table], curve_mapping_last_y[table]));
vec2(curve_mapping.first_x[table], curve_mapping.first_y[table]),
vec2(curve_mapping.last_x[table], curve_mapping.last_y[table]));
}
else {
if (i < 0) {
@ -106,7 +77,7 @@ float curvemap_evaluateF(int table, float value)
vec4 curvemapping_evaluate_premulRGBF(vec4 col)
{
col.rgb = (col.rgb - curve_mapping_black.rgb) * curve_mapping_bwmul.rgb;
col.rgb = (col.rgb - curve_mapping.black.rgb) * curve_mapping.bwmul.rgb;
vec4 result;
result.r = curvemap_evaluateF(0, col.r);
@ -115,8 +86,15 @@ vec4 curvemapping_evaluate_premulRGBF(vec4 col)
result.a = col.a;
return result;
}
#endif /* USE_CURVE_MAPPING */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Dithering
* \{ */
/* Using a triangle distribution which gives a more final uniform noise.
* See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */
/* GPUs are rounding before writing to framebuffer so we center the distribution around 0.0. */
@ -135,23 +113,33 @@ float dither_random_value(vec2 co)
vec2 round_to_pixel(sampler2D tex, vec2 uv)
{
vec2 size = textureSize(tex, 0);
return vec2(ivec2(uv * size)) / size;
vec2 size = vec2(textureSize(tex, 0));
return floor(uv * size) / size;
}
vec4 apply_dither(vec4 col, vec2 uv)
{
col.rgb += dither_random_value(uv) * 0.0033 * dither;
col.rgb += dither_random_value(uv) * 0.0033 * parameters.dither;
return col;
}
vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay, vec2 noise_uv)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Main Processing
* \{ */
/* Prototypes: Implementation is generaterd and defined after. */
vec4 OCIO_to_scene_linear(vec4 pixel);
vec4 OCIO_to_display(vec4 pixel);
vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay)
{
#ifdef USE_CURVE_MAPPING
col = curvemapping_evaluate_premulRGBF(col);
#endif
if (predivide) {
if (parameters.use_predivide) {
if (col.a > 0.0 && col.a < 1.0) {
col.rgb *= 1.0 / col.a;
}
@ -166,7 +154,7 @@ vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay, vec2 noise_uv)
col = OCIO_to_scene_linear(col);
/* Apply exposure in scene linear. */
col.rgb *= scale;
col.rgb *= parameters.scale;
/* Convert to display space. */
col = OCIO_to_display(col);
@ -177,34 +165,31 @@ vec4 OCIO_ProcessColor(vec4 col, vec4 col_overlay, vec2 noise_uv)
* i.e: The linear color space w.r.t. display chromaticity and radiometry.
* We separate the colormanagement process into two steps to be able to
* merge UI using alpha blending in the correct color space. */
if (overlay) {
col.rgb = pow(col.rgb, vec3(exponent * 2.2));
if (parameters.use_overlay) {
col.rgb = pow(col.rgb, vec3(parameters.exponent * 2.2));
col = clamp(col, 0.0, 1.0);
col *= 1.0 - col_overlay.a;
col += col_overlay; /* Assumed unassociated alpha. */
col.rgb = pow(col.rgb, vec3(1.0 / 2.2));
}
else {
col.rgb = pow(col.rgb, vec3(exponent));
col.rgb = pow(col.rgb, vec3(parameters.exponent));
}
if (dither > 0.0) {
if (parameters.dither > 0.0) {
vec2 noise_uv = round_to_pixel(image_texture, texCoord_interp.st);
col = apply_dither(col, noise_uv);
}
return col;
}
/* ------------------------------------------------------------------------ */
in vec2 texCoord_interp;
out vec4 fragColor;
/** \} */
void main()
{
vec4 col = texture(image_texture, texCoord_interp.st);
vec4 col_overlay = texture(overlay_texture, texCoord_interp.st);
vec2 noise_uv = round_to_pixel(image_texture, texCoord_interp.st);
fragColor = OCIO_ProcessColor(col, col_overlay, noise_uv);
fragColor = OCIO_ProcessColor(col, col_overlay);
}

View File

@ -1,10 +1,4 @@
uniform mat4 ModelViewProjectionMatrix;
in vec2 texCoord;
in vec2 pos;
out vec2 texCoord_interp;
void main()
{
gl_Position = ModelViewProjectionMatrix * vec4(pos.xy, 0.0f, 1.0f);

View File

@ -320,16 +320,18 @@ void OCIOImpl::configGetXYZtoRGB(OCIO_ConstConfigRcPtr *config_, float xyz_to_rg
}
if (config->hasRole("aces_interchange")) {
/* Standard OpenColorIO role, defined as ACES2065-1. */
const float xyz_E_to_aces[3][3] = {{1.0498110175f, -0.4959030231f, 0.0f},
{0.0f, 1.3733130458f, 0.0f},
{-0.0000974845f, 0.0982400361f, 0.9912520182f}};
const float xyz_D65_to_E[3][3] = {
{1.0521111f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.9184170f}};
/* Standard OpenColorIO role, defined as ACES AP0 (ACES2065-1). */
float aces_to_rgb[3][3];
if (to_scene_linear_matrix(config, "aces_interchange", aces_to_rgb)) {
mul_m3_series(xyz_to_rgb, aces_to_rgb, xyz_E_to_aces, xyz_D65_to_E);
/* This is the OpenColorIO builtin transform:
* UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD. */
const float ACES_AP0_to_xyz_D65[3][3] = {{0.938280f, 0.337369f, 0.001174f},
{-0.004451f, 0.729522f, -0.003711f},
{0.016628f, -0.066890f, 1.091595f}};
float xyz_to_aces[3][3];
invert_m3_m3(xyz_to_aces, ACES_AP0_to_xyz_D65);
mul_m3_m3m3(xyz_to_rgb, aces_to_rgb, xyz_to_aces);
}
}
else if (config->hasRole("XYZ")) {

View File

@ -21,14 +21,14 @@
#include "GPU_shader.h"
#include "GPU_uniform_buffer.h"
#include "gpu_shader_create_info.hh"
using namespace OCIO_NAMESPACE;
#include "MEM_guardedalloc.h"
#include "ocio_impl.h"
extern "C" char datatoc_gpu_shader_display_transform_glsl[];
extern "C" char datatoc_gpu_shader_display_transform_vertex_glsl[];
#include "ocio_shader_shared.hh"
/* **** OpenGL drawing routines using GLSL for color space transform ***** */
@ -39,41 +39,19 @@ enum OCIO_GPUTextureSlots {
TEXTURE_SLOT_LUTS_OFFSET = 3,
};
/* Curve mapping parameters
*
* See documentation for OCIO_CurveMappingSettings to get fields descriptions.
* (this ones pretty much copies stuff from C structure.)
*/
struct OCIO_GPUCurveMappingParameters {
float curve_mapping_mintable[4];
float curve_mapping_range[4];
float curve_mapping_ext_in_x[4];
float curve_mapping_ext_in_y[4];
float curve_mapping_ext_out_x[4];
float curve_mapping_ext_out_y[4];
float curve_mapping_first_x[4];
float curve_mapping_first_y[4];
float curve_mapping_last_x[4];
float curve_mapping_last_y[4];
float curve_mapping_black[4];
float curve_mapping_bwmul[4];
int curve_mapping_lut_size;
int curve_mapping_use_extend_extrapolate;
int _pad[2];
/** WARNING: Needs to be 16byte aligned. Used as UBO data. */
enum OCIO_GPUUniformBufSlots {
UNIFORMBUF_SLOT_DISPLAY = 0,
UNIFORMBUF_SLOT_CURVEMAP = 1,
UNIFORMBUF_SLOT_LUTS = 2,
};
struct OCIO_GPUShader {
/* GPU shader. */
struct GPUShader *shader = nullptr;
/** Uniform locations. */
int scale_loc = 0;
int exponent_loc = 0;
int dither_loc = 0;
int overlay_loc = 0;
int predivide_loc = 0;
int ubo_bind = 0;
/** Uniform parameters. */
OCIO_GPUParameters parameters = {};
GPUUniformBuf *parameters_buffer = nullptr;
/* Destructor. */
~OCIO_GPUShader()
@ -81,6 +59,9 @@ struct OCIO_GPUShader {
if (shader) {
GPU_shader_free(shader);
}
if (parameters_buffer) {
GPU_uniformbuf_free(parameters_buffer);
}
}
};
@ -103,6 +84,7 @@ struct OCIO_GPUTextures {
/* Uniforms */
std::vector<OCIO_GPUUniform> uniforms;
GPUUniformBuf *uniforms_buffer = nullptr;
/* Destructor. */
~OCIO_GPUTextures()
@ -113,6 +95,9 @@ struct OCIO_GPUTextures {
if (dummy) {
GPU_texture_free(dummy);
}
if (uniforms_buffer) {
GPU_uniformbuf_free(uniforms_buffer);
}
}
};
@ -165,97 +150,134 @@ static bool createGPUShader(OCIO_GPUShader &shader,
const GpuShaderDescRcPtr &shaderdesc_to_display,
const bool use_curve_mapping)
{
std::ostringstream os;
using namespace blender::gpu::shader;
std::string source;
source += shaderdesc_to_scene_linear->getShaderText();
source += "\n";
source += shaderdesc_to_display->getShaderText();
source += "\n";
{
/* Fragment shader */
/* Work around OpenColorIO not supporting latest GLSL yet. */
os << "#define texture2D texture\n";
os << "#define texture3D texture\n";
if (use_curve_mapping) {
os << "#define USE_CURVE_MAPPING\n";
/* Replace all uniform declarations by a comment.
* This avoids double declarations from the backend. */
size_t index = 0;
while (true) {
index = source.find("uniform ", index);
if (index == -1) {
break;
}
source.replace(index, 2, "//");
index += 2;
}
os << shaderdesc_to_scene_linear->getShaderText() << "\n";
os << shaderdesc_to_display->getShaderText() << "\n";
os << datatoc_gpu_shader_display_transform_glsl;
}
shader.shader = GPU_shader_create(datatoc_gpu_shader_display_transform_vertex_glsl,
os.str().c_str(),
nullptr,
nullptr,
nullptr,
"OCIOShader");
StageInterfaceInfo iface("OCIO_Interface", "");
iface.smooth(Type::VEC2, "texCoord_interp");
if (shader.shader == nullptr) {
return false;
}
shader.scale_loc = GPU_shader_get_uniform(shader.shader, "scale");
shader.exponent_loc = GPU_shader_get_uniform(shader.shader, "exponent");
shader.dither_loc = GPU_shader_get_uniform(shader.shader, "dither");
shader.overlay_loc = GPU_shader_get_uniform(shader.shader, "overlay");
shader.predivide_loc = GPU_shader_get_uniform(shader.shader, "predivide");
shader.ubo_bind = GPU_shader_get_uniform_block_binding(shader.shader,
"OCIO_GPUCurveMappingParameters");
GPU_shader_bind(shader.shader);
/* Set texture bind point uniform once. This is saved by the shader. */
GPUShader *sh = shader.shader;
GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "image_texture"), TEXTURE_SLOT_IMAGE);
GPU_shader_uniform_int(sh, GPU_shader_get_uniform(sh, "overlay_texture"), TEXTURE_SLOT_OVERLAY);
ShaderCreateInfo info("OCIO_Display");
/* Work around OpenColorIO not supporting latest GLSL yet. */
info.define("texture2D", "texture");
info.define("texture3D", "texture");
info.typedef_source("ocio_shader_shared.hh");
info.sampler(TEXTURE_SLOT_IMAGE, ImageType::FLOAT_2D, "image_texture");
info.sampler(TEXTURE_SLOT_OVERLAY, ImageType::FLOAT_2D, "overlay_texture");
info.uniform_buf(UNIFORMBUF_SLOT_DISPLAY, "OCIO_GPUParameters", "parameters");
info.push_constant(Type::MAT4, "ModelViewProjectionMatrix");
info.vertex_in(0, Type::VEC2, "pos");
info.vertex_in(1, Type::VEC2, "texCoord");
info.vertex_out(iface);
info.fragment_out(0, Type::VEC4, "fragColor");
info.vertex_source("gpu_shader_display_transform_vert.glsl");
info.fragment_source("gpu_shader_display_transform_frag.glsl");
info.fragment_source_generated = source;
if (use_curve_mapping) {
GPU_shader_uniform_int(
sh, GPU_shader_get_uniform(sh, "curve_mapping_texture"), TEXTURE_SLOT_CURVE_MAPPING);
info.define("USE_CURVE_MAPPING");
info.uniform_buf(UNIFORMBUF_SLOT_CURVEMAP, "OCIO_GPUCurveMappingParameters", "curve_mapping");
info.sampler(TEXTURE_SLOT_CURVE_MAPPING, ImageType::FLOAT_1D, "curve_mapping_texture");
}
/* Set LUT textures. */
for (int i = 0; i < textures.luts.size(); i++) {
GPU_shader_uniform_int(sh,
GPU_shader_get_uniform(sh, textures.luts[i].sampler_name.c_str()),
TEXTURE_SLOT_LUTS_OFFSET + i);
int slot = TEXTURE_SLOT_LUTS_OFFSET;
for (OCIO_GPULutTexture &texture : textures.luts) {
ImageType type = GPU_texture_dimensions(texture.texture) == 2 ? ImageType::FLOAT_2D :
ImageType::FLOAT_3D;
info.sampler(slot++, type, texture.sampler_name.c_str());
}
/* Set uniforms. */
for (OCIO_GPUUniform &uniform : textures.uniforms) {
const GpuShaderDesc::UniformData &data = uniform.data;
const char *name = uniform.name.c_str();
/* Set LUT uniforms. */
if (!textures.uniforms.empty()) {
/* NOTE: For simplicity, we pad everything to size of vec4 avoiding sorting and alignment
* issues. It is unlikely that this becomes a real issue. */
size_t ubo_size = textures.uniforms.size() * sizeof(float) * 4;
void *ubo_data_buf = malloc(ubo_size);
if (data.m_getDouble) {
GPU_shader_uniform_1f(sh, name, (float)data.m_getDouble());
}
else if (data.m_getBool) {
GPU_shader_uniform_1f(sh, name, (float)(data.m_getBool() ? 1.0f : 0.0f));
}
else if (data.m_getFloat3) {
GPU_shader_uniform_3f(sh,
name,
(float)data.m_getFloat3()[0],
(float)data.m_getFloat3()[1],
(float)data.m_getFloat3()[2]);
}
else if (data.m_vectorFloat.m_getSize && data.m_vectorFloat.m_getVector) {
GPU_shader_uniform_vector(sh,
GPU_shader_get_uniform(sh, name),
(int)data.m_vectorFloat.m_getSize(),
1,
(float *)data.m_vectorFloat.m_getVector());
}
else if (data.m_vectorInt.m_getSize && data.m_vectorInt.m_getVector) {
GPU_shader_uniform_vector_int(sh,
GPU_shader_get_uniform(sh, name),
(int)data.m_vectorInt.m_getSize(),
1,
(int *)data.m_vectorInt.m_getVector());
uint32_t *ubo_data = reinterpret_cast<uint32_t *>(ubo_data_buf);
std::stringstream ss;
ss << "struct OCIO_GPULutParameters {\n";
int index = 0;
for (OCIO_GPUUniform &uniform : textures.uniforms) {
index += 1;
const GpuShaderDesc::UniformData &data = uniform.data;
const char *name = uniform.name.c_str();
char prefix = ' ';
int vec_len;
switch (data.m_type) {
case UNIFORM_DOUBLE: {
vec_len = 1;
float value = float(data.m_getDouble());
memcpy(ubo_data, &value, sizeof(float));
break;
}
case UNIFORM_BOOL: {
prefix = 'b';
vec_len = 1;
int value = int(data.m_getBool());
memcpy(ubo_data, &value, sizeof(int));
break;
}
case UNIFORM_FLOAT3:
vec_len = 3;
memcpy(ubo_data, data.m_getFloat3().data(), sizeof(float) * 3);
break;
case UNIFORM_VECTOR_FLOAT:
vec_len = data.m_vectorFloat.m_getSize();
memcpy(ubo_data, data.m_vectorFloat.m_getVector(), sizeof(float) * vec_len);
break;
case UNIFORM_VECTOR_INT:
prefix = 'i';
vec_len = data.m_vectorInt.m_getSize();
memcpy(ubo_data, data.m_vectorInt.m_getVector(), sizeof(int) * vec_len);
break;
default:
continue;
}
/* Align every member to 16bytes. */
ubo_data += 4;
/* Use a generic variable name because some GLSL compilers can interpret the preprocessor
* define as recursive. */
ss << " " << prefix << "vec4 var" << index << ";\n";
/* Use a define to keep the generated code working. */
blender::StringRef suffix = blender::StringRefNull("xyzw").substr(0, vec_len);
ss << "#define " << name << " lut_parameters.var" << index << "." << suffix << "\n";
}
ss << "};\n";
info.typedef_source_generated = ss.str();
info.uniform_buf(UNIFORMBUF_SLOT_LUTS, "OCIO_GPULutParameters", "lut_parameters");
textures.uniforms_buffer = GPU_uniformbuf_create_ex(
ubo_size, ubo_data_buf, "OCIO_LutParameters");
free(ubo_data_buf);
}
return true;
shader.shader = GPU_shader_create_from_info(reinterpret_cast<GPUShaderCreateInfo *>(&info));
return (shader.shader != nullptr);
}
/** \} */
@ -438,27 +460,65 @@ static void updateGPUCurveMapping(OCIO_GPUCurveMappping &curvemap,
/* Update uniforms. */
OCIO_GPUCurveMappingParameters data;
for (int i = 0; i < 4; i++) {
data.curve_mapping_range[i] = curve_mapping_settings->range[i];
data.curve_mapping_mintable[i] = curve_mapping_settings->mintable[i];
data.curve_mapping_ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
data.curve_mapping_ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
data.curve_mapping_ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
data.curve_mapping_ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
data.curve_mapping_first_x[i] = curve_mapping_settings->first_x[i];
data.curve_mapping_first_y[i] = curve_mapping_settings->first_y[i];
data.curve_mapping_last_x[i] = curve_mapping_settings->last_x[i];
data.curve_mapping_last_y[i] = curve_mapping_settings->last_y[i];
data.range[i] = curve_mapping_settings->range[i];
data.mintable[i] = curve_mapping_settings->mintable[i];
data.ext_in_x[i] = curve_mapping_settings->ext_in_x[i];
data.ext_in_y[i] = curve_mapping_settings->ext_in_y[i];
data.ext_out_x[i] = curve_mapping_settings->ext_out_x[i];
data.ext_out_y[i] = curve_mapping_settings->ext_out_y[i];
data.first_x[i] = curve_mapping_settings->first_x[i];
data.first_y[i] = curve_mapping_settings->first_y[i];
data.last_x[i] = curve_mapping_settings->last_x[i];
data.last_y[i] = curve_mapping_settings->last_y[i];
}
for (int i = 0; i < 3; i++) {
data.curve_mapping_black[i] = curve_mapping_settings->black[i];
data.curve_mapping_bwmul[i] = curve_mapping_settings->bwmul[i];
data.black[i] = curve_mapping_settings->black[i];
data.bwmul[i] = curve_mapping_settings->bwmul[i];
}
data.curve_mapping_lut_size = curve_mapping_settings->lut_size;
data.curve_mapping_use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
data.lut_size = curve_mapping_settings->lut_size;
data.use_extend_extrapolate = curve_mapping_settings->use_extend_extrapolate;
GPU_uniformbuf_update(curvemap.buffer, &data);
}
static void updateGPUDisplayParameters(OCIO_GPUShader &shader,
float scale,
float exponent,
float dither,
bool use_predivide,
bool use_overlay)
{
bool do_update = false;
if (shader.parameters_buffer == nullptr) {
shader.parameters_buffer = GPU_uniformbuf_create(sizeof(OCIO_GPUParameters));
do_update = true;
}
OCIO_GPUParameters &data = shader.parameters;
if (data.scale != scale) {
data.scale = scale;
do_update = true;
}
if (data.exponent != exponent) {
data.exponent = exponent;
do_update = true;
}
if (data.dither != dither) {
data.dither = dither;
do_update = true;
}
if (data.use_predivide != use_predivide) {
data.use_predivide = use_predivide;
do_update = true;
}
if (data.use_overlay != use_overlay) {
data.use_overlay = use_overlay;
do_update = true;
}
if (do_update) {
GPU_uniformbuf_update(shader.parameters_buffer, &data);
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -609,7 +669,7 @@ bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
/* Update and bind curve mapping data. */
if (curve_mapping_settings) {
updateGPUCurveMapping(curvemap, curve_mapping_settings);
GPU_uniformbuf_bind(curvemap.buffer, shader.ubo_bind);
GPU_uniformbuf_bind(curvemap.buffer, UNIFORMBUF_SLOT_CURVEMAP);
GPU_texture_bind(curvemap.texture, TEXTURE_SLOT_CURVE_MAPPING);
}
@ -623,17 +683,16 @@ bool OCIOImpl::gpuDisplayShaderBind(OCIO_ConstConfigRcPtr *config,
GPU_texture_bind(textures.luts[i].texture, TEXTURE_SLOT_LUTS_OFFSET + i);
}
if (textures.uniforms_buffer) {
GPU_uniformbuf_bind(textures.uniforms_buffer, UNIFORMBUF_SLOT_LUTS);
}
updateGPUDisplayParameters(shader, scale, exponent, dither, use_predivide, use_overlay);
GPU_uniformbuf_bind(shader.parameters_buffer, UNIFORMBUF_SLOT_DISPLAY);
/* TODO(fclem): remove remains of IMM. */
immBindShader(shader.shader);
/* Bind Shader and set uniforms. */
// GPU_shader_bind(shader.shader);
GPU_shader_uniform_float(shader.shader, shader.scale_loc, scale);
GPU_shader_uniform_float(shader.shader, shader.exponent_loc, exponent);
GPU_shader_uniform_float(shader.shader, shader.dither_loc, dither);
GPU_shader_uniform_int(shader.shader, shader.overlay_loc, use_overlay);
GPU_shader_uniform_int(shader.shader, shader.predivide_loc, use_predivide);
return true;
}

View File

@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2022 Blender Foundation. All rights reserved. */
#ifndef GPU_SHADER
# include "GPU_shader_shared_utils.h"
#endif
struct OCIO_GPUCurveMappingParameters {
/* Curve mapping parameters
*
* See documentation for OCIO_CurveMappingSettings to get fields descriptions.
* (this ones pretty much copies stuff from C structure.)
*/
float4 mintable;
float4 range;
float4 ext_in_x;
float4 ext_in_y;
float4 ext_out_x;
float4 ext_out_y;
float4 first_x;
float4 first_y;
float4 last_x;
float4 last_y;
float4 black;
float4 bwmul;
int lut_size;
int use_extend_extrapolate;
int _pad0;
int _pad1;
};
struct OCIO_GPUParameters {
float dither;
float scale;
float exponent;
bool1 use_predivide;
bool1 use_overlay;
int _pad0;
int _pad1;
int _pad2;
};

View File

@ -66,6 +66,8 @@ if(WITH_OPENSUBDIV)
internal/evaluator/evaluator_capi.cc
internal/evaluator/evaluator_impl.cc
internal/evaluator/evaluator_impl.h
internal/evaluator/gl_compute_evaluator.cc
internal/evaluator/gl_compute_evaluator.h
internal/evaluator/patch_map.cc
internal/evaluator/patch_map.h
@ -104,6 +106,8 @@ if(WITH_OPENSUBDIV)
add_definitions(-DNOMINMAX)
add_definitions(-D_USE_MATH_DEFINES)
endif()
data_to_c_simple(internal/evaluator/shaders/glsl_compute_kernel.glsl SRC)
else()
list(APPEND SRC
stub/opensubdiv_stub.cc

View File

@ -20,13 +20,11 @@
#define OPENSUBDIV_EVAL_OUTPUT_GPU_H_
#include "internal/evaluator/eval_output.h"
#include "internal/evaluator/gl_compute_evaluator.h"
#include <opensubdiv/osd/glComputeEvaluator.h>
#include <opensubdiv/osd/glPatchTable.h>
#include <opensubdiv/osd/glVertexBuffer.h>
using OpenSubdiv::Osd::GLComputeEvaluator;
using OpenSubdiv::Osd::GLStencilTableSSBO;
using OpenSubdiv::Osd::GLVertexBuffer;
namespace blender {

View File

@ -0,0 +1,647 @@
//
// Copyright 2015 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#include "gl_compute_evaluator.h"
#include <GL/glew.h>
#include <opensubdiv/far/error.h>
#include <opensubdiv/far/patchDescriptor.h>
#include <opensubdiv/far/stencilTable.h>
#include <opensubdiv/osd/glslPatchShaderSource.h>
#include <cassert>
#include <cmath>
#include <sstream>
#include <string>
#include <vector>
using OpenSubdiv::Far::LimitStencilTable;
using OpenSubdiv::Far::StencilTable;
using OpenSubdiv::Osd::BufferDescriptor;
using OpenSubdiv::Osd::PatchArray;
using OpenSubdiv::Osd::PatchArrayVector;
extern "C" char datatoc_glsl_compute_kernel_glsl[];
namespace blender {
namespace opensubdiv {
template<class T> GLuint createSSBO(std::vector<T> const &src)
{
if (src.empty()) {
return 0;
}
GLuint devicePtr = 0;
#if defined(GL_ARB_direct_state_access)
if (GLEW_ARB_direct_state_access) {
glCreateBuffers(1, &devicePtr);
glNamedBufferData(devicePtr, src.size() * sizeof(T), &src.at(0), GL_STATIC_DRAW);
}
else
#endif
{
GLint prev = 0;
glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &prev);
glGenBuffers(1, &devicePtr);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, devicePtr);
glBufferData(GL_SHADER_STORAGE_BUFFER, src.size() * sizeof(T), &src.at(0), GL_STATIC_DRAW);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, prev);
}
return devicePtr;
}
GLStencilTableSSBO::GLStencilTableSSBO(StencilTable const *stencilTable)
{
_numStencils = stencilTable->GetNumStencils();
if (_numStencils > 0) {
_sizes = createSSBO(stencilTable->GetSizes());
_offsets = createSSBO(stencilTable->GetOffsets());
_indices = createSSBO(stencilTable->GetControlIndices());
_weights = createSSBO(stencilTable->GetWeights());
_duWeights = _dvWeights = 0;
_duuWeights = _duvWeights = _dvvWeights = 0;
}
else {
_sizes = _offsets = _indices = _weights = 0;
_duWeights = _dvWeights = 0;
_duuWeights = _duvWeights = _dvvWeights = 0;
}
}
GLStencilTableSSBO::GLStencilTableSSBO(LimitStencilTable const *limitStencilTable)
{
_numStencils = limitStencilTable->GetNumStencils();
if (_numStencils > 0) {
_sizes = createSSBO(limitStencilTable->GetSizes());
_offsets = createSSBO(limitStencilTable->GetOffsets());
_indices = createSSBO(limitStencilTable->GetControlIndices());
_weights = createSSBO(limitStencilTable->GetWeights());
_duWeights = createSSBO(limitStencilTable->GetDuWeights());
_dvWeights = createSSBO(limitStencilTable->GetDvWeights());
_duuWeights = createSSBO(limitStencilTable->GetDuuWeights());
_duvWeights = createSSBO(limitStencilTable->GetDuvWeights());
_dvvWeights = createSSBO(limitStencilTable->GetDvvWeights());
}
else {
_sizes = _offsets = _indices = _weights = 0;
_duWeights = _dvWeights = 0;
_duuWeights = _duvWeights = _dvvWeights = 0;
}
}
GLStencilTableSSBO::~GLStencilTableSSBO()
{
if (_sizes)
glDeleteBuffers(1, &_sizes);
if (_offsets)
glDeleteBuffers(1, &_offsets);
if (_indices)
glDeleteBuffers(1, &_indices);
if (_weights)
glDeleteBuffers(1, &_weights);
if (_duWeights)
glDeleteBuffers(1, &_duWeights);
if (_dvWeights)
glDeleteBuffers(1, &_dvWeights);
if (_duuWeights)
glDeleteBuffers(1, &_duuWeights);
if (_duvWeights)
glDeleteBuffers(1, &_duvWeights);
if (_dvvWeights)
glDeleteBuffers(1, &_dvvWeights);
}
// ---------------------------------------------------------------------------
GLComputeEvaluator::GLComputeEvaluator() : _workGroupSize(64), _patchArraysSSBO(0)
{
memset(&_stencilKernel, 0, sizeof(_stencilKernel));
memset(&_patchKernel, 0, sizeof(_patchKernel));
}
GLComputeEvaluator::~GLComputeEvaluator()
{
if (_patchArraysSSBO) {
glDeleteBuffers(1, &_patchArraysSSBO);
}
}
static GLuint compileKernel(BufferDescriptor const &srcDesc,
BufferDescriptor const &dstDesc,
BufferDescriptor const &duDesc,
BufferDescriptor const &dvDesc,
BufferDescriptor const &duuDesc,
BufferDescriptor const &duvDesc,
BufferDescriptor const &dvvDesc,
const char *kernelDefine,
int workGroupSize)
{
GLuint program = glCreateProgram();
GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
std::string patchBasisShaderSource =
OpenSubdiv::Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource();
const char *patchBasisShaderSourceDefine = "#define OSD_PATCH_BASIS_GLSL\n";
std::ostringstream defines;
defines << "#define LENGTH " << srcDesc.length << "\n"
<< "#define SRC_STRIDE " << srcDesc.stride << "\n"
<< "#define DST_STRIDE " << dstDesc.stride << "\n"
<< "#define WORK_GROUP_SIZE " << workGroupSize << "\n"
<< kernelDefine << "\n"
<< patchBasisShaderSourceDefine << "\n";
bool deriv1 = (duDesc.length > 0 || dvDesc.length > 0);
bool deriv2 = (duuDesc.length > 0 || duvDesc.length > 0 || dvvDesc.length > 0);
if (deriv1) {
defines << "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n";
}
if (deriv2) {
defines << "#define OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES\n";
}
std::string defineStr = defines.str();
const char *shaderSources[4] = {"#version 430\n", 0, 0, 0};
shaderSources[1] = defineStr.c_str();
shaderSources[2] = patchBasisShaderSource.c_str();
shaderSources[3] = datatoc_glsl_compute_kernel_glsl;
glShaderSource(shader, 4, shaderSources, NULL);
glCompileShader(shader);
glAttachShader(program, shader);
GLint linked = 0;
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &linked);
if (linked == GL_FALSE) {
char buffer[1024];
glGetShaderInfoLog(shader, 1024, NULL, buffer);
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR, buffer);
glGetProgramInfoLog(program, 1024, NULL, buffer);
OpenSubdiv::Far::Error(OpenSubdiv::Far::FAR_RUNTIME_ERROR, buffer);
glDeleteProgram(program);
return 0;
}
glDeleteShader(shader);
return program;
}
bool GLComputeEvaluator::Compile(BufferDescriptor const &srcDesc,
BufferDescriptor const &dstDesc,
BufferDescriptor const &duDesc,
BufferDescriptor const &dvDesc,
BufferDescriptor const &duuDesc,
BufferDescriptor const &duvDesc,
BufferDescriptor const &dvvDesc)
{
// create a stencil kernel
if (!_stencilKernel.Compile(
srcDesc, dstDesc, duDesc, dvDesc, duuDesc, duvDesc, dvvDesc, _workGroupSize)) {
return false;
}
// create a patch kernel
if (!_patchKernel.Compile(
srcDesc, dstDesc, duDesc, dvDesc, duuDesc, duvDesc, dvvDesc, _workGroupSize)) {
return false;
}
// create a patch arrays buffer
if (!_patchArraysSSBO) {
glGenBuffers(1, &_patchArraysSSBO);
}
return true;
}
/* static */
void GLComputeEvaluator::Synchronize(void * /*kernel*/)
{
// XXX: this is currently just for the performance measuring purpose.
// need to be reimplemented by fence and sync.
glFinish();
}
int GLComputeEvaluator::GetDispatchSize(int count) const
{
return (count + _workGroupSize - 1) / _workGroupSize;
}
void GLComputeEvaluator::DispatchCompute(int totalDispatchSize) const
{
int maxWorkGroupCount[2] = {0, 0};
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &maxWorkGroupCount[0]);
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &maxWorkGroupCount[1]);
const GLuint maxResX = static_cast<GLuint>(maxWorkGroupCount[0]);
const int dispatchSize = GetDispatchSize(totalDispatchSize);
GLuint dispatchRX = static_cast<GLuint>(dispatchSize);
GLuint dispatchRY = 1u;
if (dispatchRX > maxResX) {
/* Since there are some limitations with regards to the maximum work group size (could be as
* low as 64k elements per call), we split the number elements into a "2d" number, with the
* final index being computed as `res_x + res_y * max_work_group_size`. Even with a maximum
* work group size of 64k, that still leaves us with roughly `64k * 64k = 4` billion elements
* total, which should be enough. If not, we could also use the 3rd dimension. */
/* TODO(fclem): We could dispatch fewer groups if we compute the prime factorization and
* get the smallest rect fitting the requirements. */
dispatchRX = dispatchRY = std::ceil(std::sqrt(dispatchSize));
/* Avoid a completely empty dispatch line caused by rounding. */
if ((dispatchRX * (dispatchRY - 1)) >= dispatchSize) {
dispatchRY -= 1;
}
}
/* X and Y dimensions may have different limits so the above computation may not be right, but
* even with the standard 64k minimum on all dimensions we still have a lot of room. Therefore,
* we presume it all fits. */
assert(dispatchRY < static_cast<GLuint>(maxWorkGroupCount[1]));
glDispatchCompute(dispatchRX, dispatchRY, 1);
}
bool GLComputeEvaluator::EvalStencils(GLuint srcBuffer,
BufferDescriptor const &srcDesc,
GLuint dstBuffer,
BufferDescriptor const &dstDesc,
GLuint duBuffer,
BufferDescriptor const &duDesc,
GLuint dvBuffer,
BufferDescriptor const &dvDesc,
GLuint sizesBuffer,
GLuint offsetsBuffer,
GLuint indicesBuffer,
GLuint weightsBuffer,
GLuint duWeightsBuffer,
GLuint dvWeightsBuffer,
int start,
int end) const
{
return EvalStencils(srcBuffer,
srcDesc,
dstBuffer,
dstDesc,
duBuffer,
duDesc,
dvBuffer,
dvDesc,
0,
BufferDescriptor(),
0,
BufferDescriptor(),
0,
BufferDescriptor(),
sizesBuffer,
offsetsBuffer,
indicesBuffer,
weightsBuffer,
duWeightsBuffer,
dvWeightsBuffer,
0,
0,
0,
start,
end);
}
bool GLComputeEvaluator::EvalStencils(GLuint srcBuffer,
BufferDescriptor const &srcDesc,
GLuint dstBuffer,
BufferDescriptor const &dstDesc,
GLuint duBuffer,
BufferDescriptor const &duDesc,
GLuint dvBuffer,
BufferDescriptor const &dvDesc,
GLuint duuBuffer,
BufferDescriptor const &duuDesc,
GLuint duvBuffer,
BufferDescriptor const &duvDesc,
GLuint dvvBuffer,
BufferDescriptor const &dvvDesc,
GLuint sizesBuffer,
GLuint offsetsBuffer,
GLuint indicesBuffer,
GLuint weightsBuffer,
GLuint duWeightsBuffer,
GLuint dvWeightsBuffer,
GLuint duuWeightsBuffer,
GLuint duvWeightsBuffer,
GLuint dvvWeightsBuffer,
int start,
int end) const
{
if (!_stencilKernel.program)
return false;
int count = end - start;
if (count <= 0) {
return true;
}
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, srcBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, dstBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, duBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, dvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, duuBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, duvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 12, dvvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, sizesBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, offsetsBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, indicesBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, weightsBuffer);
if (duWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 8, duWeightsBuffer);
if (dvWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 9, dvWeightsBuffer);
if (duuWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 13, duuWeightsBuffer);
if (duvWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 14, duvWeightsBuffer);
if (dvvWeightsBuffer)
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 15, dvvWeightsBuffer);
glUseProgram(_stencilKernel.program);
glUniform1i(_stencilKernel.uniformStart, start);
glUniform1i(_stencilKernel.uniformEnd, end);
glUniform1i(_stencilKernel.uniformSrcOffset, srcDesc.offset);
glUniform1i(_stencilKernel.uniformDstOffset, dstDesc.offset);
if (_stencilKernel.uniformDuDesc > 0) {
glUniform3i(_stencilKernel.uniformDuDesc, duDesc.offset, duDesc.length, duDesc.stride);
}
if (_stencilKernel.uniformDvDesc > 0) {
glUniform3i(_stencilKernel.uniformDvDesc, dvDesc.offset, dvDesc.length, dvDesc.stride);
}
if (_stencilKernel.uniformDuuDesc > 0) {
glUniform3i(_stencilKernel.uniformDuuDesc, duuDesc.offset, duuDesc.length, duuDesc.stride);
}
if (_stencilKernel.uniformDuvDesc > 0) {
glUniform3i(_stencilKernel.uniformDuvDesc, duvDesc.offset, duvDesc.length, duvDesc.stride);
}
if (_stencilKernel.uniformDvvDesc > 0) {
glUniform3i(_stencilKernel.uniformDvvDesc, dvvDesc.offset, dvvDesc.length, dvvDesc.stride);
}
DispatchCompute(count);
glUseProgram(0);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
for (int i = 0; i < 16; ++i) {
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, i, 0);
}
return true;
}
bool GLComputeEvaluator::EvalPatches(GLuint srcBuffer,
BufferDescriptor const &srcDesc,
GLuint dstBuffer,
BufferDescriptor const &dstDesc,
GLuint duBuffer,
BufferDescriptor const &duDesc,
GLuint dvBuffer,
BufferDescriptor const &dvDesc,
int numPatchCoords,
GLuint patchCoordsBuffer,
const PatchArrayVector &patchArrays,
GLuint patchIndexBuffer,
GLuint patchParamsBuffer) const
{
return EvalPatches(srcBuffer,
srcDesc,
dstBuffer,
dstDesc,
duBuffer,
duDesc,
dvBuffer,
dvDesc,
0,
BufferDescriptor(),
0,
BufferDescriptor(),
0,
BufferDescriptor(),
numPatchCoords,
patchCoordsBuffer,
patchArrays,
patchIndexBuffer,
patchParamsBuffer);
}
bool GLComputeEvaluator::EvalPatches(GLuint srcBuffer,
BufferDescriptor const &srcDesc,
GLuint dstBuffer,
BufferDescriptor const &dstDesc,
GLuint duBuffer,
BufferDescriptor const &duDesc,
GLuint dvBuffer,
BufferDescriptor const &dvDesc,
GLuint duuBuffer,
BufferDescriptor const &duuDesc,
GLuint duvBuffer,
BufferDescriptor const &duvDesc,
GLuint dvvBuffer,
BufferDescriptor const &dvvDesc,
int numPatchCoords,
GLuint patchCoordsBuffer,
const PatchArrayVector &patchArrays,
GLuint patchIndexBuffer,
GLuint patchParamsBuffer) const
{
if (!_patchKernel.program)
return false;
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, srcBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, dstBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, duBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, dvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, duuBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, duvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 12, dvvBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, patchCoordsBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, patchIndexBuffer);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 7, patchParamsBuffer);
glUseProgram(_patchKernel.program);
glUniform1i(_patchKernel.uniformSrcOffset, srcDesc.offset);
glUniform1i(_patchKernel.uniformDstOffset, dstDesc.offset);
int patchArraySize = sizeof(PatchArray);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, _patchArraysSSBO);
glBufferData(
GL_SHADER_STORAGE_BUFFER, patchArrays.size() * patchArraySize, NULL, GL_STATIC_DRAW);
for (int i = 0; i < (int)patchArrays.size(); ++i) {
glBufferSubData(
GL_SHADER_STORAGE_BUFFER, i * patchArraySize, sizeof(PatchArray), &patchArrays[i]);
}
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, _patchArraysSSBO);
if (_patchKernel.uniformDuDesc > 0) {
glUniform3i(_patchKernel.uniformDuDesc, duDesc.offset, duDesc.length, duDesc.stride);
}
if (_patchKernel.uniformDvDesc > 0) {
glUniform3i(_patchKernel.uniformDvDesc, dvDesc.offset, dvDesc.length, dvDesc.stride);
}
if (_patchKernel.uniformDuuDesc > 0) {
glUniform3i(_patchKernel.uniformDuuDesc, duuDesc.offset, duuDesc.length, duuDesc.stride);
}
if (_patchKernel.uniformDuvDesc > 0) {
glUniform3i(_patchKernel.uniformDuvDesc, duvDesc.offset, duvDesc.length, duvDesc.stride);
}
if (_patchKernel.uniformDvvDesc > 0) {
glUniform3i(_patchKernel.uniformDvvDesc, dvvDesc.offset, dvvDesc.length, dvvDesc.stride);
}
DispatchCompute(numPatchCoords);
glUseProgram(0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 4, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 5, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 6, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 10, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 11, 0);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 12, 0);
return true;
}
// ---------------------------------------------------------------------------
GLComputeEvaluator::_StencilKernel::_StencilKernel() : program(0)
{
}
GLComputeEvaluator::_StencilKernel::~_StencilKernel()
{
if (program) {
glDeleteProgram(program);
}
}
bool GLComputeEvaluator::_StencilKernel::Compile(BufferDescriptor const &srcDesc,
BufferDescriptor const &dstDesc,
BufferDescriptor const &duDesc,
BufferDescriptor const &dvDesc,
BufferDescriptor const &duuDesc,
BufferDescriptor const &duvDesc,
BufferDescriptor const &dvvDesc,
int workGroupSize)
{
// create stencil kernel
if (program) {
glDeleteProgram(program);
}
const char *kernelDefine = "#define OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_STENCILS\n";
program = compileKernel(
srcDesc, dstDesc, duDesc, dvDesc, duuDesc, duvDesc, dvvDesc, kernelDefine, workGroupSize);
if (program == 0)
return false;
// cache uniform locations (TODO: use uniform block)
uniformStart = glGetUniformLocation(program, "batchStart");
uniformEnd = glGetUniformLocation(program, "batchEnd");
uniformSrcOffset = glGetUniformLocation(program, "srcOffset");
uniformDstOffset = glGetUniformLocation(program, "dstOffset");
uniformDuDesc = glGetUniformLocation(program, "duDesc");
uniformDvDesc = glGetUniformLocation(program, "dvDesc");
uniformDuuDesc = glGetUniformLocation(program, "duuDesc");
uniformDuvDesc = glGetUniformLocation(program, "duvDesc");
uniformDvvDesc = glGetUniformLocation(program, "dvvDesc");
return true;
}
// ---------------------------------------------------------------------------
GLComputeEvaluator::_PatchKernel::_PatchKernel() : program(0)
{
}
GLComputeEvaluator::_PatchKernel::~_PatchKernel()
{
if (program) {
glDeleteProgram(program);
}
}
bool GLComputeEvaluator::_PatchKernel::Compile(BufferDescriptor const &srcDesc,
BufferDescriptor const &dstDesc,
BufferDescriptor const &duDesc,
BufferDescriptor const &dvDesc,
BufferDescriptor const &duuDesc,
BufferDescriptor const &duvDesc,
BufferDescriptor const &dvvDesc,
int workGroupSize)
{
// create stencil kernel
if (program) {
glDeleteProgram(program);
}
const char *kernelDefine = "#define OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_PATCHES\n";
program = compileKernel(
srcDesc, dstDesc, duDesc, dvDesc, duuDesc, duvDesc, dvvDesc, kernelDefine, workGroupSize);
if (program == 0)
return false;
// cache uniform locations
uniformSrcOffset = glGetUniformLocation(program, "srcOffset");
uniformDstOffset = glGetUniformLocation(program, "dstOffset");
uniformPatchArray = glGetUniformLocation(program, "patchArray");
uniformDuDesc = glGetUniformLocation(program, "duDesc");
uniformDvDesc = glGetUniformLocation(program, "dvDesc");
uniformDuuDesc = glGetUniformLocation(program, "duuDesc");
uniformDuvDesc = glGetUniformLocation(program, "duvDesc");
uniformDvvDesc = glGetUniformLocation(program, "dvvDesc");
return true;
}
} // namespace opensubdiv
} // namespace blender

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,316 @@
//
// Copyright 2013 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
//------------------------------------------------------------------------------
layout(local_size_x=WORK_GROUP_SIZE, local_size_y=1, local_size_z=1) in;
layout(std430) buffer;
// source and destination buffers
uniform int srcOffset = 0;
uniform int dstOffset = 0;
layout(binding=0) buffer src_buffer { float srcVertexBuffer[]; };
layout(binding=1) buffer dst_buffer { float dstVertexBuffer[]; };
// derivative buffers (if needed)
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES)
uniform ivec3 duDesc;
uniform ivec3 dvDesc;
layout(binding=2) buffer du_buffer { float duBuffer[]; };
layout(binding=3) buffer dv_buffer { float dvBuffer[]; };
#endif
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES)
uniform ivec3 duuDesc;
uniform ivec3 duvDesc;
uniform ivec3 dvvDesc;
layout(binding=10) buffer duu_buffer { float duuBuffer[]; };
layout(binding=11) buffer duv_buffer { float duvBuffer[]; };
layout(binding=12) buffer dvv_buffer { float dvvBuffer[]; };
#endif
// stencil buffers
#if defined(OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_STENCILS)
uniform int batchStart = 0;
uniform int batchEnd = 0;
layout(binding=4) buffer stencilSizes { int _sizes[]; };
layout(binding=5) buffer stencilOffsets { int _offsets[]; };
layout(binding=6) buffer stencilIndices { int _indices[]; };
layout(binding=7) buffer stencilWeights { float _weights[]; };
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES)
layout(binding=8) buffer stencilDuWeights { float _duWeights[]; };
layout(binding=9) buffer stencilDvWeights { float _dvWeights[]; };
#endif
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES)
layout(binding=13) buffer stencilDuuWeights { float _duuWeights[]; };
layout(binding=14) buffer stencilDuvWeights { float _duvWeights[]; };
layout(binding=15) buffer stencilDvvWeights { float _dvvWeights[]; };
#endif
uint getGlobalInvocationIndex()
{
uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x;
return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row;
}
#endif
// patch buffers
#if defined(OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_PATCHES)
layout(binding=4) buffer patchArray_buffer { OsdPatchArray patchArrayBuffer[]; };
layout(binding=5) buffer patchCoord_buffer { OsdPatchCoord patchCoords[]; };
layout(binding=6) buffer patchIndex_buffer { int patchIndexBuffer[]; };
layout(binding=7) buffer patchParam_buffer { OsdPatchParam patchParamBuffer[]; };
OsdPatchCoord GetPatchCoord(int coordIndex)
{
return patchCoords[coordIndex];
}
OsdPatchArray GetPatchArray(int arrayIndex)
{
return patchArrayBuffer[arrayIndex];
}
OsdPatchParam GetPatchParam(int patchIndex)
{
return patchParamBuffer[patchIndex];
}
#endif
//------------------------------------------------------------------------------
struct Vertex {
float vertexData[LENGTH];
};
void clear(out Vertex v) {
for (int i = 0; i < LENGTH; ++i) {
v.vertexData[i] = 0;
}
}
Vertex readVertex(int index) {
Vertex v;
int vertexIndex = srcOffset + index * SRC_STRIDE;
for (int i = 0; i < LENGTH; ++i) {
v.vertexData[i] = srcVertexBuffer[vertexIndex + i];
}
return v;
}
void writeVertex(int index, Vertex v) {
int vertexIndex = dstOffset + index * DST_STRIDE;
for (int i = 0; i < LENGTH; ++i) {
dstVertexBuffer[vertexIndex + i] = v.vertexData[i];
}
}
void addWithWeight(inout Vertex v, const Vertex src, float weight) {
for (int i = 0; i < LENGTH; ++i) {
v.vertexData[i] += weight * src.vertexData[i];
}
}
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES)
void writeDu(int index, Vertex du) {
int duIndex = duDesc.x + index * duDesc.z;
for (int i = 0; i < LENGTH; ++i) {
duBuffer[duIndex + i] = du.vertexData[i];
}
}
void writeDv(int index, Vertex dv) {
int dvIndex = dvDesc.x + index * dvDesc.z;
for (int i = 0; i < LENGTH; ++i) {
dvBuffer[dvIndex + i] = dv.vertexData[i];
}
}
#endif
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES)
void writeDuu(int index, Vertex duu) {
int duuIndex = duuDesc.x + index * duuDesc.z;
for (int i = 0; i < LENGTH; ++i) {
duuBuffer[duuIndex + i] = duu.vertexData[i];
}
}
void writeDuv(int index, Vertex duv) {
int duvIndex = duvDesc.x + index * duvDesc.z;
for (int i = 0; i < LENGTH; ++i) {
duvBuffer[duvIndex + i] = duv.vertexData[i];
}
}
void writeDvv(int index, Vertex dvv) {
int dvvIndex = dvvDesc.x + index * dvvDesc.z;
for (int i = 0; i < LENGTH; ++i) {
dvvBuffer[dvvIndex + i] = dvv.vertexData[i];
}
}
#endif
//------------------------------------------------------------------------------
#if defined(OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_STENCILS)
void main() {
int current = int(getGlobalInvocationIndex()) + batchStart;
if (current>=batchEnd) {
return;
}
Vertex dst;
clear(dst);
int offset = _offsets[current],
size = _sizes[current];
for (int stencil = 0; stencil < size; ++stencil) {
int vindex = offset + stencil;
addWithWeight(
dst, readVertex(_indices[vindex]), _weights[vindex]);
}
writeVertex(current, dst);
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES)
Vertex du, dv;
clear(du);
clear(dv);
for (int i=0; i<size; ++i) {
// expects the compiler optimizes readVertex out here.
Vertex src = readVertex(_indices[offset+i]);
addWithWeight(du, src, _duWeights[offset+i]);
addWithWeight(dv, src, _dvWeights[offset+i]);
}
if (duDesc.y > 0) { // length
writeDu(current, du);
}
if (dvDesc.y > 0) {
writeDv(current, dv);
}
#endif
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES)
Vertex duu, duv, dvv;
clear(duu);
clear(duv);
clear(dvv);
for (int i=0; i<size; ++i) {
// expects the compiler optimizes readVertex out here.
Vertex src = readVertex(_indices[offset+i]);
addWithWeight(duu, src, _duuWeights[offset+i]);
addWithWeight(duv, src, _duvWeights[offset+i]);
addWithWeight(dvv, src, _dvvWeights[offset+i]);
}
if (duuDesc.y > 0) { // length
writeDuu(current, duu);
}
if (duvDesc.y > 0) {
writeDuv(current, duv);
}
if (dvvDesc.y > 0) {
writeDvv(current, dvv);
}
#endif
}
#endif
//------------------------------------------------------------------------------
#if defined(OPENSUBDIV_GLSL_COMPUTE_KERNEL_EVAL_PATCHES)
// PERFORMANCE: stride could be constant, but not as significant as length
void main() {
int current = int(gl_GlobalInvocationID.x);
OsdPatchCoord coord = GetPatchCoord(current);
OsdPatchArray array = GetPatchArray(coord.arrayIndex);
OsdPatchParam param = GetPatchParam(coord.patchIndex);
int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc;
float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
int nPoints = OsdEvaluatePatchBasis(patchType, param,
coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv);
Vertex dst, du, dv, duu, duv, dvv;
clear(dst);
clear(du);
clear(dv);
clear(duu);
clear(duv);
clear(dvv);
int indexBase = array.indexBase + array.stride *
(coord.patchIndex - array.primitiveIdBase);
for (int cv = 0; cv < nPoints; ++cv) {
int index = patchIndexBuffer[indexBase + cv];
addWithWeight(dst, readVertex(index), wP[cv]);
addWithWeight(du, readVertex(index), wDu[cv]);
addWithWeight(dv, readVertex(index), wDv[cv]);
addWithWeight(duu, readVertex(index), wDuu[cv]);
addWithWeight(duv, readVertex(index), wDuv[cv]);
addWithWeight(dvv, readVertex(index), wDvv[cv]);
}
writeVertex(current, dst);
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES)
if (duDesc.y > 0) { // length
writeDu(current, du);
}
if (dvDesc.y > 0) {
writeDv(current, dv);
}
#endif
#if defined(OPENSUBDIV_GLSL_COMPUTE_USE_2ND_DERIVATIVES)
if (duuDesc.y > 0) { // length
writeDuu(current, duu);
}
if (duvDesc.y > 0) { // length
writeDuv(current, duv);
}
if (dvvDesc.y > 0) {
writeDvv(current, dvv);
}
#endif
}
#endif

View File

@ -9,7 +9,7 @@
#
# See ocio-license.txt for details.
ocio_profile_version: 1
ocio_profile_version: 2
search_path: "luts:filmic"
strictparsing: true
@ -100,8 +100,7 @@ colorspaces:
from_reference: !<GroupTransform>
children:
- !<FileTransform> {src: srgb_to_xyz.spimtx, interpolation: linear}
- !<FileTransform> {src: xyz_D65_to_E.spimtx, interpolation: linear}
- !<FileTransform> {src: xyz_to_aces.spimtx, interpolation: linear}
- !<BuiltinTransform> {style: "UTILITY - ACES-AP0_to_CIE-XYZ-D65_BFD", direction: inverse}
- !<ColorSpace>
name: nuke_rec709

@ -1 +1 @@
Subproject commit e1d44bf37501eb19a057777bd0b0ba4484773531
Subproject commit 089aef61debbece2baff6516e33fc7491629b1d0

View File

@ -2,9 +2,11 @@
#pragma once
#include "DNA_curves_types.h"
/** \file
* \ingroup bke
* \brief Low-level operations for curves.
* \brief Low-level operations for curves that cannot be defined in the C++ header yet.
*/
#ifdef __cplusplus
@ -23,14 +25,10 @@ void *BKE_curves_add(struct Main *bmain, const char *name);
struct BoundBox *BKE_curves_boundbox_get(struct Object *ob);
void BKE_curves_update_customdata_pointers(struct Curves *curves);
bool BKE_curves_customdata_required(struct Curves *curves, struct CustomDataLayer *layer);
/* Depsgraph */
struct Curves *BKE_curves_new_for_eval(const struct Curves *curves_src,
int totpoint,
int totcurve);
struct Curves *BKE_curves_copy_for_eval(struct Curves *curves_src, bool reference);
void BKE_curves_data_update(struct Depsgraph *depsgraph,

View File

@ -0,0 +1,156 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "BKE_curves.h"
/** \file
* \ingroup bke
* \brief Low-level operations for curves.
*/
#include <mutex>
#include "BLI_float4x4.hh"
#include "BLI_index_mask.hh"
#include "BLI_math_vec_types.hh"
#include "BLI_span.hh"
#include "BLI_task.hh"
#include "BLI_vector.hh"
#include "BLI_virtual_array.hh"
#include "BKE_attribute_access.hh"
#include "FN_generic_virtual_array.hh"
namespace blender::bke {
/**
* Contains derived data, caches, and other information not saved in files, besides a few pointers
* to arrays that are kept in the non-runtime struct to avoid dereferencing this whenever they are
* accessed.
*/
class CurvesGeometryRuntime {
public:
/** Cache of evaluated positions. */
mutable Vector<float3> evaluated_position_cache;
mutable std::mutex position_cache_mutex;
mutable bool position_cache_dirty = true;
/** Direction of the spline at each evaluated point. */
mutable Vector<float3> evaluated_tangents_cache;
mutable std::mutex tangent_cache_mutex;
mutable bool tangent_cache_dirty = true;
/** Normal direction vectors for each evaluated point. */
mutable Vector<float3> evaluated_normals_cache;
mutable std::mutex normal_cache_mutex;
mutable bool normal_cache_dirty = true;
};
/**
* A C++ class that wraps the DNA struct for better encapsulation and ease of use. It inherits
* directly from the struct rather than storing a pointer to avoid more complicated ownership
* handling.
*/
class CurvesGeometry : public ::CurvesGeometry {
public:
CurvesGeometry();
/**
* Create curves with the given size. Only the position attribute is created, along with the
* offsets.
*/
CurvesGeometry(int point_size, int curve_size);
CurvesGeometry(const CurvesGeometry &other);
CurvesGeometry &operator=(const CurvesGeometry &other);
~CurvesGeometry();
static CurvesGeometry &wrap(::CurvesGeometry &dna_struct)
{
CurvesGeometry *geometry = reinterpret_cast<CurvesGeometry *>(&dna_struct);
return *geometry;
}
static const CurvesGeometry &wrap(const ::CurvesGeometry &dna_struct)
{
const CurvesGeometry *geometry = reinterpret_cast<const CurvesGeometry *>(&dna_struct);
return *geometry;
}
/* --------------------------------------------------------------------
* Accessors.
*/
int points_size() const;
int curves_size() const;
/**
* The total number of points in the evaluated poly curve.
* This can depend on the resolution attribute if it exists.
*/
int evaluated_points_size() const;
/**
* Access a range of indices of point data for a specific curve.
*/
IndexRange range_for_curve(int index) const;
/** The type (#CurveType) of each curve, or potentially a single if all are the same type. */
VArray<int8_t> curve_types() const;
/** Mutable access to curve types. Call #tag_topology_changed after changing any type. */
MutableSpan<int8_t> curve_types();
MutableSpan<float3> positions();
Span<float3> positions() const;
/**
* Calculate the largest and smallest position values, only including control points
* (rather than evaluated points). The existing values of `min` and `max` are taken into account.
*
* \return Whether there are any points. If the curve is empty, the inputs will be unaffected.
*/
bool bounds_min_max(float3 &min, float3 &max) const;
/**
* The index of the first point in every curve. The size of this span is one larger than the
* number of curves. Consider using #range_for_curve rather than using the offsets directly.
*/
Span<int> offsets() const;
MutableSpan<int> offsets();
/* --------------------------------------------------------------------
* Operations.
*/
/**
* Change the number of elements. New values for existing attributes should be properly
* initialized afterwards.
*/
void resize(int point_size, int curve_size);
/** Call after deforming the position attribute. */
void tag_positions_changed();
/**
* Call after any operation that changes the topology
* (number of points, evaluated points, or the total count).
*/
void tag_topology_changed();
/** Call after changing the "tilt" or "up" attributes. */
void tag_normals_changed();
void translate(const float3 &translation);
void transform(const float4x4 &matrix);
void update_customdata_pointers();
/* --------------------------------------------------------------------
* Attributes.
*/
fn::GVArray adapt_domain(const fn::GVArray &varray,
AttributeDomain from,
AttributeDomain to) const;
};
Curves *curves_new_nomain(int point_size, int curves_size);
} // namespace blender::bke

View File

@ -90,7 +90,6 @@ typedef enum VolumeGridType {
VOLUME_GRID_INT,
VOLUME_GRID_INT64,
VOLUME_GRID_MASK,
VOLUME_GRID_STRING,
VOLUME_GRID_VECTOR_FLOAT,
VOLUME_GRID_VECTOR_DOUBLE,
VOLUME_GRID_VECTOR_INT,
@ -204,8 +203,6 @@ auto BKE_volume_grid_type_operation(const VolumeGridType grid_type, OpType &&op)
return op.template operator()<openvdb::Vec3IGrid>();
case VOLUME_GRID_VECTOR_DOUBLE:
return op.template operator()<openvdb::Vec3dGrid>();
case VOLUME_GRID_STRING:
return op.template operator()<openvdb::StringGrid>();
case VOLUME_GRID_MASK:
return op.template operator()<openvdb::MaskGrid>();
case VOLUME_GRID_POINTS:

View File

@ -103,6 +103,7 @@ set(SRC
intern/cryptomatte.cc
intern/curve.cc
intern/curves.cc
intern/curves_geometry.cc
intern/curve_bevel.c
intern/curve_convert.c
intern/curve_decimate.c
@ -341,6 +342,7 @@ set(SRC
BKE_cryptomatte.hh
BKE_curve.h
BKE_curves.h
BKE_curves.hh
BKE_curve_to_mesh.hh
BKE_curveprofile.h
BKE_customdata.h

View File

@ -207,6 +207,16 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider {
void foreach_domain(const FunctionRef<void(AttributeDomain)> callback) const final;
};
template<typename T> GVArray make_array_read_attribute(const void *data, const int domain_size)
{
return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
}
template<typename T> GVMutableArray make_array_write_attribute(void *data, const int domain_size)
{
return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
}
/**
* This provider is used to provide access to builtin attributes. It supports making internal types
* available as different types. For example, the vertex position attribute is stored as part of

View File

@ -147,7 +147,7 @@ static void brush_make_local(Main *bmain, ID *id, const int flags)
/* NOTE: assert below ensures that the comment above is valid, and that that exception is
* acceptable for the time being. */
BKE_lib_id_make_local(bmain, &brush->clone.image->id, 0);
BLI_assert(brush->clone.image->id.lib == NULL && brush->clone.image->id.newid == NULL);
BLI_assert(!ID_IS_LINKED(brush->clone.image) && brush->clone.image->id.newid == NULL);
}
if (force_local) {

View File

@ -550,9 +550,8 @@ void BKE_camera_view_frame(const Scene *scene, const Camera *camera, float r_vec
#define CAMERA_VIEWFRAME_NUM_PLANES 4
typedef struct CameraViewFrameData {
float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes */
float normal_tx[CAMERA_VIEWFRAME_NUM_PLANES][3];
float dist_vals_sq[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance squared (signed) */
float plane_tx[CAMERA_VIEWFRAME_NUM_PLANES][4]; /* 4 planes normalized */
float dist_vals[CAMERA_VIEWFRAME_NUM_PLANES]; /* distance (signed) */
unsigned int tot;
/* Ortho camera only. */
@ -569,8 +568,8 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data)
CameraViewFrameData *data = (CameraViewFrameData *)user_data;
for (uint i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
const float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]);
CLAMP_MAX(data->dist_vals_sq[i], nd);
const float nd = plane_point_side_v3(data->plane_tx[i], co);
CLAMP_MAX(data->dist_vals[i], nd);
}
if (data->is_ortho) {
@ -625,10 +624,11 @@ static void camera_frame_fit_data_init(const Scene *scene,
/* Rotate planes and get normals from them */
for (uint i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
mul_m4_v4(camera_rotmat_transposed_inversed, data->plane_tx[i]);
normalize_v3_v3(data->normal_tx[i], data->plane_tx[i]);
/* Normalize. */
data->plane_tx[i][3] /= normalize_v3(data->plane_tx[i]);
}
copy_v4_fl(data->dist_vals_sq, FLT_MAX);
copy_v4_fl(data->dist_vals, FLT_MAX);
data->tot = 0;
data->is_ortho = params->is_ortho;
if (params->is_ortho) {
@ -653,14 +653,9 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
const float *cam_axis_x = data->camera_rotmat[0];
const float *cam_axis_y = data->camera_rotmat[1];
const float *cam_axis_z = data->camera_rotmat[2];
float dists[CAMERA_VIEWFRAME_NUM_PLANES];
const float *dists = data->dist_vals;
float scale_diff;
/* apply the dist-from-plane's to the transformed plane points */
for (int i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
dists[i] = sqrtf_signed(data->dist_vals_sq[i]);
}
if ((dists[0] + dists[2]) > (dists[1] + dists[3])) {
scale_diff = (dists[1] + dists[3]) *
(BLI_rctf_size_x(&params->viewplane) / BLI_rctf_size_y(&params->viewplane));
@ -687,8 +682,8 @@ static bool camera_frame_fit_calc_from_data(CameraParams *params,
/* apply the dist-from-plane's to the transformed plane points */
for (int i = 0; i < CAMERA_VIEWFRAME_NUM_PLANES; i++) {
float co[3];
mul_v3_v3fl(co, data->normal_tx[i], sqrtf_signed(data->dist_vals_sq[i]));
plane_from_point_normal_v3(plane_tx[i], co, data->normal_tx[i]);
mul_v3_v3fl(co, data->plane_tx[i], data->dist_vals[i]);
plane_from_point_normal_v3(plane_tx[i], co, data->plane_tx[i]);
}
if ((!isect_plane_plane_v3(plane_tx[0], plane_tx[2], plane_isect_1, plane_isect_1_no)) ||

View File

@ -14,16 +14,18 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "BLI_bounds.hh"
#include "BLI_index_range.hh"
#include "BLI_listbase.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.hh"
#include "BLI_rand.hh"
#include "BLI_span.hh"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_anim_data.h"
#include "BKE_curves.h"
#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_idtype.h"
@ -44,11 +46,12 @@ using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
using blender::RandomNumberGenerator;
using blender::Span;
static const char *ATTR_POSITION = "position";
static const char *ATTR_RADIUS = "radius";
static void curves_random(Curves *curves);
static void update_custom_data_pointers(Curves &curves);
static void curves_init_data(ID *id)
{
@ -57,50 +60,38 @@ static void curves_init_data(ID *id)
MEMCPY_STRUCT_AFTER(curves, DNA_struct_default_get(Curves), id);
CustomData_reset(&curves->geometry.point_data);
CustomData_reset(&curves->geometry.curve_data);
CustomData_add_layer_named(&curves->geometry.point_data,
CD_PROP_FLOAT3,
CD_CALLOC,
nullptr,
curves->geometry.point_size,
ATTR_POSITION);
CustomData_add_layer_named(&curves->geometry.point_data,
CD_PROP_FLOAT,
CD_CALLOC,
nullptr,
curves->geometry.point_size,
ATTR_RADIUS);
BKE_curves_update_customdata_pointers(curves);
new (&curves->geometry) blender::bke::CurvesGeometry();
curves_random(curves);
}
static void curves_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, const int flag)
{
using namespace blender;
Curves *curves_dst = (Curves *)id_dst;
const Curves *curves_src = (const Curves *)id_src;
curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat));
curves_dst->geometry.point_size = curves_src->geometry.point_size;
curves_dst->geometry.curve_size = curves_src->geometry.curve_size;
const bke::CurvesGeometry &src = bke::CurvesGeometry::wrap(curves_src->geometry);
bke::CurvesGeometry &dst = bke::CurvesGeometry::wrap(curves_dst->geometry);
/* We need special handling here because the generic ID management code has already done a
* shallow copy from the source to the destination, and because the copy-on-write functionality
* isn't supported more generically yet. */
dst.point_size = src.point_size;
dst.curve_size = src.curve_size;
const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE;
CustomData_copy(&curves_src->geometry.point_data,
&curves_dst->geometry.point_data,
CD_MASK_ALL,
alloc_type,
curves_dst->geometry.point_size);
CustomData_copy(&curves_src->geometry.curve_data,
&curves_dst->geometry.curve_data,
CD_MASK_ALL,
alloc_type,
curves_dst->geometry.curve_size);
BKE_curves_update_customdata_pointers(curves_dst);
CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, alloc_type, dst.point_size);
CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, alloc_type, dst.curve_size);
curves_dst->geometry.offsets = static_cast<int *>(MEM_dupallocN(curves_src->geometry.offsets));
dst.curve_offsets = static_cast<int *>(MEM_dupallocN(src.curve_offsets));
dst.runtime = MEM_new<bke::CurvesGeometryRuntime>(__func__);
dst.update_customdata_pointers();
curves_dst->batch_cache = nullptr;
}
@ -110,13 +101,10 @@ static void curves_free_data(ID *id)
Curves *curves = (Curves *)id;
BKE_animdata_free(&curves->id, false);
blender::bke::CurvesGeometry::wrap(curves->geometry).~CurvesGeometry();
BKE_curves_batch_cache_free(curves);
CustomData_free(&curves->geometry.point_data, curves->geometry.point_size);
CustomData_free(&curves->geometry.curve_data, curves->geometry.curve_size);
MEM_SAFE_FREE(curves->geometry.offsets);
MEM_SAFE_FREE(curves->mat);
}
@ -157,7 +145,7 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre
CD_MASK_ALL,
&curves->id);
BLO_write_int32_array(writer, curves->geometry.curve_size + 1, curves->geometry.offsets);
BLO_write_int32_array(writer, curves->geometry.curve_size + 1, curves->geometry.curve_offsets);
BLO_write_pointer_array(writer, curves->totcol, curves->mat);
if (curves->adt) {
@ -182,9 +170,11 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id)
/* Geometry */
CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_size);
CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_size);
BKE_curves_update_customdata_pointers(curves);
update_custom_data_pointers(*curves);
BLO_read_int32_array(reader, curves->geometry.curve_size + 1, &curves->geometry.offsets);
BLO_read_int32_array(reader, curves->geometry.curve_size + 1, &curves->geometry.curve_offsets);
curves->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
/* Materials */
BLO_read_pointer_array(reader, (void **)&curves->mat);
@ -236,34 +226,33 @@ IDTypeInfo IDType_ID_CV = {
/*lib_override_apply_post */ nullptr,
};
static void update_custom_data_pointers(Curves &curves)
{
blender::bke::CurvesGeometry::wrap(curves.geometry).update_customdata_pointers();
}
static void curves_random(Curves *curves)
{
CurvesGeometry &geometry = curves->geometry;
const int numpoints = 8;
geometry.curve_size = 500;
blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry);
geometry = blender::bke::CurvesGeometry(500 * numpoints, 500);
geometry.curve_size = 500;
geometry.point_size = geometry.curve_size * numpoints;
MutableSpan<int> offsets = geometry.offsets();
MutableSpan<float3> positions = geometry.positions();
curves->geometry.offsets = (int *)MEM_calloc_arrayN(
curves->geometry.curve_size + 1, sizeof(int), __func__);
CustomData_realloc(&geometry.point_data, geometry.point_size);
CustomData_realloc(&geometry.curve_data, geometry.curve_size);
BKE_curves_update_customdata_pointers(curves);
MutableSpan<int> offsets{geometry.offsets, geometry.curve_size + 1};
MutableSpan<float3> positions{(float3 *)geometry.position, geometry.point_size};
MutableSpan<float> radii{geometry.radius, geometry.point_size};
float *radius_data = (float *)CustomData_add_layer_named(
&geometry.point_data, CD_PROP_FLOAT, CD_DEFAULT, nullptr, geometry.point_size, "radius");
MutableSpan<float> radii{radius_data, geometry.points_size()};
for (const int i : offsets.index_range()) {
geometry.offsets[i] = numpoints * i;
offsets[i] = numpoints * i;
}
RandomNumberGenerator rng;
for (int i = 0; i < geometry.curve_size; i++) {
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);
const IndexRange curve_range = geometry.range_for_curve(i);
MutableSpan<float3> curve_positions = positions.slice(curve_range);
MutableSpan<float> curve_radii = radii.slice(curve_range);
@ -304,18 +293,13 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
float min[3], max[3];
INIT_MINMAX(min, max);
blender::bke::CurvesGeometry &geometry = blender::bke::CurvesGeometry::wrap(curves->geometry);
float(*curves_co)[3] = curves->geometry.position;
float *curves_radius = curves->geometry.radius;
for (int a = 0; a < curves->geometry.point_size; a++) {
float *co = curves_co[a];
float radius = (curves_radius) ? curves_radius[a] : 0.0f;
const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius};
const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius};
DO_MIN(co_min, min);
DO_MAX(co_max, max);
float3 min(FLT_MAX);
float3 max(-FLT_MAX);
if (!geometry.bounds_min_max(min, max)) {
min = float3(-1);
max = float3(1);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
@ -324,46 +308,11 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
return ob->runtime.bb;
}
void BKE_curves_update_customdata_pointers(Curves *curves)
{
curves->geometry.position = (float(*)[3])CustomData_get_layer_named(
&curves->geometry.point_data, CD_PROP_FLOAT3, ATTR_POSITION);
curves->geometry.radius = (float *)CustomData_get_layer_named(
&curves->geometry.point_data, CD_PROP_FLOAT, ATTR_RADIUS);
}
bool BKE_curves_customdata_required(Curves *UNUSED(curves), CustomDataLayer *layer)
{
return layer->type == CD_PROP_FLOAT3 && STREQ(layer->name, ATTR_POSITION);
}
/* Dependency Graph */
Curves *BKE_curves_new_for_eval(const Curves *curves_src, int totpoint, int totcurve)
{
Curves *curves_dst = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
STRNCPY(curves_dst->id.name, curves_src->id.name);
curves_dst->mat = static_cast<Material **>(MEM_dupallocN(curves_src->mat));
curves_dst->totcol = curves_src->totcol;
curves_dst->geometry.point_size = totpoint;
curves_dst->geometry.curve_size = totcurve;
CustomData_copy(&curves_src->geometry.point_data,
&curves_dst->geometry.point_data,
CD_MASK_ALL,
CD_CALLOC,
totpoint);
CustomData_copy(&curves_src->geometry.curve_data,
&curves_dst->geometry.curve_data,
CD_MASK_ALL,
CD_CALLOC,
totcurve);
BKE_curves_update_customdata_pointers(curves_dst);
return curves_dst;
}
Curves *BKE_curves_copy_for_eval(Curves *curves_src, bool reference)
{
int flags = LIB_ID_COPY_LOCALIZE;
@ -414,7 +363,7 @@ static Curves *curves_evaluate_modifiers(struct Depsgraph *depsgraph,
CD_PROP_FLOAT3,
ATTR_POSITION,
curves->geometry.point_size);
BKE_curves_update_customdata_pointers(curves);
update_custom_data_pointers(*curves);
/* Created deformed coordinates array on demand. */
mti->deformVerts(
@ -457,3 +406,15 @@ void BKE_curves_batch_cache_free(Curves *curves)
BKE_curves_batch_cache_free_cb(curves);
}
}
namespace blender::bke {
Curves *curves_new_nomain(const int point_size, const int curves_size)
{
Curves *curves = static_cast<Curves *>(BKE_id_new_nomain(ID_CV, nullptr));
CurvesGeometry &geometry = CurvesGeometry::wrap(curves->geometry);
geometry.resize(point_size, curves_size);
return curves;
}
} // namespace blender::bke

View File

@ -0,0 +1,368 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include "MEM_guardedalloc.h"
#include "BLI_bounds.hh"
#include "DNA_curves_types.h"
#include "BKE_attribute_math.hh"
#include "BKE_curves.hh"
namespace blender::bke {
static const std::string ATTR_POSITION = "position";
static const std::string ATTR_RADIUS = "radius";
static const std::string ATTR_CURVE_TYPE = "curve_type";
/* -------------------------------------------------------------------- */
/** \name Constructors/Destructor
* \{ */
CurvesGeometry::CurvesGeometry() : CurvesGeometry(0, 0)
{
}
CurvesGeometry::CurvesGeometry(const int point_size, const int curve_size)
{
this->point_size = point_size;
this->curve_size = curve_size;
CustomData_reset(&this->point_data);
CustomData_reset(&this->curve_data);
CustomData_add_layer_named(&this->point_data,
CD_PROP_FLOAT3,
CD_DEFAULT,
nullptr,
this->point_size,
ATTR_POSITION.c_str());
this->curve_offsets = (int *)MEM_calloc_arrayN(this->curve_size + 1, sizeof(int), __func__);
this->update_customdata_pointers();
this->runtime = MEM_new<CurvesGeometryRuntime>(__func__);
}
/**
* \note Expects `dst` to be initialized, since the original attributes must be freed.
*/
static void copy_curves_geometry(CurvesGeometry &dst, const CurvesGeometry &src)
{
CustomData_free(&dst.point_data, dst.point_size);
CustomData_free(&dst.curve_data, dst.curve_size);
dst.point_size = src.point_size;
dst.curve_size = src.curve_size;
CustomData_copy(&src.point_data, &dst.point_data, CD_MASK_ALL, CD_DUPLICATE, dst.point_size);
CustomData_copy(&src.curve_data, &dst.curve_data, CD_MASK_ALL, CD_DUPLICATE, dst.curve_size);
MEM_SAFE_FREE(dst.curve_offsets);
dst.curve_offsets = (int *)MEM_calloc_arrayN(dst.point_size + 1, sizeof(int), __func__);
dst.offsets().copy_from(src.offsets());
dst.tag_topology_changed();
dst.update_customdata_pointers();
}
CurvesGeometry::CurvesGeometry(const CurvesGeometry &other)
: CurvesGeometry(other.point_size, other.curve_size)
{
copy_curves_geometry(*this, other);
}
CurvesGeometry &CurvesGeometry::operator=(const CurvesGeometry &other)
{
if (this != &other) {
copy_curves_geometry(*this, other);
}
return *this;
}
CurvesGeometry::~CurvesGeometry()
{
CustomData_free(&this->point_data, this->point_size);
CustomData_free(&this->curve_data, this->curve_size);
MEM_SAFE_FREE(this->curve_offsets);
MEM_delete(this->runtime);
this->runtime = nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Accessors
* \{ */
int CurvesGeometry::points_size() const
{
return this->point_size;
}
int CurvesGeometry::curves_size() const
{
return this->curve_size;
}
int CurvesGeometry::evaluated_points_size() const
{
/* TODO: Implement when there are evaluated points. */
return 0;
}
IndexRange CurvesGeometry::range_for_curve(const int index) const
{
const int offset = this->curve_offsets[index];
const int offset_next = this->curve_offsets[index + 1];
return {offset, offset_next - offset};
}
VArray<int8_t> CurvesGeometry::curve_types() const
{
if (const int8_t *data = (const int8_t *)CustomData_get_layer_named(
&this->curve_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str())) {
return VArray<int8_t>::ForSpan({data, this->curve_size});
}
return VArray<int8_t>::ForSingle(CURVE_TYPE_CATMULL_ROM, this->curve_size);
}
MutableSpan<int8_t> CurvesGeometry::curve_types()
{
int8_t *data = (int8_t *)CustomData_add_layer_named(&this->curve_data,
CD_PROP_INT8,
CD_CALLOC,
nullptr,
this->curve_size,
ATTR_CURVE_TYPE.c_str());
BLI_assert(data != nullptr);
return {data, this->curve_size};
}
MutableSpan<float3> CurvesGeometry::positions()
{
CustomData_duplicate_referenced_layer(&this->point_data, CD_PROP_FLOAT3, this->point_size);
this->update_customdata_pointers();
return {(float3 *)this->position, this->point_size};
}
Span<float3> CurvesGeometry::positions() const
{
return {(const float3 *)this->position, this->point_size};
}
MutableSpan<int> CurvesGeometry::offsets()
{
return {this->curve_offsets, this->curve_size + 1};
}
Span<int> CurvesGeometry::offsets() const
{
return {this->curve_offsets, this->curve_size + 1};
}
void CurvesGeometry::resize(const int point_size, const int curve_size)
{
if (point_size != this->point_size) {
CustomData_realloc(&this->point_data, point_size);
this->point_size = point_size;
}
if (curve_size != this->curve_size) {
CustomData_realloc(&this->curve_data, curve_size);
this->curve_size = curve_size;
this->curve_offsets = (int *)MEM_reallocN(this->curve_offsets, sizeof(int) * (curve_size + 1));
}
this->tag_topology_changed();
this->update_customdata_pointers();
}
void CurvesGeometry::tag_positions_changed()
{
this->runtime->position_cache_dirty = true;
this->runtime->tangent_cache_dirty = true;
this->runtime->normal_cache_dirty = true;
}
void CurvesGeometry::tag_topology_changed()
{
this->runtime->position_cache_dirty = true;
this->runtime->tangent_cache_dirty = true;
this->runtime->normal_cache_dirty = true;
}
void CurvesGeometry::tag_normals_changed()
{
this->runtime->normal_cache_dirty = true;
}
void CurvesGeometry::translate(const float3 &translation)
{
MutableSpan<float3> positions = this->positions();
threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position += translation;
}
});
}
void CurvesGeometry::transform(const float4x4 &matrix)
{
MutableSpan<float3> positions = this->positions();
threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) {
for (float3 &position : positions.slice(range)) {
position = matrix * position;
}
});
}
static std::optional<bounds::MinMaxResult<float3>> curves_bounds(const CurvesGeometry &curves)
{
Span<float3> positions = curves.positions();
if (curves.radius) {
Span<float> radii{curves.radius, curves.points_size()};
return bounds::min_max_with_radii(positions, radii);
}
return bounds::min_max(positions);
}
bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const
{
const std::optional<bounds::MinMaxResult<float3>> bounds = curves_bounds(*this);
if (!bounds) {
return false;
}
min = math::min(bounds->min, min);
max = math::max(bounds->max, max);
return true;
}
void CurvesGeometry::update_customdata_pointers()
{
this->position = (float(*)[3])CustomData_get_layer_named(
&this->point_data, CD_PROP_FLOAT3, ATTR_POSITION.c_str());
this->radius = (float *)CustomData_get_layer_named(
&this->point_data, CD_PROP_FLOAT, ATTR_RADIUS.c_str());
this->curve_type = (int8_t *)CustomData_get_layer_named(
&this->point_data, CD_PROP_INT8, ATTR_CURVE_TYPE.c_str());
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Domain Interpolation
* \{ */
/**
* Mix together all of a curve's control point values.
*
* \note Theoretically this interpolation does not need to compute all values at once.
* However, doing that makes the implementation simpler, and this can be optimized in the future if
* only some values are required.
*/
template<typename T>
static void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
attribute_math::DefaultMixer<T> mixer(r_values);
for (const int i_curve : IndexRange(curves.curves_size())) {
for (const int i_point : curves.range_for_curve(i_curve)) {
mixer.mix_in(i_curve, old_values[i_point]);
}
}
mixer.finalize();
}
/**
* A curve is selected if all of its control points were selected.
*
* \note Theoretically this interpolation does not need to compute all values at once.
* However, doing that makes the implementation simpler, and this can be optimized in the future if
* only some values are required.
*/
template<>
void adapt_curve_domain_point_to_curve_impl(const CurvesGeometry &curves,
const VArray<bool> &old_values,
MutableSpan<bool> r_values)
{
r_values.fill(true);
for (const int i_curve : IndexRange(curves.curves_size())) {
for (const int i_point : curves.range_for_curve(i_curve)) {
if (!old_values[i_point]) {
r_values[i_curve] = false;
break;
}
}
}
}
static GVArray adapt_curve_domain_point_to_curve(const CurvesGeometry &curves,
const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) {
Array<T> values(curves.curves_size());
adapt_curve_domain_point_to_curve_impl<T>(curves, varray.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
}
});
return new_varray;
}
/**
* Copy the value from a curve to all of its points.
*
* \note Theoretically this interpolation does not need to compute all values at once.
* However, doing that makes the implementation simpler, and this can be optimized in the future if
* only some values are required.
*/
template<typename T>
static void adapt_curve_domain_curve_to_point_impl(const CurvesGeometry &curves,
const VArray<T> &old_values,
MutableSpan<T> r_values)
{
for (const int i_curve : IndexRange(curves.curves_size())) {
r_values.slice(curves.range_for_curve(i_curve)).fill(old_values[i_curve]);
}
}
static GVArray adapt_curve_domain_curve_to_point(const CurvesGeometry &curves,
const GVArray &varray)
{
GVArray new_varray;
attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) {
using T = decltype(dummy);
Array<T> values(curves.points_size());
adapt_curve_domain_curve_to_point_impl<T>(curves, varray.typed<T>(), values);
new_varray = VArray<T>::ForContainer(std::move(values));
});
return new_varray;
}
fn::GVArray CurvesGeometry::adapt_domain(const fn::GVArray &varray,
const AttributeDomain from,
const AttributeDomain to) const
{
if (!varray) {
return {};
}
if (varray.is_empty()) {
return {};
}
if (from == to) {
return varray;
}
if (from == ATTR_DOMAIN_POINT && to == ATTR_DOMAIN_CURVE) {
return adapt_curve_domain_point_to_curve(*this, varray);
}
if (from == ATTR_DOMAIN_CURVE && to == ATTR_DOMAIN_POINT) {
return adapt_curve_domain_curve_to_point(*this, varray);
}
BLI_assert_unreachable();
return {};
}
/** \} */
} // namespace blender::bke

View File

@ -439,18 +439,6 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider
}
};
template<typename T>
static GVArray make_array_read_attribute(const void *data, const int domain_size)
{
return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
}
template<typename T>
static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
{
return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
}
static ComponentAttributeProviders create_attribute_providers_for_instances()
{
static InstancePositionAttributeProvider position;

View File

@ -854,18 +854,6 @@ static GVMutableArray make_derived_write_attribute(void *data, const int domain_
MutableSpan<StructT>((StructT *)data, domain_size));
}
template<typename T>
static GVArray make_array_read_attribute(const void *data, const int domain_size)
{
return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
}
template<typename T>
static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
{
return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
}
static float3 get_vertex_position(const MVert &vert)
{
return float3(vert.co);

View File

@ -117,18 +117,6 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con
namespace blender::bke {
template<typename T>
static GVArray make_array_read_attribute(const void *data, const int domain_size)
{
return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size));
}
template<typename T>
static GVMutableArray make_array_write_attribute(void *data, const int domain_size)
{
return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size));
}
/**
* In this function all the attribute providers for a point cloud component are created. Most data
* in this function is statically allocated, because it does not change over time.

View File

@ -234,7 +234,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
for (id = lb->first; id; id = id_next) {
id_next = id->next;
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
if ((id->tag & tag) || (ID_IS_LINKED(id) && (id->lib->id.tag & tag))) {
BLI_remlink(lb, id);
BLI_addtail(&tagged_deleted_ids, id);
/* Do not tag as no_main now, we want to unlink it first (lower-level ID management
@ -290,7 +290,7 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion)
for (id = lb->first; id; id = id_next) {
id_next = id->next;
/* NOTE: in case we delete a library, we also delete all its datablocks! */
if ((id->tag & tag) || (id->lib != NULL && (id->lib->id.tag & tag))) {
if ((id->tag & tag) || (ID_IS_LINKED(id) && (id->lib->id.tag & tag))) {
id->tag |= tag;
BKE_id_remapper_add(remapper, id, NULL);
}

View File

@ -2127,7 +2127,7 @@ static void lib_override_library_main_resync_on_library_indirect_level(
"ID override %s from library level %d still found as needing resync, when all "
"IDs from that level should have been processed after tackling library level %d",
id->name,
id->lib != NULL ? id->lib->temp_index : 0,
ID_IS_LINKED(id) ? id->lib->temp_index : 0,
library_indirect_level);
id->tag &= ~LIB_TAG_LIB_OVERRIDE_NEED_RESYNC;
}

View File

@ -73,7 +73,7 @@
#include "BKE_constraint.h"
#include "BKE_crazyspace.h"
#include "BKE_curve.h"
#include "BKE_curves.h"
#include "BKE_curves.hh"
#include "BKE_deform.h"
#include "BKE_displist.h"
#include "BKE_duplilist.h"
@ -3936,7 +3936,7 @@ bool BKE_object_minmax_dupli(Depsgraph *depsgraph,
ListBase *lb = object_duplilist(depsgraph, scene, ob);
LISTBASE_FOREACH (DupliObject *, dob, lb) {
if ((use_hidden == false) && (dob->no_draw != 0)) {
if (((use_hidden == false) && (dob->no_draw != 0)) || dob->ob_data == nullptr) {
/* pass */
}
else {

View File

@ -1331,9 +1331,6 @@ VolumeGridType BKE_volume_grid_type_openvdb(const openvdb::GridBase &grid)
if (grid.isType<openvdb::Vec3dGrid>()) {
return VOLUME_GRID_VECTOR_DOUBLE;
}
if (grid.isType<openvdb::StringGrid>()) {
return VOLUME_GRID_STRING;
}
if (grid.isType<openvdb::MaskGrid>()) {
return VOLUME_GRID_MASK;
}
@ -1369,7 +1366,6 @@ int BKE_volume_grid_channels(const VolumeGrid *grid)
case VOLUME_GRID_VECTOR_DOUBLE:
case VOLUME_GRID_VECTOR_INT:
return 3;
case VOLUME_GRID_STRING:
case VOLUME_GRID_POINTS:
case VOLUME_GRID_UNKNOWN:
return 0;
@ -1610,13 +1606,8 @@ struct CreateGridWithChangedResolutionOp {
template<typename GridType> typename openvdb::GridBase::Ptr operator()()
{
if constexpr (std::is_same_v<GridType, openvdb::StringGrid>) {
return {};
}
else {
return create_grid_with_changed_resolution(static_cast<const GridType &>(grid),
resolution_factor);
}
return create_grid_with_changed_resolution(static_cast<const GridType &>(grid),
resolution_factor);
}
};

View File

@ -63,7 +63,6 @@ static void extract_dense_float_voxels(const VolumeGridType grid_type,
case VOLUME_GRID_VECTOR_INT:
return extract_dense_voxels<openvdb::Vec3IGrid, openvdb::Vec3f>(
grid, bbox, reinterpret_cast<openvdb::Vec3f *>(r_voxels));
case VOLUME_GRID_STRING:
case VOLUME_GRID_POINTS:
case VOLUME_GRID_UNKNOWN:
/* Zero channels to copy. */

View File

@ -1,18 +1,4 @@
/*
* 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.
*/
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once

View File

@ -64,16 +64,6 @@ template<typename T> uint64_t vector_hash(const T &vec)
return result;
}
template<typename T, int Size> inline bool is_any_zero(const vec_struct_base<T, Size> &a)
{
for (int i = 0; i < Size; i++) {
if (a[i] == T(0)) {
return true;
}
}
return false;
}
} // namespace math
template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size> {
@ -353,7 +343,9 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
friend vec_base operator/(const vec_base &a, const vec_base &b)
{
BLI_assert(!math::is_any_zero(b));
for (int i = 0; i < Size; i++) {
BLI_assert(b[i] != T(0));
}
BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] / b[i]);
}
@ -365,7 +357,9 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
friend vec_base operator/(T a, const vec_base &b)
{
BLI_assert(!math::is_any_zero(b));
for (int i = 0; i < Size; i++) {
BLI_assert(b[i] != T(0));
}
BLI_VEC_OP_IMPL(ret, i, ret[i] = a / b[i]);
}
@ -509,7 +503,9 @@ template<typename T, int Size> struct vec_base : public vec_struct_base<T, Size>
BLI_INT_OP(T) friend vec_base operator%(const vec_base &a, const vec_base &b)
{
BLI_assert(!math::is_any_zero(b));
for (int i = 0; i < Size; i++) {
BLI_assert(b[i] != T(0));
}
BLI_VEC_OP_IMPL(ret, i, ret[i] = a[i] % b[i]);
}

View File

@ -39,6 +39,16 @@ template<typename T, int Size> inline bool is_zero(const vec_base<T, Size> &a)
return true;
}
template<typename T, int Size> inline bool is_any_zero(const vec_base<T, Size> &a)
{
for (int i = 0; i < Size; i++) {
if (a[i] == T(0)) {
return true;
}
}
return false;
}
template<typename T, int Size> inline vec_base<T, Size> abs(const vec_base<T, Size> &a)
{
vec_base<T, Size> result;

View File

@ -1,4 +1,4 @@
/* Apache License, Version 2.0 */
/* SPDX-License-Identifier: Apache-2.0 */
#include "testing/testing.h"

View File

@ -146,4 +146,29 @@ TEST(math_vec_types, VectorTypeConversion)
EXPECT_EQ(d[1], -1.0);
}
TEST(math_vec_types, Divide)
{
float2 a(1.0f, 2.0f);
float2 b(0.5f, 2.0f);
float2 result = a / b;
EXPECT_FLOAT_EQ(result.x, 2.0f);
EXPECT_FLOAT_EQ(result.y, 1.0f);
}
TEST(math_vec_types, DivideFloatByVector)
{
float a = 2.0f;
float2 b(0.5f, 2.0f);
float2 result = a / b;
EXPECT_FLOAT_EQ(result.x, 4.0f);
EXPECT_FLOAT_EQ(result.y, 1.0f);
}
TEST(math_vec_types, DivideFloatByVectorSmall)
{
float2 result = 2.0f / float2(2.0f);
EXPECT_FLOAT_EQ(result.x, 1.0f);
EXPECT_FLOAT_EQ(result.y, 1.0f);
}
} // namespace blender::tests

View File

@ -56,7 +56,7 @@ ID *do_versions_rename_id(Main *bmain,
ListBase *lb = which_libbase(bmain, id_type);
ID *id = nullptr;
LISTBASE_FOREACH (ID *, idtest, lb) {
if (idtest->lib == nullptr) {
if (!ID_IS_LINKED(idtest)) {
if (STREQ(idtest->name + 2, name_src)) {
id = idtest;
}

View File

@ -22,7 +22,7 @@
#include "DNA_curves_types.h"
#include "DNA_object_types.h"
#include "BKE_curves.h"
#include "BKE_curves.hh"
#include "GPU_batch.h"
#include "GPU_material.h"
@ -133,7 +133,7 @@ static void curves_batch_cache_fill_segments_proc_pos(Curves *curves,
{
/* TODO: use hair radius layer if available. */
const int curve_size = curves->geometry.curve_size;
Span<int> offsets{curves->geometry.offsets, curves->geometry.curve_size + 1};
Span<int> offsets{curves->geometry.curve_offsets, curves->geometry.curve_size + 1};
Span<float3> positions{(float3 *)curves->geometry.position, curves->geometry.point_size};
@ -216,7 +216,7 @@ static void curves_batch_cache_fill_strands_data(Curves *curves,
GPUVertBufRaw *seg_step)
{
const int curve_size = curves->geometry.curve_size;
Span<int> offsets{curves->geometry.offsets, curves->geometry.curve_size + 1};
Span<int> offsets{curves->geometry.curve_offsets, curves->geometry.curve_size + 1};
for (const int i : IndexRange(curve_size)) {
const IndexRange curve_range(offsets[i], offsets[i + 1] - offsets[i]);

View File

@ -592,6 +592,67 @@ void draw_subdiv_cache_free(DRWSubdivCache *cache)
SUBDIV_COARSE_FACE_FLAG_ACTIVE) \
<< SUBDIV_COARSE_FACE_FLAG_OFFSET)
static uint32_t compute_coarse_face_flag(BMFace *f, BMFace *efa_act)
{
if (f == nullptr) {
/* May happen during mapped extraction. */
return 0;
}
uint32_t flag = 0;
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
if (f == efa_act) {
flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
}
const int loopstart = BM_elem_index_get(f->l_first);
return (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
static void draw_subdiv_cache_extra_coarse_face_data_bm(BMesh *bm,
BMFace *efa_act,
uint32_t *flags_data)
{
BMFace *f;
BMIter iter;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
const int index = BM_elem_index_get(f);
flags_data[index] = compute_coarse_face_flag(f, efa_act);
}
}
static void draw_subdiv_cache_extra_coarse_face_data_mesh(Mesh *mesh, uint32_t *flags_data)
{
for (int i = 0; i < mesh->totpoly; i++) {
uint32_t flag = 0;
if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) {
flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
}
static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh,
BMesh *bm,
MeshRenderData *mr,
uint32_t *flags_data)
{
if (bm == nullptr) {
draw_subdiv_cache_extra_coarse_face_data_mesh(mesh, flags_data);
return;
}
for (int i = 0; i < mesh->totpoly; i++) {
BMFace *f = bm_original_face_get(mr, i);
flags_data[i] = compute_coarse_face_flag(f, mr->efa_act);
}
}
static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cache,
Mesh *mesh,
MeshRenderData *mr)
@ -611,56 +672,13 @@ static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cach
uint32_t *flags_data = (uint32_t *)(GPU_vertbuf_get_data(cache->extra_coarse_face_data));
if (mr->extract_type == MR_EXTRACT_BMESH) {
BMesh *bm = cache->bm;
BMFace *f;
BMIter iter;
/* Ensure all current elements follow new customdata layout. */
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
const int index = BM_elem_index_get(f);
uint32_t flag = 0;
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
if (f == mr->efa_act) {
flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
}
const int loopstart = BM_elem_index_get(f->l_first);
flags_data[index] = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
draw_subdiv_cache_extra_coarse_face_data_bm(cache->bm, mr->efa_act, flags_data);
}
else if (mr->extract_type == MR_EXTRACT_MAPPED) {
for (int i = 0; i < mesh->totpoly; i++) {
BMFace *f = bm_original_face_get(mr, i);
uint32_t flag = 0;
if (f) {
if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
flag |= SUBDIV_COARSE_FACE_FLAG_SELECT;
}
if (f == mr->efa_act) {
flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE;
}
const int loopstart = BM_elem_index_get(f->l_first);
flag = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
flags_data[i] = flag;
}
draw_subdiv_cache_extra_coarse_face_data_mapped(mesh, cache->bm, mr, flags_data);
}
else {
for (int i = 0; i < mesh->totpoly; i++) {
uint32_t flag = 0;
if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) {
flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH;
}
flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET);
}
draw_subdiv_cache_extra_coarse_face_data_mesh(mesh, flags_data);
}
/* Make sure updated data is re-uploaded. */

View File

@ -153,10 +153,10 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
const MeshRenderData *UNUSED(mr),
const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *UNUSED(data))
void *_data)
{
Mesh *coarse_mesh = subdiv_cache->mesh;
GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
@ -168,28 +168,20 @@ static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache,
GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops);
GPUVertBuf *coarse_weights = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format(coarse_weights, &format);
GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop);
float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights));
extract_weights_init(mr, cache, coarse_weights, _data);
const DRW_MeshWeightState *wstate = &cache->weight_state;
const MDeformVert *dverts = static_cast<const MDeformVert *>(
CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT));
for (int i = 0; i < coarse_mesh->totpoly; i++) {
const MPoly *mpoly = &coarse_mesh->mpoly[i];
for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop;
loop_index++) {
const MLoop *ml = &coarse_mesh->mloop[loop_index];
if (dverts != nullptr) {
const MDeformVert *dvert = &dverts[ml->v];
coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate);
}
else {
coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate);
}
if (mr->extract_type != MR_EXTRACT_BMESH) {
for (int i = 0; i < coarse_mesh->totpoly; i++) {
const MPoly *mpoly = &coarse_mesh->mpoly[i];
extract_weights_iter_poly_mesh(mr, mpoly, i, _data);
}
}
else {
BMIter f_iter;
BMFace *efa;
int face_index = 0;
BM_ITER_MESH_INDEX (efa, &f_iter, mr->bm, BM_FACES_OF_MESH, face_index) {
extract_weights_iter_poly_bm(mr, efa, face_index, _data);
}
}

View File

@ -163,6 +163,18 @@ static void reset_bezts(tGraphSliderOp *gso)
ANIM_animdata_freelist(&anim_data);
}
/**
* Get factor value and store it in RNA property.
* Custom data of #wmOperator needs to contain #tGraphSliderOp.
*/
static float slider_factor_get_and_remember(wmOperator *op)
{
tGraphSliderOp *gso = op->customdata;
const float factor = ED_slider_factor_get(gso->slider);
RNA_property_float_set(op->ptr, gso->factor_prop, factor);
return factor;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -378,8 +390,7 @@ static void decimate_modal_update(bContext *C, wmOperator *op)
reset_bezts(gso);
/* Apply... */
float factor = ED_slider_factor_get(gso->slider);
RNA_property_float_set(op->ptr, gso->factor_prop, factor);
const float factor = slider_factor_get_and_remember(op);
/* We don't want to limit the decimation to a certain error margin. */
const float error_sq_max = FLT_MAX;
decimate_graph_keys(&gso->ac, factor, error_sq_max);
@ -598,8 +609,7 @@ static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op)
/* Reset keyframe data to the state at invoke. */
reset_bezts(gso);
const float factor = ED_slider_factor_get(gso->slider);
RNA_property_float_set(op->ptr, gso->factor_prop, factor);
const float factor = slider_factor_get_and_remember(op);
blend_to_neighbor_graph_keys(&gso->ac, factor);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@ -725,7 +735,8 @@ static void breakdown_modal_update(bContext *C, wmOperator *op)
/* Reset keyframe data to the state at invoke. */
reset_bezts(gso);
breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider));
const float factor = slider_factor_get_and_remember(op);
breakdown_graph_keys(&gso->ac, factor);
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
}
@ -739,6 +750,7 @@ static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event)
tGraphSliderOp *gso = op->customdata;
gso->modal_update = breakdown_modal_update;
gso->factor_prop = RNA_struct_find_property(op->ptr, "factor");
breakdown_draw_status_header(C, gso);
return invoke_result;

View File

@ -1926,7 +1926,6 @@ static void sequencer_draw_display_buffer(const bContext *C,
if (!glsl_used) {
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
immUniform1i("image", 0);
}
immBegin(GPU_PRIM_TRI_FAN, 4);

View File

@ -226,7 +226,7 @@ static int lib_id_fake_user_toggle_exec(bContext *C, wmOperator *op)
ID *id = (ID *)idptr.data;
if ((id->lib != nullptr) || (ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
if (ID_IS_LINKED(id) || (ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB, ID_WS))) {
BKE_report(op->reports, RPT_ERROR, "Data-block type does not support fake user");
return OPERATOR_CANCELLED;
}

View File

@ -452,12 +452,21 @@ if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
endif()
if(WITH_OPENCOLORIO)
add_definitions(-DWITH_OCIO)
endif()
blender_add_lib(bf_gpu "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
target_link_libraries(bf_gpu PUBLIC
bf_draw_shaders
bf_gpu_shaders
)
if(WITH_OPENCOLORIO)
target_link_libraries(bf_gpu PUBLIC bf_ocio_shaders)
endif()
if(CXX_WARN_NO_SUGGEST_OVERRIDE)
target_compile_options(bf_gpu PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wsuggest-override>)
endif()

View File

@ -21,6 +21,9 @@ extern "C" {
#define SHADER_SOURCE(datatoc, filename, filepath) extern char datatoc[];
#include "glsl_draw_source_list.h"
#include "glsl_gpu_source_list.h"
#ifdef WITH_OCIO
# include "glsl_ocio_source_list.h"
#endif
#undef SHADER_SOURCE
}
@ -348,6 +351,9 @@ void gpu_shader_dependency_init()
g_sources->add_new(filename, new GPUSource(filepath, filename, datatoc));
#include "glsl_draw_source_list.h"
#include "glsl_gpu_source_list.h"
#ifdef WITH_OCIO
# include "glsl_ocio_source_list.h"
#endif
#undef SHADER_SOURCE
int errors = 0;

View File

@ -277,8 +277,6 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
GPU_matrix_identity_set();
GPU_matrix_identity_projection_set();
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE);
immUniform1i("overlayTexture", 0);
immUniform1i("imageTexture", 1);
int settings = stereo_format->display_mode;
if (settings == S3D_DISPLAY_ANAGLYPH) {
switch (stereo_format->anaglyph_type) {
@ -432,8 +430,6 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
GPU_batch_uniform_1i(batch, "overlay", do_overlay_merge);
GPU_batch_uniform_1i(batch, "display_transform", display_colorspace);
GPU_batch_uniform_1i(batch, "image_texture", 0);
GPU_batch_uniform_1i(batch, "overlays_texture", 1);
}
GPU_texture_bind(color, 0);

View File

@ -16,6 +16,7 @@ GPU_SHADER_CREATE_INFO(gpu_shader_2D_image_overlays_merge)
.push_constant(Type::MAT4, "ModelViewProjectionMatrix")
.push_constant(Type::BOOL, "display_transform")
.push_constant(Type::BOOL, "overlay")
/* Sampler slots should match OCIO's. */
.sampler(0, ImageType::FLOAT_2D, "image_texture")
.sampler(1, ImageType::FLOAT_2D, "overlays_texture")
.vertex_source("gpu_shader_2D_image_vert.glsl")

View File

@ -16,30 +16,46 @@
#include <stdexcept>
#include <string>
#include <Iex.h>
#include <ImathBox.h>
#include <ImfArray.h>
#include <ImfChannelList.h>
#include <ImfCompression.h>
#include <ImfCompressionAttribute.h>
#include <ImfIO.h>
#include <ImfInputFile.h>
#include <ImfOutputFile.h>
#include <ImfPixelType.h>
#include <ImfStandardAttributes.h>
#include <ImfStringAttribute.h>
#include <ImfVersion.h>
#include <half.h>
/* The OpenEXR version can reliably be found in this header file from OpenEXR,
* for both 2.x and 3.x:
*/
#include <OpenEXR/OpenEXRConfig.h>
#define COMBINED_OPENEXR_VERSION \
((10000 * OPENEXR_VERSION_MAJOR) + (100 * OPENEXR_VERSION_MINOR) + OPENEXR_VERSION_PATCH)
#if COMBINED_OPENEXR_VERSION >= 20599
/* >=2.5.99 -> OpenEXR >=3.0 */
# include <Imath/half.h>
# include <OpenEXR/ImfFrameBuffer.h>
# define exr_file_offset_t uint64_t
#else
/* OpenEXR 2.x, use the old locations. */
# include <OpenEXR/half.h>
# define exr_file_offset_t Int64
#endif
#include <OpenEXR/Iex.h>
#include <OpenEXR/ImfArray.h>
#include <OpenEXR/ImfChannelList.h>
#include <OpenEXR/ImfCompression.h>
#include <OpenEXR/ImfCompressionAttribute.h>
#include <OpenEXR/ImfIO.h>
#include <OpenEXR/ImfInputFile.h>
#include <OpenEXR/ImfOutputFile.h>
#include <OpenEXR/ImfPixelType.h>
#include <OpenEXR/ImfStandardAttributes.h>
#include <OpenEXR/ImfStringAttribute.h>
#include <OpenEXR/ImfVersion.h>
/* multiview/multipart */
#include <ImfInputPart.h>
#include <ImfMultiPartInputFile.h>
#include <ImfMultiPartOutputFile.h>
#include <ImfMultiView.h>
#include <ImfOutputPart.h>
#include <ImfPartHelper.h>
#include <ImfPartType.h>
#include <ImfTiledOutputPart.h>
#include <OpenEXR/ImfInputPart.h>
#include <OpenEXR/ImfMultiPartInputFile.h>
#include <OpenEXR/ImfMultiPartOutputFile.h>
#include <OpenEXR/ImfMultiView.h>
#include <OpenEXR/ImfOutputPart.h>
#include <OpenEXR/ImfPartHelper.h>
#include <OpenEXR/ImfPartType.h>
#include <OpenEXR/ImfTiledOutputPart.h>
#include "DNA_scene_types.h" /* For OpenEXR compression constants */
@ -115,12 +131,12 @@ class IMemStream : public Imf::IStream {
return false;
}
Int64 tellg() override
exr_file_offset_t tellg() override
{
return _exrpos;
}
void seekg(Int64 pos) override
void seekg(exr_file_offset_t pos) override
{
_exrpos = pos;
}
@ -130,8 +146,8 @@ class IMemStream : public Imf::IStream {
}
private:
Int64 _exrpos;
Int64 _exrsize;
exr_file_offset_t _exrpos;
exr_file_offset_t _exrsize;
unsigned char *_exrbuf;
};
@ -166,12 +182,12 @@ class IFileStream : public Imf::IStream {
return check_error();
}
Int64 tellg() override
exr_file_offset_t tellg() override
{
return std::streamoff(ifs.tellg());
}
void seekg(Int64 pos) override
void seekg(exr_file_offset_t pos) override
{
ifs.seekg(pos);
check_error();
@ -215,19 +231,19 @@ class OMemStream : public OStream {
ibuf->encodedsize += n;
}
Int64 tellp() override
exr_file_offset_t tellp() override
{
return offset;
}
void seekp(Int64 pos) override
void seekp(exr_file_offset_t pos) override
{
offset = pos;
ensure_size(offset);
}
private:
void ensure_size(Int64 size)
void ensure_size(exr_file_offset_t size)
{
/* if buffer is too small increase it. */
while (size > ibuf->encodedbuffersize) {
@ -238,7 +254,7 @@ class OMemStream : public OStream {
}
ImBuf *ibuf;
Int64 offset;
exr_file_offset_t offset;
};
/* File Output Stream */
@ -268,12 +284,12 @@ class OFileStream : public OStream {
check_error();
}
Int64 tellp() override
exr_file_offset_t tellp() override
{
return std::streamoff(ofs.tellp());
}
void seekp(Int64 pos) override
void seekp(exr_file_offset_t pos) override
{
ofs.seekp(pos);
check_error();

View File

@ -14,6 +14,10 @@ if(OPENCOLLADA_ANIMATION_CLIP)
add_definitions(-DWITH_OPENCOLLADA_ANIMATION_CLIP)
endif()
# In cmake version 3.21 and up, we can instead use the NO_CACHE option for
# find_file so we don't need to clear it from the cache here.
unset(OPENCOLLADA_ANIMATION_CLIP CACHE)
set(INC
.
../../blenkernel

View File

@ -330,7 +330,7 @@ enum {
/* 2 characters for ID code and 64 for actual name */
#define MAX_ID_NAME 66
/* ID_Runtime.remapping_status */
/* ID_Runtime_Remap.status */
enum {
/** new_id is directly linked in current .blend. */
ID_REMAP_IS_LINKED_DIRECT = 1 << 0,

View File

@ -13,6 +13,33 @@
extern "C" {
#endif
#ifdef __cplusplus
namespace blender::bke {
class CurvesGeometryRuntime;
} // namespace blender::bke
using CurvesGeometryRuntimeHandle = blender::bke::CurvesGeometryRuntime;
#else
typedef struct CurvesGeometryRuntimeHandle CurvesGeometryRuntimeHandle;
#endif
typedef enum CurveType {
CURVE_TYPE_CATMULL_ROM = 0,
CURVE_TYPE_POLY = 1,
CURVE_TYPE_BEZIER = 2,
CURVE_TYPE_NURBS = 3,
} CurveType;
typedef enum HandleType {
/** The handle can be moved anywhere, and doesn't influence the point's other handle. */
BEZIER_HANDLE_FREE = 0,
/** The location is automatically calculated to be smooth. */
BEZIER_HANDLE_AUTO = 1,
/** The location is calculated to point to the next/previous control point. */
BEZIER_HANDLE_VECTOR = 2,
/** The location is constrained to point in the opposite direction as the other handle. */
BEZIER_HANDLE_ALIGN = 3,
} HandleType;
/**
* A reusable data structure for geometry consisting of many curves. All control point data is
* stored contiguously for better efficiency. Data for each curve is stored as a slice of the
@ -33,6 +60,12 @@ typedef struct CurvesGeometry {
*/
float *radius;
/**
* The type of each curve. #CurveType.
* \note This data is owned by #curve_data.
*/
int8_t *curve_type;
/**
* The start index of each curve in the point data. The size of each curve can be calculated by
* subtracting the offset from the next offset. That is valid even for the last curve because
@ -40,7 +73,7 @@ typedef struct CurvesGeometry {
*
* \note This is *not* stored in #CustomData because its size is one larger than #curve_data.
*/
int *offsets;
int *curve_offsets;
/**
* All attributes stored on control points (#ATTR_DOMAIN_POINT).
@ -60,6 +93,11 @@ typedef struct CurvesGeometry {
* The number of curves in the data-block.
*/
int curve_size;
/**
* Runtime data for curves, stored as a pointer to allow defining this as a C++ class.
*/
CurvesGeometryRuntimeHandle *runtime;
} CurvesGeometry;
typedef struct Curves {

View File

@ -1988,7 +1988,7 @@ extern const char *RE_engine_id_CYCLES;
((v3d == NULL) || (((1 << (base)->object->type) & (v3d)->object_type_exclude_select) == 0)) && \
(((base)->flag & BASE_SELECTABLE) != 0))
#define BASE_SELECTED(v3d, base) (BASE_VISIBLE(v3d, base) && (((base)->flag & BASE_SELECTED) != 0))
#define BASE_EDITABLE(v3d, base) (BASE_VISIBLE(v3d, base) && ((base)->object->id.lib == NULL))
#define BASE_EDITABLE(v3d, base) (BASE_VISIBLE(v3d, base) && !ID_IS_LINKED((base)->object))
#define BASE_SELECTED_EDITABLE(v3d, base) \
(BASE_EDITABLE(v3d, base) && (((base)->flag & BASE_SELECTED) != 0))

View File

@ -106,8 +106,23 @@ typedef enum eXrPoseFlag {
XR_POSE_AIM = (1 << 1),
} eXrPoseFlag;
/**
* The following user and component path lengths are dependent on OpenXR's XR_MAX_PATH_LENGTH
* (256). A user path will be combined with a component path to identify an action binding, and
* that combined path should also have a max of XR_MAX_PATH_LENGTH (e.g. user_path =
* /user/hand/left, component_path = /input/trigger/value, full_path =
* /user/hand/left/input/trigger/value).
*/
#define XR_MAX_USER_PATH_LENGTH 64
#define XR_MAX_COMPONENT_PATH_LENGTH 192
/* -------------------------------------------------------------------- */
typedef struct XrComponentPath {
struct XrComponentPath *next, *prev;
char path[192]; /* XR_MAX_COMPONENT_PATH_LENGTH */
} XrComponentPath;
typedef struct XrActionMapBinding {
struct XrActionMapBinding *next, *prev;
@ -117,8 +132,7 @@ typedef struct XrActionMapBinding {
/** OpenXR interaction profile path. */
char profile[256];
/** OpenXR component paths. */
char component_path0[192];
char component_path1[192];
ListBase component_paths; /* XrComponentPath */
/** Input threshold/region. */
float float_threshold;
@ -132,6 +146,11 @@ typedef struct XrActionMapBinding {
/* -------------------------------------------------------------------- */
typedef struct XrUserPath {
struct XrUserPath *next, *prev;
char path[64]; /* XR_MAX_USER_PATH_LENGTH */
} XrUserPath;
typedef struct XrActionMapItem {
struct XrActionMapItem *next, *prev;
@ -142,8 +161,7 @@ typedef struct XrActionMapItem {
char _pad[7];
/** OpenXR user paths. */
char user_path0[64];
char user_path1[64];
ListBase user_paths; /* XrUserPath */
/** Operator to be called on XR events. */
char op[64]; /* OP_MAX_TYPENAME */

View File

@ -43,7 +43,7 @@ static void rna_Curves_curve_offset_data_begin(CollectionPropertyIterator *iter,
{
const Curves *curves = rna_curves(ptr);
rna_iterator_array_begin(iter,
(void *)curves->geometry.offsets,
(void *)curves->geometry.curve_offsets,
sizeof(int),
curves->geometry.curve_size + 1,
false,
@ -95,7 +95,7 @@ static char *rna_CurvePoint_path(PointerRNA *ptr)
static int rna_CurveSlice_index_get(PointerRNA *ptr)
{
Curves *curves = rna_curves(ptr);
return (int)((int *)ptr->data - curves->geometry.offsets);
return (int)((int *)ptr->data - curves->geometry.curve_offsets);
}
static char *rna_CurveSlice_path(PointerRNA *ptr)
@ -220,7 +220,7 @@ static void rna_def_curves(BlenderRNA *brna)
/* Point and Curve RNA API helpers. */
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", "geometry.curve_size");
RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", "geometry.curve_size");
RNA_def_property_struct_type(prop, "CurveSlice");
RNA_def_property_ui_text(prop, "Curves", "All curves in the data-block");
@ -243,7 +243,7 @@ static void rna_def_curves(BlenderRNA *brna)
RNA_define_verify_sdna(1);
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "geometry.offsets", NULL);
RNA_def_property_collection_sdna(prop, NULL, "geometry.curve_offsets", NULL);
RNA_def_property_struct_type(prop, "IntAttributeValue");
RNA_def_property_collection_funcs(prop,
"rna_Curves_curve_offset_data_begin",

View File

@ -26,7 +26,6 @@ const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = {
{VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"},
{VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"},
{VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"},
{VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"},
{VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"},
{VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"},
{VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"},

View File

@ -46,6 +46,43 @@ static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
/** \name XR Action Map
* \{ */
static XrComponentPath *rna_XrComponentPath_new(XrActionMapBinding *amb, const char *path_str)
{
# ifdef WITH_XR_OPENXR
XrComponentPath *component_path = MEM_callocN(sizeof(XrComponentPath), __func__);
BLI_strncpy(component_path->path, path_str, sizeof(component_path->path));
BLI_addtail(&amb->component_paths, component_path);
return component_path;
# else
UNUSED_VARS(amb, path_str);
return NULL;
# endif
}
static void rna_XrComponentPath_remove(XrActionMapBinding *amb, PointerRNA *component_path_ptr)
{
# ifdef WITH_XR_OPENXR
XrComponentPath *component_path = component_path_ptr->data;
int idx = BLI_findindex(&amb->component_paths, component_path);
if (idx != -1) {
BLI_freelinkN(&amb->component_paths, component_path);
}
RNA_POINTER_INVALIDATE(component_path_ptr);
# else
UNUSED_VARS(amb, component_path_ptr);
# endif
}
static XrComponentPath *rna_XrComponentPath_find(XrActionMapBinding *amb, const char *path_str)
{
# ifdef WITH_XR_OPENXR
return BLI_findstring(&amb->component_paths, path_str, offsetof(XrComponentPath, path));
# else
UNUSED_VARS(amb, path_str);
return NULL;
# endif
}
static XrActionMapBinding *rna_XrActionMapBinding_new(XrActionMapItem *ami,
const char *name,
bool replace_existing)
@ -99,6 +136,28 @@ static XrActionMapBinding *rna_XrActionMapBinding_find(XrActionMapItem *ami, con
# endif
}
static void rna_XrActionMapBinding_component_paths_begin(CollectionPropertyIterator *iter,
PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapBinding *amb = (XrActionMapBinding *)ptr->data;
rna_iterator_listbase_begin(iter, &amb->component_paths, NULL);
# else
UNUSED_VARS(iter, ptr);
# endif
}
static int rna_XrActionMapBinding_component_paths_length(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapBinding *amb = (XrActionMapBinding *)ptr->data;
return BLI_listbase_count(&amb->component_paths);
# else
UNUSED_VARS(ptr);
return 0;
# endif
}
static int rna_XrActionMapBinding_axis0_region_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@ -174,6 +233,43 @@ static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene)
# endif
}
static XrUserPath *rna_XrUserPath_new(XrActionMapItem *ami, const char *path_str)
{
# ifdef WITH_XR_OPENXR
XrUserPath *user_path = MEM_callocN(sizeof(XrUserPath), __func__);
BLI_strncpy(user_path->path, path_str, sizeof(user_path->path));
BLI_addtail(&ami->user_paths, user_path);
return user_path;
# else
UNUSED_VARS(ami, path_str);
return NULL;
# endif
}
static void rna_XrUserPath_remove(XrActionMapItem *ami, PointerRNA *user_path_ptr)
{
# ifdef WITH_XR_OPENXR
XrUserPath *user_path = user_path_ptr->data;
int idx = BLI_findindex(&ami->user_paths, user_path);
if (idx != -1) {
BLI_freelinkN(&ami->user_paths, user_path);
}
RNA_POINTER_INVALIDATE(user_path_ptr);
# else
UNUSED_VARS(ami, user_path_ptr);
# endif
}
static XrUserPath *rna_XrUserPath_find(XrActionMapItem *ami, const char *path_str)
{
# ifdef WITH_XR_OPENXR
return BLI_findstring(&ami->user_paths, path_str, offsetof(XrUserPath, path));
# else
UNUSED_VARS(ami, path_str);
return NULL;
# endif
}
static XrActionMapItem *rna_XrActionMapItem_new(XrActionMap *am,
const char *name,
bool replace_existing)
@ -222,6 +318,27 @@ static XrActionMapItem *rna_XrActionMapItem_find(XrActionMap *am, const char *na
# endif
}
static void rna_XrActionMapItem_user_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapItem *ami = (XrActionMapItem *)ptr->data;
rna_iterator_listbase_begin(iter, &ami->user_paths, NULL);
# else
UNUSED_VARS(iter, ptr);
# endif
}
static int rna_XrActionMapItem_user_paths_length(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapItem *ami = (XrActionMapItem *)ptr->data;
return BLI_listbase_count(&ami->user_paths);
# else
UNUSED_VARS(ptr);
return 0;
# endif
}
static void rna_XrActionMapItem_op_name_get(PointerRNA *ptr, char *value)
{
# ifdef WITH_XR_OPENXR
@ -395,6 +512,27 @@ static void rna_XrActionMapItem_pose_is_controller_aim_set(PointerRNA *ptr, bool
# endif
}
static void rna_XrActionMapItem_bindings_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapItem *ami = (XrActionMapItem *)ptr->data;
rna_iterator_listbase_begin(iter, &ami->bindings, NULL);
# else
UNUSED_VARS(iter, ptr);
# endif
}
static int rna_XrActionMapItem_bindings_length(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMapItem *ami = (XrActionMapItem *)ptr->data;
return BLI_listbase_count(&ami->bindings);
# else
UNUSED_VARS(ptr);
return 0;
# endif
}
static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@ -471,6 +609,27 @@ static XrActionMap *rna_XrActionMap_find(PointerRNA *ptr, const char *name)
# endif
}
static void rna_XrActionMap_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMap *actionmap = (XrActionMap *)ptr->data;
rna_iterator_listbase_begin(iter, &actionmap->items, NULL);
# else
UNUSED_VARS(iter, ptr);
# endif
}
static int rna_XrActionMap_items_length(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
XrActionMap *actionmap = (XrActionMap *)ptr->data;
return BLI_listbase_count(&actionmap->items);
# else
UNUSED_VARS(ptr);
return 0;
# endif
}
static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@ -576,26 +735,8 @@ static bool rna_XrSessionState_action_create(bContext *C,
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = CTX_wm_manager(C);
unsigned int count_subaction_paths = 0;
const char *subaction_paths[2];
if (ami->user_path0[0]) {
subaction_paths[0] = ami->user_path0;
++count_subaction_paths;
if (ami->user_path1[0]) {
subaction_paths[1] = ami->user_path1;
++count_subaction_paths;
}
}
else {
if (ami->user_path1[0]) {
subaction_paths[0] = ami->user_path1;
++count_subaction_paths;
}
else {
return false;
}
if (BLI_listbase_is_empty(&ami->user_paths)) {
return false;
}
const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT);
@ -621,8 +762,7 @@ static bool rna_XrSessionState_action_create(bContext *C,
actionmap->name,
ami->name,
ami->type,
count_subaction_paths,
subaction_paths,
&ami->user_paths,
ot,
op_properties,
is_button_action ? ami->haptic_name : NULL,
@ -645,30 +785,10 @@ static bool rna_XrSessionState_action_binding_create(bContext *C,
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = CTX_wm_manager(C);
unsigned int count_subaction_paths = 0;
const char *subaction_paths[2];
const char *component_paths[2];
if (ami->user_path0[0]) {
subaction_paths[0] = ami->user_path0;
component_paths[0] = amb->component_path0;
++count_subaction_paths;
if (ami->user_path1[0]) {
subaction_paths[1] = ami->user_path1;
component_paths[1] = amb->component_path1;
++count_subaction_paths;
}
}
else {
if (ami->user_path1[0]) {
subaction_paths[0] = ami->user_path1;
component_paths[0] = amb->component_path1;
++count_subaction_paths;
}
else {
return false;
}
const int count_user_paths = BLI_listbase_count(&ami->user_paths);
const int count_component_paths = BLI_listbase_count(&amb->component_paths);
if (count_user_paths < 1 || (count_user_paths != count_component_paths)) {
return false;
}
const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT);
@ -695,9 +815,8 @@ static bool rna_XrSessionState_action_binding_create(bContext *C,
actionmap->name,
ami->name,
amb->profile,
count_subaction_paths,
subaction_paths,
component_paths,
&ami->user_paths,
&amb->component_paths,
is_float_action ? float_thresholds : NULL,
is_button_action ? axis_flags : NULL,
is_pose_action ? poses : NULL);
@ -954,6 +1073,18 @@ static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter
# endif
}
static int rna_XrSessionState_actionmaps_length(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
ListBase *lb = WM_xr_actionmaps_get(xr->runtime);
return BLI_listbase_count(lb);
# else
UNUSED_VARS(ptr);
return 0;
# endif
}
static int rna_XrSessionState_active_actionmap_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@ -1240,6 +1371,42 @@ static const EnumPropertyItem rna_enum_xr_axis1_flags[] = {
/** \name XR Action Map
* \{ */
static void rna_def_xr_component_paths(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "XrComponentPaths");
srna = RNA_def_struct(brna, "XrComponentPaths", NULL);
RNA_def_struct_sdna(srna, "XrActionMapBinding");
RNA_def_struct_ui_text(srna, "XR Component Paths", "Collection of OpenXR component paths");
func = RNA_def_function(srna, "new", "rna_XrComponentPath_new");
parm = RNA_def_string(
func, "path", NULL, XR_MAX_COMPONENT_PATH_LENGTH, "Path", "OpenXR component path");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
func, "component_path", "XrComponentPath", "Component Path", "Added component path");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrComponentPath_remove");
parm = RNA_def_pointer(func, "component_path", "XrComponentPath", "Component Path", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "find", "rna_XrComponentPath_find");
parm = RNA_def_string(
func, "path", NULL, XR_MAX_COMPONENT_PATH_LENGTH, "Path", "OpenXR component path");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func,
"component_path",
"XrComponentPath",
"Component Path",
"The component path with the given path");
RNA_def_function_return(func, parm);
}
static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@ -1289,6 +1456,36 @@ static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
}
static void rna_def_xr_user_paths(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
FunctionRNA *func;
PropertyRNA *parm;
RNA_def_property_srna(cprop, "XrUserPaths");
srna = RNA_def_struct(brna, "XrUserPaths", NULL);
RNA_def_struct_sdna(srna, "XrActionMapItem");
RNA_def_struct_ui_text(srna, "XR User Paths", "Collection of OpenXR user paths");
func = RNA_def_function(srna, "new", "rna_XrUserPath_new");
parm = RNA_def_string(func, "path", NULL, XR_MAX_USER_PATH_LENGTH, "Path", "OpenXR user path");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(func, "user_path", "XrUserPath", "User Path", "Added user path");
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrUserPath_remove");
parm = RNA_def_pointer(func, "user_path", "XrUserPath", "User Path", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0);
func = RNA_def_function(srna, "find", "rna_XrUserPath_find");
parm = RNA_def_string(func, "path", NULL, XR_MAX_USER_PATH_LENGTH, "Path", "OpenXR user path");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
func, "user_path", "XrUserPath", "User Path", "The user path with the given path");
RNA_def_function_return(func, parm);
}
static void rna_def_xr_actionmap_items(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@ -1404,6 +1601,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
prop = RNA_def_property(srna, "actionmap_items", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "items", NULL);
RNA_def_property_struct_type(prop, "XrActionMapItem");
RNA_def_property_collection_funcs(prop,
"rna_XrActionMap_items_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
"rna_XrActionMap_items_length",
NULL,
NULL,
NULL);
RNA_def_property_ui_text(
prop,
"Items",
@ -1414,6 +1620,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "selitem");
RNA_def_property_ui_text(prop, "Selected Item", "");
/* XrUserPath */
srna = RNA_def_struct(brna, "XrUserPath", NULL);
RNA_def_struct_sdna(srna, "XrUserPath");
RNA_def_struct_ui_text(srna, "XR User Path", "");
prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, XR_MAX_USER_PATH_LENGTH);
RNA_def_property_ui_text(prop, "Path", "OpenXR user path");
/* XrActionMapItem */
srna = RNA_def_struct(brna, "XrActionMapItem", NULL);
RNA_def_struct_sdna(srna, "XrActionMapItem");
@ -1429,13 +1644,19 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Action type");
RNA_def_property_update(prop, 0, "rna_XrActionMapItem_update");
prop = RNA_def_property(srna, "user_path0", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 64);
RNA_def_property_ui_text(prop, "User Path 0", "OpenXR user path");
prop = RNA_def_property(srna, "user_path1", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 64);
RNA_def_property_ui_text(prop, "User Path 1", "OpenXR user path");
prop = RNA_def_property(srna, "user_paths", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrUserPath");
RNA_def_property_collection_funcs(prop,
"rna_XrActionMapItem_user_paths_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
"rna_XrActionMapItem_user_paths_length",
NULL,
NULL,
NULL);
RNA_def_property_ui_text(prop, "User Paths", "OpenXR user paths");
rna_def_xr_user_paths(brna, prop);
prop = RNA_def_property(srna, "op", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME);
@ -1520,6 +1741,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
prop = RNA_def_property(srna, "bindings", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionMapBinding");
RNA_def_property_collection_funcs(prop,
"rna_XrActionMapItem_bindings_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
"rna_XrActionMapItem_bindings_length",
NULL,
NULL,
NULL);
RNA_def_property_ui_text(
prop, "Bindings", "Bindings for the action map item, mapping the action to an XR input");
rna_def_xr_actionmap_bindings(brna, prop);
@ -1528,6 +1758,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "selbinding");
RNA_def_property_ui_text(prop, "Selected Binding", "Currently selected binding");
/* XrComponentPath */
srna = RNA_def_struct(brna, "XrComponentPath", NULL);
RNA_def_struct_sdna(srna, "XrComponentPath");
RNA_def_struct_ui_text(srna, "XR Component Path", "");
prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, XR_MAX_COMPONENT_PATH_LENGTH);
RNA_def_property_ui_text(prop, "Path", "OpenXR component path");
/* XrActionMapBinding */
srna = RNA_def_struct(brna, "XrActionMapBinding", NULL);
RNA_def_struct_sdna(srna, "XrActionMapBinding");
@ -1542,13 +1781,19 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_string_maxlength(prop, 256);
RNA_def_property_ui_text(prop, "Profile", "OpenXR interaction profile path");
prop = RNA_def_property(srna, "component_path0", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 192);
RNA_def_property_ui_text(prop, "Component Path 0", "OpenXR component path");
prop = RNA_def_property(srna, "component_path1", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, 192);
RNA_def_property_ui_text(prop, "Component Path 1", "OpenXR component path");
prop = RNA_def_property(srna, "component_paths", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrComponentPath");
RNA_def_property_collection_funcs(prop,
"rna_XrActionMapBinding_component_paths_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
"rna_XrActionMapBinding_component_paths_length",
NULL,
NULL,
NULL);
RNA_def_property_ui_text(prop, "Component Paths", "OpenXR component paths");
rna_def_xr_component_paths(brna, prop);
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "float_threshold");
@ -1812,7 +2057,7 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_set", NULL, 64, "Action Set", "Action set name");
parm = RNA_def_string(func, "action_set", NULL, MAX_NAME, "Action Set", "Action set name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
@ -1823,19 +2068,19 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_set", NULL, 64, "Action Set", "Action set name");
parm = RNA_def_string(func, "action_set", NULL, MAX_NAME, "Action Set", "Action set name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func,
"grip_action",
NULL,
64,
MAX_NAME,
"Grip Action",
"Name of the action representing the controller grips");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func,
"aim_action",
NULL,
64,
MAX_NAME,
"Aim Action",
"Name of the action representing the controller aims");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
@ -1847,11 +2092,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "user_path", NULL, 64, "User Path", "OpenXR user path");
parm = RNA_def_string(
func, "user_path", NULL, XR_MAX_USER_PATH_LENGTH, "User Path", "OpenXR user path");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_float_array(
func,
@ -1871,15 +2117,15 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(
func,
"user_path",
NULL,
64,
XR_MAX_USER_PATH_LENGTH,
"User Path",
"Optional OpenXR user path. If not set, the action will be applied to all paths");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
@ -1922,15 +2168,15 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
RNA_def_function_flag(func, FUNC_NO_SELF);
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_string(
func,
"user_path",
NULL,
64,
XR_MAX_USER_PATH_LENGTH,
"User Path",
"Optional OpenXR user path. If not set, the action will be stopped for all paths");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
@ -2068,16 +2314,16 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
"Additional scale multiplier to apply to base scale when determining viewer scale");
prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "XrActionMap");
RNA_def_property_collection_funcs(prop,
"rna_XrSessionState_actionmaps_begin",
"rna_iterator_listbase_next",
"rna_iterator_listbase_end",
"rna_iterator_listbase_get",
NULL,
"rna_XrSessionState_actionmaps_length",
NULL,
NULL,
NULL);
RNA_def_property_struct_type(prop, "XrActionMap");
RNA_def_property_ui_text(prop, "XR Action Maps", "");
rna_def_xr_actionmaps(brna, prop);

View File

@ -189,10 +189,8 @@ struct DisplaceGridOp {
template<typename GridType> void operator()()
{
if constexpr (blender::is_same_any_v<GridType,
openvdb::points::PointDataGrid,
openvdb::StringGrid,
openvdb::MaskGrid>) {
if constexpr (blender::
is_same_any_v<GridType, openvdb::points::PointDataGrid, openvdb::MaskGrid>) {
/* We don't support displacing these grid types yet. */
return;
}

View File

@ -10,6 +10,7 @@
#include "BLI_assert.h"
#include "BLI_dynstr.h"
#include "BLI_hash_mm3.h"
#include "BLI_math_vector.h"
#include "BLI_string_ref.hh"
#include "BLI_utildefines.h"

View File

@ -3,6 +3,7 @@
#include <cmath>
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_string.h"
#include "UI_interface.h"

View File

@ -2,6 +2,8 @@
#include "node_function_util.hh"
#include "BLI_math_vector.h"
#include "UI_interface.h"
#include "UI_resources.h"

View File

@ -1585,8 +1585,7 @@ bool WM_xr_action_create(wmXrData *xr,
const char *action_set_name,
const char *action_name,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
const ListBase *user_paths,
struct wmOperatorType *ot,
struct IDProperty *op_properties,
const char *haptic_name,
@ -1601,9 +1600,8 @@ bool WM_xr_action_binding_create(wmXrData *xr,
const char *action_set_name,
const char *action_name,
const char *profile_path,
unsigned int count_subaction_paths,
const char **subaction_paths,
const char **component_paths,
const ListBase *user_paths,
const ListBase *component_paths,
const float *float_thresholds,
const eXrAxisFlag *axis_flags,
const struct wmXrPose *poses);

View File

@ -483,7 +483,6 @@ static void draw_display_buffer(PlayState *ps, ImBuf *ibuf)
if (!glsl_used) {
immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
immUniform1i("image", 0);
}
immBegin(GPU_PRIM_TRI_FAN, 4);

View File

@ -67,7 +67,7 @@ void wm_stereo3d_draw_sidebyside(wmWindow *win, int view)
const float halfx = GLA_PIXEL_OFS / sizex;
const float halfy = GLA_PIXEL_OFS / sizex;
immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
/* Texture is already bound to GL_TEXTURE0 unit. */
immBegin(GPU_PRIM_TRI_FAN, 4);
@ -111,7 +111,7 @@ void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
const float halfx = GLA_PIXEL_OFS / sizex;
const float halfy = GLA_PIXEL_OFS / sizex;
immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
/* Texture is already bound to GL_TEXTURE0 unit. */
immBegin(GPU_PRIM_TRI_FAN, 4);

View File

@ -56,8 +56,7 @@ static wmXrActionSet *action_set_find(wmXrData *xr, const char *action_set_name)
static wmXrAction *action_create(const char *action_name,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
const ListBase *user_paths,
wmOperatorType *ot,
IDProperty *op_properties,
const char *haptic_name,
@ -73,15 +72,16 @@ static wmXrAction *action_create(const char *action_name,
strcpy(action->name, action_name);
action->type = type;
const unsigned int count = count_subaction_paths;
const unsigned int count = (unsigned int)BLI_listbase_count(user_paths);
unsigned int subaction_idx = 0;
action->count_subaction_paths = count;
action->subaction_paths = MEM_mallocN(sizeof(*action->subaction_paths) * count,
"XrAction_SubactionPaths");
for (unsigned int i = 0; i < count; ++i) {
action->subaction_paths[i] = MEM_mallocN(strlen(subaction_paths[i]) + 1,
"XrAction_SubactionPath");
strcpy(action->subaction_paths[i], subaction_paths[i]);
LISTBASE_FOREACH_INDEX (XrUserPath *, user_path, user_paths, subaction_idx) {
action->subaction_paths[subaction_idx] = MEM_mallocN(strlen(user_path->path) + 1,
"XrAction_SubactionPath");
strcpy(action->subaction_paths[subaction_idx], user_path->path);
}
size_t size;
@ -140,10 +140,9 @@ static void action_destroy(void *val)
MEM_SAFE_FREE(action->name);
const unsigned int count = action->count_subaction_paths;
char **subaction_paths = action->subaction_paths;
if (subaction_paths) {
for (unsigned int i = 0; i < count; ++i) {
for (unsigned int i = 0; i < action->count_subaction_paths; ++i) {
MEM_SAFE_FREE(subaction_paths[i]);
}
MEM_freeN(subaction_paths);
@ -214,8 +213,7 @@ bool WM_xr_action_create(wmXrData *xr,
const char *action_set_name,
const char *action_name,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
const ListBase *user_paths,
wmOperatorType *ot,
IDProperty *op_properties,
const char *haptic_name,
@ -232,8 +230,7 @@ bool WM_xr_action_create(wmXrData *xr,
wmXrAction *action = action_create(action_name,
type,
count_subaction_paths,
subaction_paths,
user_paths,
ot,
op_properties,
haptic_name,
@ -244,9 +241,19 @@ bool WM_xr_action_create(wmXrData *xr,
action_flag,
haptic_flag);
const unsigned int count = (unsigned int)BLI_listbase_count(user_paths);
unsigned int subaction_idx = 0;
char **subaction_paths = MEM_calloc_arrayN(
count, sizeof(*subaction_paths), "XrAction_SubactionPathPointers");
LISTBASE_FOREACH_INDEX (XrUserPath *, user_path, user_paths, subaction_idx) {
subaction_paths[subaction_idx] = (char *)user_path->path;
}
GHOST_XrActionInfo info = {
.name = action_name,
.count_subaction_paths = count_subaction_paths,
.count_subaction_paths = count,
.subaction_paths = subaction_paths,
.states = action->states,
.float_thresholds = action->float_thresholds,
@ -273,11 +280,11 @@ bool WM_xr_action_create(wmXrData *xr,
break;
}
if (!GHOST_XrCreateActions(xr->runtime->context, action_set_name, 1, &info)) {
return false;
}
const bool success = GHOST_XrCreateActions(xr->runtime->context, action_set_name, 1, &info);
return true;
MEM_freeN(subaction_paths);
return success;
}
void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char *action_name)
@ -323,19 +330,29 @@ bool WM_xr_action_binding_create(wmXrData *xr,
const char *action_set_name,
const char *action_name,
const char *profile_path,
unsigned int count_subaction_paths,
const char **subaction_paths,
const char **component_paths,
const ListBase *user_paths,
const ListBase *component_paths,
const float *float_thresholds,
const eXrAxisFlag *axis_flags,
const struct wmXrPose *poses)
{
GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN(
count_subaction_paths, sizeof(*binding_infos), __func__);
const unsigned int count = (unsigned int)BLI_listbase_count(user_paths);
BLI_assert(count == (unsigned int)BLI_listbase_count(component_paths));
for (unsigned int i = 0; i < count_subaction_paths; ++i) {
GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN(
count, sizeof(*binding_infos), "XrActionBinding_Infos");
char **subaction_paths = MEM_calloc_arrayN(
count, sizeof(*subaction_paths), "XrActionBinding_SubactionPathPointers");
for (unsigned int i = 0; i < count; ++i) {
GHOST_XrActionBindingInfo *binding_info = &binding_infos[i];
binding_info->component_path = component_paths[i];
const XrUserPath *user_path = BLI_findlink(user_paths, i);
const XrComponentPath *component_path = BLI_findlink(component_paths, i);
subaction_paths[i] = (char *)user_path->path;
binding_info->component_path = component_path->path;
if (float_thresholds) {
binding_info->float_threshold = float_thresholds[i];
}
@ -351,15 +368,18 @@ bool WM_xr_action_binding_create(wmXrData *xr,
GHOST_XrActionProfileInfo profile_info = {
.action_name = action_name,
.profile_path = profile_path,
.count_subaction_paths = count_subaction_paths,
.count_subaction_paths = count,
.subaction_paths = subaction_paths,
.bindings = binding_infos,
};
bool ret = GHOST_XrCreateActionBindings(xr->runtime->context, action_set_name, 1, &profile_info);
const bool success = GHOST_XrCreateActionBindings(
xr->runtime->context, action_set_name, 1, &profile_info);
MEM_freeN(subaction_paths);
MEM_freeN(binding_infos);
return ret;
return success;
}
void WM_xr_action_binding_destroy(wmXrData *xr,

View File

@ -118,11 +118,17 @@ XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
return amb_dst;
}
static void wm_xr_actionmap_binding_clear(XrActionMapBinding *amb)
{
BLI_freelistN(&amb->component_paths);
}
bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb)
{
int idx = BLI_findindex(&ami->bindings, amb);
if (idx != -1) {
wm_xr_actionmap_binding_clear(amb);
BLI_freelinkN(&ami->bindings, amb);
if (idx <= ami->selbinding) {
@ -155,12 +161,6 @@ XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const cha
* Item in an XR action map, that maps an XR event to an operator, pose, or haptic output.
* \{ */
static void wm_xr_actionmap_item_bindings_clear(XrActionMapItem *ami)
{
BLI_freelistN(&ami->bindings);
ami->selbinding = 0;
}
static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami)
{
WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op);
@ -180,6 +180,19 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
}
}
static void wm_xr_actionmap_item_clear(XrActionMapItem *ami)
{
LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
wm_xr_actionmap_binding_clear(amb);
}
BLI_freelistN(&ami->bindings);
ami->selbinding = 0;
wm_xr_actionmap_item_properties_free(ami);
BLI_freelistN(&ami->user_paths);
}
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
{
switch (ami->type) {
@ -324,8 +337,7 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
int idx = BLI_findindex(&actionmap->items, ami);
if (idx != -1) {
wm_xr_actionmap_item_bindings_clear(ami);
wm_xr_actionmap_item_properties_free(ami);
wm_xr_actionmap_item_clear(ami);
BLI_freelinkN(&actionmap->items, ami);
if (idx <= actionmap->selitem) {
@ -480,12 +492,9 @@ XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
void WM_xr_actionmap_clear(XrActionMap *actionmap)
{
LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
wm_xr_actionmap_item_bindings_clear(ami);
wm_xr_actionmap_item_properties_free(ami);
wm_xr_actionmap_item_clear(ami);
}
BLI_freelistN(&actionmap->items);
actionmap->selitem = 0;
}
@ -494,9 +503,7 @@ void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
WM_xr_actionmap_clear(am);
}
BLI_freelistN(&runtime->actionmaps);
runtime->actactionmap = runtime->selactionmap = 0;
}

View File

@ -114,12 +114,8 @@ typedef struct wmXrDrawData {
typedef struct wmXrController {
struct wmXrController *next, *prev;
/** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256).
This subaction path will later be combined with a component path, and that combined path should
also have a max of XR_MAX_PATH_LENGTH (e.g. subaction_path = /user/hand/left, component_path =
/input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
*/
char subaction_path[64];
/** OpenXR user path identifier. */
char subaction_path[64]; /* XR_MAX_USER_PATH_LENGTH */
/** Pose (in world space) that represents the user's hand when holding the controller. */
GHOST_XrPose grip_pose;

View File

@ -1188,8 +1188,9 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
&state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat);
}
int ret = GHOST_XrSyncActions(xr_context, active_action_set ? active_action_set->name : NULL);
if (!ret) {
const bool synced = GHOST_XrSyncActions(xr_context,
active_action_set ? active_action_set->name : NULL);
if (!synced) {
return;
}

View File

@ -319,16 +319,23 @@ elseif(WIN32)
elseif(APPLE)
if(WITH_PYTHON_MODULE)
if(WITH_INSTALL_PORTABLE)
set(BPY_INSTALL_DIR)
set(TARGETDIR_VER $<TARGET_FILE_DIR:blender>/../Resources/${BLENDER_VERSION})
# Keep the `BLENDER_VERSION` folder and bpy.so in the build folder.
set(INSTALL_BPY_TO_SITE_PACKAGES OFF)
else()
set(TARGETDIR_VER "${PYTHON_LIBPATH}/Resources/${BLENDER_VERSION}")
# Parent directory of bpy.so for installation.
set(BPY_INSTALL_DIR ${PYTHON_LIBPATH}/site-packages)
# Defined in terms of site-packages since the site-packages
# directory can be a symlink (brew for example).
set(TARGETDIR_VER "${BPY_INSTALL_DIR}/../Resources/${BLENDER_VERSION}")
set(INSTALL_BPY_TO_SITE_PACKAGES ON)
endif()
else()
set(TARGETDIR_VER Blender.app/Contents/Resources/${BLENDER_VERSION})
endif()
# License, copyright, readme files.
set(BLENDER_TEXT_FILES_DESTINATION "${TARGETDIR_VER}/../text")
set(MAC_BLENDER_TARGET_DYLIBS_DIR "${TARGETDIR_VER}/lib")
# Skip relinking on cpack / install
set_target_properties(blender PROPERTIES BUILD_WITH_INSTALL_RPATH true)
@ -1052,9 +1059,6 @@ elseif(APPLE)
DESTINATION "."
)
# install release and app files
set(BLENDER_TEXT_FILES_DESTINATION Blender.app/Contents/Resources/text)
install(
FILES ${OSX_APP_SOURCEDIR}/Contents/PkgInfo
DESTINATION Blender.app/Contents
@ -1108,11 +1112,12 @@ elseif(APPLE)
)
unset(_py_inc_suffix)
endif()
if(WITH_PYTHON_MODULE)
if(INSTALL_BPY_TO_SITE_PACKAGES)
install(
TARGETS blender
LIBRARY DESTINATION ${PYTHON_LIBPATH}/site-packages
LIBRARY DESTINATION ${BPY_INSTALL_DIR}
)
endif()
endif()