Merge branch 'bf-blender' into main

This commit is contained in:
Jaume Bellet 2023-12-16 11:10:41 +01:00
commit 5104519898
815 changed files with 81706 additions and 47635 deletions

View File

@ -760,8 +760,8 @@ endif()
# Unit testing
option(WITH_GTESTS "Enable GTest unit testing" OFF)
option(WITH_OPENGL_RENDER_TESTS "Enable OpenGL render related unit testing (Experimental)" OFF)
option(WITH_OPENGL_DRAW_TESTS "Enable OpenGL UI drawing related unit testing (Experimental)" OFF)
option(WITH_GPU_RENDER_TESTS "Enable GPU render related unit testing (EEVEE, Workbench and Grease Pencil)" OFF)
option(WITH_GPU_DRAW_TESTS "Enable GPU drawing related unit testing (GPU backends and draw manager)" OFF)
option(WITH_COMPOSITOR_REALTIME_TESTS "Enable regression testing for realtime compositor" OFF)
if(UNIX AND NOT (APPLE OR HAIKU))
option(WITH_UI_TESTS "\

View File

@ -17,6 +17,7 @@ ExternalProject_Add(external_ocloc
PREFIX ${BUILD_DIR}/ocloc
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${LIBDIR}/ocloc ${DEFAULT_CMAKE_FLAGS} ${OCLOC_EXTRA_ARGS}
INSTALL_DIR ${LIBDIR}/ocloc
PATCH_COMMAND ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/ocloc/src/external_ocloc/ < ${PATCH_DIR}/ocloc.diff
)
add_dependencies(

View File

@ -14,6 +14,7 @@ if(NOT APPLE)
${OIDN_EXTRA_ARGS}
-DOIDN_DEVICE_SYCL=ON
-DOIDN_DEVICE_SYCL_AOT=OFF
-DOIDN_DEVICE_HIP=ON
-DLEVEL_ZERO_ROOT=${LIBDIR}/level-zero/lib
)
endif()

View File

@ -47,12 +47,6 @@ set(OPENVDB_EXTRA_ARGS
)
set(OPENVDB_PATCH ${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb.diff)
if(APPLE)
set(OPENVDB_PATCH
${OPENVDB_PATCH} &&
${PATCH_CMD} -p 1 -d ${BUILD_DIR}/openvdb/src/openvdb < ${PATCH_DIR}/openvdb_metal.diff
)
endif()
ExternalProject_Add(openvdb
URL file://${PACKAGE_DIR}/${OPENVDB_FILE}

View File

@ -0,0 +1,14 @@
diff --git a/shared/offline_compiler/source/ocloc_fatbinary.cpp b/shared/offline_compiler/source/ocloc_fatbinary.cpp
index 98a1c0e..4d9b5b0 100644
--- a/shared/offline_compiler/source/ocloc_fatbinary.cpp
+++ b/shared/offline_compiler/source/ocloc_fatbinary.cpp
@@ -286,7 +286,9 @@ int buildFatBinaryForTarget(int retVal, const std::vector<std::string> &argsCopy
productConfig = ProductConfigHelper::parseMajorMinorRevisionValue(argHelper->productConfigHelper->getProductConfigFromDeviceName(product));
}
- fatbinary.appendFileEntry(pointerSize + "." + productConfig, pCompiler->getPackedDeviceBinaryOutput());
+ // Storing binaries under the hardware prefix instead of the full architecture version number,
+ // as they would otherwise be ignored if they do not fully match that of the execution device.
+ fatbinary.appendFileEntry(pointerSize + "." + NEO::hardwarePrefix[argHelper->productConfigHelper->getProductFamilyFromDeviceName(productConfig)], pCompiler->getPackedDeviceBinaryOutput());
return retVal;
}

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@ buildbot:
optix:
version: '7.3.0'
ocloc:
version: '101.4723'
version: '101.4723p0'
cmake:
default:
version: any

View File

@ -17,8 +17,8 @@ if NOT "%1" == "" (
shift /1
) else if "%1" == "with_tests" (
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GTESTS=On
) else if "%1" == "with_opengl_tests" (
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_OPENGL_DRAW_TESTS=On -DWITH_OPENGL_RENDER_TESTS=On
) else if "%1" == "with_gpu_tests" (
set TESTS_CMAKE_ARGS=%TESTS_CMAKE_ARGS% -DWITH_GPU_DRAW_TESTS=On -DWITH_GPU_RENDER_TESTS=On
) else if "%1" == "full" (
set TARGET=Full
set BUILD_CMAKE_ARGS=%BUILD_CMAKE_ARGS% ^

View File

@ -39,7 +39,7 @@ echo - doc_py ^(Generate sphinx python api docs^)
echo.
echo Experimental options
echo - with_opengl_tests ^(enable both the render and draw opengl test suites^)
echo - with_gpu_tests ^(enable both the render and draw gpu test suites including EEVEE, Workbench, Grease Pencil, draw manager and GPU backends^)
echo - clang ^(enable building with clang^)
echo - asan ^(enable asan when building with clang^)
echo - ninja ^(enable building with ninja instead of msbuild^)

View File

@ -7,4 +7,5 @@ GPL-2.0-or-later GPL-license.txt https://spdx.org/licenses/GP
GPL-3.0-or-later GPL3-license.txt https://spdx.org/licenses/GPL-3.0-or-later.html
LGPL-2.1-or-later LGPL2.1-license.txt https://spdx.org/licenses/LGPL-2.1-or-later.html
MIT MIT-license.txt https://spdx.org/licenses/MIT.html
MPL-2.0 MPL-2.0.txt https://spdx.org/licenses/MPL-2.0.html
Zlib Zlib-license.txt https://spdx.org/licenses/Zlib.html

View File

@ -191,13 +191,6 @@ if(CXX_HAS_AVX2)
add_definitions(-DWITH_KERNEL_AVX2)
endif()
# LLVM and OSL need to build without RTTI
if(WIN32 AND MSVC)
set(RTTI_DISABLE_FLAGS "/GR- -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
elseif(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
set(RTTI_DISABLE_FLAGS "-fno-rtti -DBOOST_NO_RTTI -DBOOST_NO_TYPEID")
endif()
# Definitions and Includes
add_definitions(

View File

@ -2272,6 +2272,7 @@ class CYCLES_RENDER_PT_simplify_viewport(CyclesButtonsPanel, Panel):
col.prop(rd, "simplify_child_particles", text="Child Particles")
col.prop(cscene, "texture_limit", text="Texture Limit")
col.prop(rd, "simplify_volumes", text="Volume Resolution")
col.prop(rd, "use_simplify_normals", text="Normals")
class CYCLES_RENDER_PT_simplify_render(CyclesButtonsPanel, Panel):

View File

@ -326,13 +326,13 @@ static void attr_create_generic(Scene *scene,
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
const MLoopTri &lt = looptris[i];
data[i * 3 + 0] = make_uchar4(
src[tri.tri[0]][0], src[tri.tri[0]][1], src[tri.tri[0]][2], src[tri.tri[0]][3]);
src[lt.tri[0]][0], src[lt.tri[0]][1], src[lt.tri[0]][2], src[lt.tri[0]][3]);
data[i * 3 + 1] = make_uchar4(
src[tri.tri[1]][0], src[tri.tri[1]][1], src[tri.tri[1]][2], src[tri.tri[1]][3]);
src[lt.tri[1]][0], src[lt.tri[1]][1], src[lt.tri[1]][2], src[lt.tri[1]][3]);
data[i * 3 + 2] = make_uchar4(
src[tri.tri[2]][0], src[tri.tri[2]][1], src[tri.tri[2]][2], src[tri.tri[2]][3]);
src[lt.tri[2]][0], src[lt.tri[2]][1], src[lt.tri[2]][2], src[lt.tri[2]][3]);
}
}
return true;
@ -376,10 +376,10 @@ static void attr_create_generic(Scene *scene,
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
data[i * 3 + 0] = Converter::convert(src[tri.tri[0]]);
data[i * 3 + 1] = Converter::convert(src[tri.tri[1]]);
data[i * 3 + 2] = Converter::convert(src[tri.tri[2]]);
const MLoopTri &lt = looptris[i];
data[i * 3 + 0] = Converter::convert(src[lt.tri[0]]);
data[i * 3 + 1] = Converter::convert(src[lt.tri[1]]);
data[i * 3 + 2] = Converter::convert(src[lt.tri[2]]);
}
}
break;
@ -469,10 +469,10 @@ static void attr_create_uv_map(Scene *scene,
uv_name.c_str(), ATTR_DOMAIN_CORNER);
float2 *fdata = uv_attr->data_float2();
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[tri.tri[0]][0], b_uv_map[tri.tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[tri.tri[1]][0], b_uv_map[tri.tri[1]][1]);
fdata[i * 3 + 2] = make_float2(b_uv_map[tri.tri[2]][0], b_uv_map[tri.tri[2]][1]);
const MLoopTri &lt = looptris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[lt.tri[0]][0], b_uv_map[lt.tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[lt.tri[1]][0], b_uv_map[lt.tri[1]][1]);
fdata[i * 3 + 2] = make_float2(b_uv_map[lt.tri[2]][0], b_uv_map[lt.tri[2]][1]);
}
}
@ -915,10 +915,10 @@ static void create_mesh(Scene *scene,
const blender::Span<MLoopTri> looptris = b_mesh.looptris();
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
triangles[i * 3 + 0] = corner_verts[tri.tri[0]];
triangles[i * 3 + 1] = corner_verts[tri.tri[1]];
triangles[i * 3 + 2] = corner_verts[tri.tri[2]];
const MLoopTri &lt = looptris[i];
triangles[i * 3 + 0] = corner_verts[lt.tri[0]];
triangles[i * 3 + 1] = corner_verts[lt.tri[1]];
triangles[i * 3 + 2] = corner_verts[lt.tri[2]];
}
if (!material_indices.is_empty()) {
@ -944,9 +944,9 @@ static void create_mesh(Scene *scene,
if (use_loop_normals && !corner_normals.is_empty()) {
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
const MLoopTri &lt = looptris[i];
for (int i = 0; i < 3; i++) {
const int corner = tri.tri[i];
const int corner = lt.tri[i];
const int vert = corner_verts[corner];
const float *normal = corner_normals[corner];
N[vert] = make_float3(normal[0], normal[1], normal[2]);

View File

@ -313,7 +313,7 @@ void CPUDevice::get_cpu_kernel_thread_globals(
kernel_thread_globals.clear();
void *osl_memory = get_cpu_osl_memory();
for (int i = 0; i < info.cpu_threads; i++) {
kernel_thread_globals.emplace_back(kernel_globals, osl_memory, profiler);
kernel_thread_globals.emplace_back(kernel_globals, osl_memory, profiler, i);
}
}

View File

@ -60,7 +60,7 @@ class CPUKernels {
int x,
int y,
float threshold,
bool reset,
int reset,
int offset,
int stride)>;

View File

@ -12,14 +12,16 @@ CCL_NAMESPACE_BEGIN
CPUKernelThreadGlobals::CPUKernelThreadGlobals(const KernelGlobalsCPU &kernel_globals,
void *osl_globals_memory,
Profiler &cpu_profiler)
Profiler &cpu_profiler,
const int thread_index)
: KernelGlobalsCPU(kernel_globals), cpu_profiler_(cpu_profiler)
{
clear_runtime_pointers();
#ifdef WITH_OSL
OSLGlobals::thread_init(this, static_cast<OSLGlobals *>(osl_globals_memory));
OSLGlobals::thread_init(this, static_cast<OSLGlobals *>(osl_globals_memory), thread_index);
#else
(void)thread_index;
(void)osl_globals_memory;
#endif

View File

@ -23,7 +23,8 @@ class CPUKernelThreadGlobals : public KernelGlobalsCPU {
* without OSL support. Will avoid need to those unnamed pointers and casts. */
CPUKernelThreadGlobals(const KernelGlobalsCPU &kernel_globals,
void *osl_globals_memory,
Profiler &cpu_profiler);
Profiler &cpu_profiler,
const int thread_index);
~CPUKernelThreadGlobals();

View File

@ -10,6 +10,8 @@
# include "device/device.h"
# include "device/hip/device_impl.h"
# include "integrator/denoiser_oidn_gpu.h"
# include "util/string.h"
# include "util/windows.h"
#endif /* WITH_HIP */
@ -158,6 +160,11 @@ void device_hip_info(vector<DeviceInfo> &devices)
info.has_light_tree = true;
info.has_mnee = true;
info.denoisers = 0;
# if defined(WITH_OPENIMAGEDENOISE)
if (OIDNDenoiserGPU::is_device_supported(info)) {
info.denoisers |= DENOISER_OPENIMAGEDENOISE;
}
# endif
info.has_gpu_queue = true;
/* Check if the device has P2P access to any other device in the system. */

View File

@ -73,7 +73,7 @@ class MetalDevice : public Device {
/* Bindless Textures */
bool is_texture(const TextureInfo &tex);
device_vector<TextureInfo> texture_info;
bool need_texture_info;
bool need_texture_info = false;
id<MTLArgumentEncoder> mtlTextureArgEncoder = nil;
id<MTLArgumentEncoder> mtlBufferArgEncoder = nil;
id<MTLBuffer> buffer_bindings_1d = nil;

View File

@ -40,7 +40,7 @@ class OneapiDeviceQueue : public DeviceQueue {
virtual void copy_to_device(device_memory &mem) override;
virtual void copy_from_device(device_memory &mem) override;
virtual bool supports_local_atomic_sort() const
virtual bool supports_local_atomic_sort() const override
{
return true;
}

View File

@ -27,7 +27,6 @@ struct DeviceKernelArguments {
POINTER,
INT32,
FLOAT32,
BOOLEAN,
KERNEL_FILM_CONVERT,
};
@ -66,10 +65,6 @@ struct DeviceKernelArguments {
{
add(FLOAT32, value, sizeof(float));
}
void add(const bool *value)
{
add(BOOLEAN, value, 4);
}
void add(const Type type, const void *value, size_t size)
{
assert(count < MAX_ARGS);

View File

@ -27,7 +27,9 @@ unique_ptr<Denoiser> Denoiser::create(Device *path_trace_device, const DenoisePa
#endif
#ifdef WITH_OPENIMAGEDENOISE
if (params.type == DENOISER_OPENIMAGEDENOISE && path_trace_device->info.type == DEVICE_ONEAPI) {
if (params.type == DENOISER_OPENIMAGEDENOISE && path_trace_device->info.type != DEVICE_CPU &&
OIDNDenoiserGPU::is_device_supported(path_trace_device->info))
{
return make_unique<OIDNDenoiserGPU>(path_trace_device, params);
}
#endif

View File

@ -103,7 +103,7 @@ class DenoiserGPU : public Denoiser {
int denoised_offset;
int num_components;
bool use_compositing;
int use_compositing;
bool use_denoising_albedo;
};

View File

@ -30,16 +30,48 @@ CCL_NAMESPACE_BEGIN
bool OIDNDenoiserGPU::is_device_supported(const DeviceInfo &device)
{
/* Currently falls back to checking just the device type, can be improved. */
int device_type = OIDN_DEVICE_TYPE_DEFAULT;
switch (device.type) {
# ifdef OIDN_DEVICE_SYCL
/* Assume all devices with Cycles support are also supported by OIDN2. */
case DEVICE_ONEAPI:
return true;
device_type = OIDN_DEVICE_TYPE_SYCL;
break;
# endif
# ifdef OIDN_DEVICE_HIP
case DEVICE_HIP:
device_type = OIDN_DEVICE_TYPE_HIP;
break;
# endif
# ifdef OIDN_DEVICE_CUDA
case DEVICE_CUDA:
case DEVICE_OPTIX:
device_type = OIDN_DEVICE_TYPE_CUDA;
break;
# endif
case DEVICE_CPU:
/* This is the GPU denoiser - CPU devices shouldn't end up here. */
assert(0);
default:
return false;
}
/* Match GPUs by their PCI ID. */
const int num_devices = oidnGetNumPhysicalDevices();
for (int i = 0; i < num_devices; i++) {
if (oidnGetPhysicalDeviceInt(i, "type") == device_type) {
if (oidnGetPhysicalDeviceBool(i, "pciAddressSupported")) {
unsigned int pci_domain = oidnGetPhysicalDeviceInt(i, "pciDomain");
unsigned int pci_bus = oidnGetPhysicalDeviceInt(i, "pciBus");
unsigned int pci_device = oidnGetPhysicalDeviceInt(i, "pciDevice");
string pci_id = string_printf("%04x:%02x:%02x", pci_domain, pci_bus, pci_device);
if (device.id.find(pci_id) != string::npos) {
return true;
}
}
}
}
return false;
}
OIDNDenoiserGPU::OIDNDenoiserGPU(Device *path_trace_device, const DenoiseParams &params)
@ -78,6 +110,9 @@ uint OIDNDenoiserGPU::get_device_type_mask() const
uint device_mask = 0;
# ifdef OIDN_DEVICE_SYCL
device_mask |= DEVICE_MASK_ONEAPI;
# endif
# ifdef OIDN_DEVICE_HIP
device_mask |= DEVICE_MASK_HIP;
# endif
return device_mask;
}
@ -122,15 +157,27 @@ bool OIDNDenoiserGPU::denoise_create_if_needed(DenoiseContext &context)
1);
denoiser_queue_->init_execution();
break;
# endif
# if defined(OIDN_DEVICE_HIP) && defined(WITH_HIP)
case DEVICE_HIP: {
hipStream_t stream = nullptr;
oidn_device_ = oidnNewHIPDevice(&denoiser_device_->info.num, &stream, 1);
break;
}
# endif
default:
break;
}
if (!oidn_device_) {
denoiser_device_->set_error("Failed to create OIDN device");
return false;
}
if (denoiser_queue_) {
denoiser_queue_->init_execution();
}
oidnCommitDevice(oidn_device_);
oidn_filter_ = create_filter();

View File

@ -1055,6 +1055,7 @@ int PathTraceWorkGPU::adaptive_sampling_convergence_check_count_active(float thr
queue_->zero_to_device(num_active_pixels);
const int work_size = effective_buffer_params_.width * effective_buffer_params_.height;
const int reset_int = reset; /* No bool kernel arguments. */
DeviceKernelArguments args(&buffers_->buffer.device_pointer,
&effective_buffer_params_.full_x,
@ -1062,7 +1063,7 @@ int PathTraceWorkGPU::adaptive_sampling_convergence_check_count_active(float thr
&effective_buffer_params_.width,
&effective_buffer_params_.height,
&threshold,
&reset,
&reset_int,
&effective_buffer_params_.offset,
&effective_buffer_params_.stride,
&num_active_pixels.device_pointer);

View File

@ -327,6 +327,7 @@ set(SRC_KERNEL_UTIL_HEADERS
util/color.h
util/differential.h
util/lookup_table.h
util/nanovdb.h
util/profiling.h
)
@ -483,8 +484,7 @@ if(WITH_CYCLES_CUDA_BINARIES)
if(WITH_NANOVDB)
set(cuda_flags ${cuda_flags}
-D WITH_NANOVDB
-I "${NANOVDB_INCLUDE_DIR}")
-D WITH_NANOVDB)
endif()
if(WITH_CYCLES_DEBUG)
@ -634,8 +634,7 @@ if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP)
if(WITH_NANOVDB)
set(hip_flags ${hip_flags}
-D WITH_NANOVDB
-I "${NANOVDB_INCLUDE_DIR}")
-D WITH_NANOVDB)
endif()
if(WITH_CYCLES_DEBUG)
@ -755,8 +754,7 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES)
if(WITH_NANOVDB)
set(cuda_flags ${cuda_flags}
-D WITH_NANOVDB
-I "${NANOVDB_INCLUDE_DIR}")
-D WITH_NANOVDB)
endif()
if(WITH_CYCLES_OSL)
set(cuda_flags ${cuda_flags}
@ -936,8 +934,7 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
if(WITH_NANOVDB)
list(APPEND sycl_compiler_flags
-DWITH_NANOVDB
-I"${NANOVDB_INCLUDE_DIR}")
-DWITH_NANOVDB)
endif()
if(WITH_CYCLES_EMBREE AND EMBREE_SYCL_SUPPORT)
@ -1256,16 +1253,3 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_SVM_HEADERS}" ${CYCLES
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_TYPES_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/util)
delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/util)
if(WITH_NANOVDB)
set(SRC_NANOVDB_HEADERS
nanovdb/NanoVDB.h
nanovdb/CNanoVDB.h
)
set(SRC_NANOVDB_UTIL_HEADERS
nanovdb/util/CSampleFromVoxels.h
nanovdb/util/SampleFromVoxels.h
)
delayed_install(${NANOVDB_INCLUDE_DIR} "${SRC_NANOVDB_HEADERS}" ${CYCLES_INSTALL_PATH}/source/nanovdb)
delayed_install(${NANOVDB_INCLUDE_DIR} "${SRC_NANOVDB_UTIL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/nanovdb/util)
endif()

View File

@ -49,6 +49,7 @@ typedef struct KernelGlobalsCPU {
OSLGlobals *osl = nullptr;
OSLShadingSystem *osl_ss = nullptr;
OSLThreadData *osl_tdata = nullptr;
int osl_thread_index = 0;
#endif
#ifdef __PATH_GUIDING__

View File

@ -5,9 +5,7 @@
#pragma once
#ifdef WITH_NANOVDB
# define NANOVDB_USE_INTRINSICS
# include <nanovdb/NanoVDB.h>
# include <nanovdb/util/SampleFromVoxels.h>
# include "kernel/util/nanovdb.h"
#endif
CCL_NAMESPACE_BEGIN
@ -685,46 +683,59 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
};
#ifdef WITH_NANOVDB
template<typename TexT, typename OutT = float4> struct NanoVDBInterpolator {
typedef typename nanovdb::NanoGrid<TexT>::AccessorType AccessorType;
template<typename TexT, typename OutT> struct NanoVDBInterpolator {
static ccl_always_inline float read(float r)
{
return r;
}
static ccl_always_inline float4 read(nanovdb::Vec3f r)
static ccl_always_inline float4 read(const packed_float3 r)
{
return make_float4(r[0], r[1], r[2], 1.0f);
return make_float4(r.x, r.y, r.z, 1.0f);
}
static ccl_always_inline OutT interp_3d_closest(const AccessorType &acc,
float x,
float y,
float z)
template<typename Acc>
static ccl_always_inline OutT interp_3d_closest(const Acc &acc, float x, float y, float z)
{
const nanovdb::Vec3f xyz(x, y, z);
return read(nanovdb::SampleFromVoxels<AccessorType, 0, false>(acc)(xyz));
const nanovdb::Coord coord((int32_t)floorf(x), (int32_t)floorf(y), (int32_t)floorf(z));
return read(acc.getValue(coord));
}
static ccl_always_inline OutT interp_3d_linear(const AccessorType &acc,
float x,
float y,
float z)
template<typename Acc>
static ccl_always_inline OutT interp_3d_linear(const Acc &acc, float x, float y, float z)
{
const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f);
return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz));
int ix, iy, iz;
const float tx = frac(x - 0.5f, &ix);
const float ty = frac(y - 0.5f, &iy);
const float tz = frac(z - 0.5f, &iz);
return mix(mix(mix(read(acc.getValue(nanovdb::Coord(ix, iy, iz))),
read(acc.getValue(nanovdb::Coord(ix, iy, iz + 1))),
tz),
mix(read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz + 1))),
read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz))),
1.0f - tz),
ty),
mix(mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz))),
read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz + 1))),
tz),
mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz + 1))),
read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz))),
1.0f - tz),
1.0f - ty),
tx);
}
/* Tricubic b-spline interpolation. */
template<typename Acc>
# if defined(__GNUC__) || defined(__clang__)
static ccl_always_inline
# else
static ccl_never_inline
# endif
OutT
interp_3d_cubic(const AccessorType &acc, float x, float y, float z)
interp_3d_cubic(const Acc &acc, float x, float y, float z)
{
int ix, iy, iz;
int nix, niy, niz;
@ -779,15 +790,20 @@ template<typename TexT, typename OutT = float4> struct NanoVDBInterpolator {
using namespace nanovdb;
NanoGrid<TexT> *const grid = (NanoGrid<TexT> *)info.data;
AccessorType acc = grid->getAccessor();
switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
case INTERPOLATION_CLOSEST:
case INTERPOLATION_CLOSEST: {
ReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_closest(acc, x, y, z);
case INTERPOLATION_LINEAR:
}
case INTERPOLATION_LINEAR: {
CachedReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_linear(acc, x, y, z);
default:
}
default: {
CachedReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_cubic(acc, x, y, z);
}
}
}
};
@ -880,7 +896,7 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
return make_float4(f, f, f, 1.0f);
}
case IMAGE_DATA_TYPE_NANOVDB_FLOAT3:
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, P.x, P.y, P.z, interp);
return NanoVDBInterpolator<packed_float3, float4>::interp_3d(info, P.x, P.y, P.z, interp);
case IMAGE_DATA_TYPE_NANOVDB_FPN: {
const float f = NanoVDBInterpolator<nanovdb::FpN, float>::interp_3d(
info, P.x, P.y, P.z, interp);

View File

@ -101,7 +101,7 @@ bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
int x,
int y,
float threshold,
bool reset,
int reset,
int offset,
int stride);

View File

@ -164,7 +164,7 @@ bool KERNEL_FUNCTION_FULL_NAME(adaptive_sampling_convergence_check)(
int x,
int y,
float threshold,
bool reset,
int reset,
int offset,
int stride)
{

View File

@ -45,6 +45,7 @@ typedef unsigned long long uint64_t;
#define ccl_global
#define ccl_inline_constant __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_static_constexpr static constexpr
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private

View File

@ -8,12 +8,17 @@ CCL_NAMESPACE_BEGIN
#if !defined __KERNEL_METAL__
# ifdef WITH_NANOVDB
# define NDEBUG /* Disable "assert" in device code */
# define NANOVDB_USE_INTRINSICS
# include "nanovdb/NanoVDB.h"
# include "nanovdb/util/SampleFromVoxels.h"
# include "kernel/util/nanovdb.h"
# endif
#endif
ccl_device_inline float frac(float x, ccl_private int *ix)
{
int i = float_to_int(x) - ((x < 0.0f) ? 1 : 0);
*ix = i;
return x - (float)i;
}
/* w0, w1, w2, and w3 are the four cubic B-spline basis functions. */
ccl_device float cubic_w0(float a)
{
@ -126,63 +131,121 @@ kernel_tex_image_interp_tricubic(ccl_global const TextureInfo &info, float x, fl
}
#ifdef WITH_NANOVDB
template<typename T, typename S>
ccl_device typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_tricubic_nanovdb(
ccl_private S &s, float x, float y, float z)
template<typename OutT, typename Acc>
ccl_device OutT
kernel_tex_image_interp_trilinear_nanovdb(ccl_private Acc &acc, float x, float y, float z)
{
float px = floorf(x);
float py = floorf(y);
float pz = floorf(z);
float fx = x - px;
float fy = y - py;
float fz = z - pz;
int ix, iy, iz;
const float tx = frac(x - 0.5f, &ix);
const float ty = frac(y - 0.5f, &iy);
const float tz = frac(z - 0.5f, &iz);
float g0x = cubic_g0(fx);
float g1x = cubic_g1(fx);
float g0y = cubic_g0(fy);
float g1y = cubic_g1(fy);
float g0z = cubic_g0(fz);
float g1z = cubic_g1(fz);
return mix(mix(mix(OutT(acc.getValue(nanovdb::Coord(ix, iy, iz))),
OutT(acc.getValue(nanovdb::Coord(ix, iy, iz + 1))),
tz),
mix(OutT(acc.getValue(nanovdb::Coord(ix, iy + 1, iz + 1))),
OutT(acc.getValue(nanovdb::Coord(ix, iy + 1, iz))),
1.0f - tz),
ty),
mix(mix(OutT(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz))),
OutT(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz + 1))),
tz),
mix(OutT(acc.getValue(nanovdb::Coord(ix + 1, iy, iz + 1))),
OutT(acc.getValue(nanovdb::Coord(ix + 1, iy, iz))),
1.0f - tz),
1.0f - ty),
tx);
}
float x0 = px + cubic_h0(fx);
float x1 = px + cubic_h1(fx);
float y0 = py + cubic_h0(fy);
float y1 = py + cubic_h1(fy);
float z0 = pz + cubic_h0(fz);
float z1 = pz + cubic_h1(fz);
template<typename OutT, typename Acc>
ccl_device OutT
kernel_tex_image_interp_tricubic_nanovdb(ccl_private Acc &acc, float x, float y, float z)
{
int ix, iy, iz;
int nix, niy, niz;
int pix, piy, piz;
int nnix, nniy, nniz;
using namespace nanovdb;
/* A -0.5 offset is used to center the cubic samples around the sample point. */
const float tx = frac(x - 0.5f, &ix);
const float ty = frac(y - 0.5f, &iy);
const float tz = frac(z - 0.5f, &iz);
return g0z * (g0y * (g0x * s(Vec3f(x0, y0, z0)) + g1x * s(Vec3f(x1, y0, z0))) +
g1y * (g0x * s(Vec3f(x0, y1, z0)) + g1x * s(Vec3f(x1, y1, z0)))) +
g1z * (g0y * (g0x * s(Vec3f(x0, y0, z1)) + g1x * s(Vec3f(x1, y0, z1))) +
g1y * (g0x * s(Vec3f(x0, y1, z1)) + g1x * s(Vec3f(x1, y1, z1))));
pix = ix - 1;
piy = iy - 1;
piz = iz - 1;
nix = ix + 1;
niy = iy + 1;
niz = iz + 1;
nnix = ix + 2;
nniy = iy + 2;
nniz = iz + 2;
const int xc[4] = {pix, ix, nix, nnix};
const int yc[4] = {piy, iy, niy, nniy};
const int zc[4] = {piz, iz, niz, nniz};
float u[4], v[4], w[4];
/* Some helper macros to keep code size reasonable.
* Lets the compiler inline all the matrix multiplications.
*/
# define SET_CUBIC_SPLINE_WEIGHTS(u, t) \
{ \
u[0] = (((-1.0f / 6.0f) * t + 0.5f) * t - 0.5f) * t + (1.0f / 6.0f); \
u[1] = ((0.5f * t - 1.0f) * t) * t + (2.0f / 3.0f); \
u[2] = ((-0.5f * t + 0.5f) * t + 0.5f) * t + (1.0f / 6.0f); \
u[3] = (1.0f / 6.0f) * t * t * t; \
} \
(void)0
# define DATA(x, y, z) (OutT(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z]))))
# define COL_TERM(col, row) \
(v[col] * (u[0] * DATA(0, col, row) + u[1] * DATA(1, col, row) + u[2] * DATA(2, col, row) + \
u[3] * DATA(3, col, row)))
# define ROW_TERM(row) \
(w[row] * (COL_TERM(0, row) + COL_TERM(1, row) + COL_TERM(2, row) + COL_TERM(3, row)))
SET_CUBIC_SPLINE_WEIGHTS(u, tx);
SET_CUBIC_SPLINE_WEIGHTS(v, ty);
SET_CUBIC_SPLINE_WEIGHTS(w, tz);
/* Actual interpolation. */
return ROW_TERM(0) + ROW_TERM(1) + ROW_TERM(2) + ROW_TERM(3);
# undef COL_TERM
# undef ROW_TERM
# undef DATA
# undef SET_CUBIC_SPLINE_WEIGHTS
}
# if defined(__KERNEL_METAL__)
template<typename T>
__attribute__((noinline)) typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_nanovdb(
template<typename OutT, typename T>
__attribute__((noinline)) OutT kernel_tex_image_interp_nanovdb(
ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation)
# else
template<typename T>
ccl_device_noinline typename nanovdb::NanoGrid<T>::ValueType kernel_tex_image_interp_nanovdb(
template<typename OutT, typename T>
ccl_device_noinline OutT kernel_tex_image_interp_nanovdb(
ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation)
# endif
{
using namespace nanovdb;
ccl_global NanoGrid<T> *const grid = (ccl_global NanoGrid<T> *)info.data;
typedef typename nanovdb::NanoGrid<T>::AccessorType AccessorType;
AccessorType acc = grid->getAccessor();
switch (interpolation) {
case INTERPOLATION_CLOSEST:
return SampleFromVoxels<AccessorType, 0, false>(acc)(Vec3f(x, y, z));
case INTERPOLATION_LINEAR:
return SampleFromVoxels<AccessorType, 1, false>(acc)(Vec3f(x - 0.5f, y - 0.5f, z - 0.5f));
default:
SampleFromVoxels<AccessorType, 1, false> s(acc);
return kernel_tex_image_interp_tricubic_nanovdb<T>(s, x - 0.5f, y - 0.5f, z - 0.5f);
case INTERPOLATION_CLOSEST: {
ReadAccessor<T> acc(grid->tree().root());
const nanovdb::Coord coord((int32_t)floorf(x), (int32_t)floorf(y), (int32_t)floorf(z));
return OutT(acc.getValue(coord));
}
case INTERPOLATION_LINEAR: {
CachedReadAccessor<T> acc(grid->tree().root());
return kernel_tex_image_interp_trilinear_nanovdb<OutT>(acc, x, y, z);
}
default: {
CachedReadAccessor<T> acc(grid->tree().root());
return kernel_tex_image_interp_tricubic_nanovdb<OutT>(acc, x, y, z);
}
}
}
#endif
@ -240,20 +303,20 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg,
#ifdef WITH_NANOVDB
if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
float f = kernel_tex_image_interp_nanovdb<float>(info, x, y, z, interpolation);
float f = kernel_tex_image_interp_nanovdb<float, float>(info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
nanovdb::Vec3f f = kernel_tex_image_interp_nanovdb<nanovdb::Vec3f>(
float3 f = kernel_tex_image_interp_nanovdb<float3, packed_float3>(
info, x, y, z, interpolation);
return make_float4(f[0], f[1], f[2], 1.0f);
return make_float4(f.x, f.y, f.z, 1.0f);
}
if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
float f = kernel_tex_image_interp_nanovdb<nanovdb::FpN>(info, x, y, z, interpolation);
float f = kernel_tex_image_interp_nanovdb<float, nanovdb::FpN>(info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
if (texture_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
float f = kernel_tex_image_interp_nanovdb<nanovdb::Fp16>(info, x, y, z, interpolation);
float f = kernel_tex_image_interp_nanovdb<float, nanovdb::Fp16>(info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
#endif

View File

@ -668,7 +668,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
int sw,
int sh,
float threshold,
bool reset,
int reset,
int offset,
int stride,
ccl_global uint *num_active_pixels)
@ -1104,7 +1104,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS)
int pass_denoised,
int pass_sample_count,
int num_components,
bool use_compositing)
int use_compositing)
{
const int work_index = ccl_gpu_global_id_x();
const int y = work_index / width;

View File

@ -38,6 +38,7 @@ typedef unsigned long long uint64_t;
#define ccl_global
#define ccl_inline_constant __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_static_constexpr static constexpr
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private

View File

@ -47,6 +47,7 @@ using namespace metal::raytracing;
#define ccl_global device
#define ccl_inline_constant static constant constexpr
#define ccl_device_constant constant
#define ccl_static_constexpr static constant constexpr
#define ccl_constant constant
#define ccl_gpu_shared threadgroup
#define ccl_private thread

View File

@ -5,10 +5,7 @@
// clang-format off
#ifdef WITH_NANOVDB
# define NDEBUG /* Disable "assert" in device code */
# define NANOVDB_USE_INTRINSICS
# include "nanovdb/NanoVDB.h"
# include "nanovdb/util/SampleFromVoxels.h"
# include "kernel/util/nanovdb.h"
#endif
/* Open the Metal kernel context class

View File

@ -40,7 +40,8 @@
#define ccl_device_inline inline
#define ccl_noinline __attribute__((noinline))
#define ccl_inline_constant const constexpr
#define ccl_static_constant const
#define ccl_device_constant static constexpr
#define ccl_static_constexpr static constexpr
#define ccl_device_forceinline __attribute__((always_inline))
#define ccl_device_noinline ccl_device ccl_noinline
#define ccl_device_noinline_cpu ccl_device

View File

@ -34,8 +34,7 @@ typedef struct ccl_vdb_double_t {
} ccl_vdb_double_t;
# define double ccl_vdb_double_t
# include <nanovdb/NanoVDB.h>
# include <nanovdb/util/SampleFromVoxels.h>
# include "kernel/util/nanovdb.h"
# undef double
#endif

View File

@ -202,48 +202,64 @@ ccl_device float4 kernel_tex_image_interp(KernelGlobals, int id, float x, float
}
#ifdef WITH_NANOVDB
template<typename T> struct NanoVDBInterpolator {
template<typename TexT, typename OutT> struct NanoVDBInterpolator {
typedef typename nanovdb::NanoGrid<T>::AccessorType AccessorType;
static ccl_always_inline float4 read(float r)
static ccl_always_inline float read(float r)
{
return make_float4(r, r, r, 1.0f);
return r;
}
static ccl_always_inline float4 read(nanovdb::Vec3f r)
static ccl_always_inline float4 read(const packed_float3 r)
{
return make_float4(r[0], r[1], r[2], 1.0f);
return make_float4(r.x, r.y, r.z, 1.0f);
}
static ccl_always_inline float4 interp_3d_closest(const AccessorType &acc,
float x,
float y,
float z)
template<typename Acc>
static ccl_always_inline OutT interp_3d_closest(const Acc &acc, float x, float y, float z)
{
const nanovdb::Vec3f xyz(x, y, z);
return read(nanovdb::SampleFromVoxels<AccessorType, 0, false>(acc)(xyz));
const nanovdb::Coord coord(int32_t(rintf(x)), int32_t(rintf(y)), int32_t(rintf(z)));
return read(acc.getValue(coord));
}
static ccl_always_inline float4 interp_3d_linear(const AccessorType &acc,
float x,
float y,
float z)
template<typename Acc>
static ccl_always_inline OutT interp_3d_linear(const Acc &acc, float x, float y, float z)
{
const nanovdb::Vec3f xyz(x - 0.5f, y - 0.5f, z - 0.5f);
return read(nanovdb::SampleFromVoxels<AccessorType, 1, false>(acc)(xyz));
int ix, iy, iz;
const float tx = svm_image_texture_frac(x - 0.5f, &ix);
const float ty = svm_image_texture_frac(y - 0.5f, &iy);
const float tz = svm_image_texture_frac(z - 0.5f, &iz);
return mix(mix(mix(read(acc.getValue(nanovdb::Coord(ix, iy, iz))),
read(acc.getValue(nanovdb::Coord(ix, iy, iz + 1))),
tz),
mix(read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz + 1))),
read(acc.getValue(nanovdb::Coord(ix, iy + 1, iz))),
1.0f - tz),
ty),
mix(mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz))),
read(acc.getValue(nanovdb::Coord(ix + 1, iy + 1, iz + 1))),
tz),
mix(read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz + 1))),
read(acc.getValue(nanovdb::Coord(ix + 1, iy, iz))),
1.0f - tz),
1.0f - ty),
tx);
}
static float4 interp_3d_cubic(const AccessorType &acc, float x, float y, float z)
/* Tricubic b-spline interpolation. */
template<typename Acc>
static ccl_always_inline OutT interp_3d_cubic(const Acc &acc, float x, float y, float z)
{
int ix, iy, iz;
int nix, niy, niz;
int pix, piy, piz;
int nnix, nniy, nniz;
/* Tri-cubic b-spline interpolation. */
/* A -0.5 offset is used to center the cubic samples around the sample point. */
const float tx = svm_image_texture_frac(x - 0.5f, &ix);
const float ty = svm_image_texture_frac(y - 0.5f, &iy);
const float tz = svm_image_texture_frac(z - 0.5f, &iz);
pix = ix - 1;
piy = iy - 1;
piz = iz - 1;
@ -259,8 +275,8 @@ template<typename T> struct NanoVDBInterpolator {
const int zc[4] = {piz, iz, niz, nniz};
float u[4], v[4], w[4];
/* Some helper macro to keep code reasonable size,
* let compiler to inline all the matrix multiplications.
/* Some helper macros to keep code size reasonable.
* Lets the compiler inline all the matrix multiplications.
*/
# define DATA(x, y, z) (read(acc.getValue(nanovdb::Coord(xc[x], yc[y], zc[z]))))
# define COL_TERM(col, row) \
@ -281,21 +297,26 @@ template<typename T> struct NanoVDBInterpolator {
# undef DATA
}
static ccl_always_inline float4
static ccl_always_inline OutT
interp_3d(const TextureInfo &info, float x, float y, float z, int interp)
{
using namespace nanovdb;
NanoGrid<T> *const grid = (NanoGrid<T> *)info.data;
AccessorType acc = grid->getAccessor();
NanoGrid<TexT> *const grid = (NanoGrid<TexT> *)info.data;
switch ((interp == INTERPOLATION_NONE) ? info.interpolation : interp) {
case INTERPOLATION_CLOSEST:
switch (interp) {
case INTERPOLATION_CLOSEST: {
ReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_closest(acc, x, y, z);
case INTERPOLATION_LINEAR:
}
case INTERPOLATION_LINEAR: {
CachedReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_linear(acc, x, y, z);
default:
}
default: {
CachedReadAccessor<TexT> acc(grid->tree().root());
return interp_3d_cubic(acc, x, y, z);
}
}
}
};
@ -318,16 +339,21 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals, int id, float3 P, in
#ifdef WITH_NANOVDB
if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT) {
return NanoVDBInterpolator<float>::interp_3d(info, x, y, z, interpolation);
const float f = NanoVDBInterpolator<float, float>::interp_3d(info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT3) {
return NanoVDBInterpolator<nanovdb::Vec3f>::interp_3d(info, x, y, z, interpolation);
return NanoVDBInterpolator<packed_float3, float4>::interp_3d(info, x, y, z, interpolation);
}
else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FPN) {
return NanoVDBInterpolator<nanovdb::FpN>::interp_3d(info, x, y, z, interpolation);
const float f = NanoVDBInterpolator<nanovdb::FpN, float>::interp_3d(
info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
else if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FP16) {
return NanoVDBInterpolator<nanovdb::Fp16>::interp_3d(info, x, y, z, interpolation);
const float f = NanoVDBInterpolator<nanovdb::Fp16, float>::interp_3d(
info, x, y, z, interpolation);
return make_float4(f, f, f, 1.0f);
}
#else
if (info.data_type == IMAGE_DATA_TYPE_NANOVDB_FLOAT ||

View File

@ -45,6 +45,7 @@ typedef unsigned long long uint64_t;
#define ccl_global
#define ccl_inline_constant static __constant__
#define ccl_device_constant __constant__ __device__
#define ccl_static_constexpr static constexpr
#define ccl_constant const
#define ccl_gpu_shared __shared__
#define ccl_private

View File

@ -34,7 +34,7 @@ ccl_device bool film_adaptive_sampling_convergence_check(KernelGlobals kg,
int x,
int y,
float threshold,
bool reset,
int reset,
int offset,
int stride)
{

View File

@ -36,9 +36,6 @@ set(LIB
${LLVM_LIBRARY}
)
# OSL and LLVM are built without RTTI
string(APPEND CMAKE_CXX_FLAGS " ${RTTI_DISABLE_FLAGS}")
if(APPLE)
# Disable allocation warning on macOS prior to 10.14: the OSLRenderServices
# contains member which is 64 bytes aligned (cache inside of OIIO's

View File

@ -110,7 +110,17 @@ void osl_eval_nodes<SHADER_TYPE_SURFACE>(const KernelGlobalsCPU *kg,
if (sd->object == OBJECT_NONE && sd->lamp == LAMP_NONE) {
/* background */
if (kg->osl->background_state) {
#if OSL_LIBRARY_VERSION_CODE >= 11304
ss->execute(*octx,
*(kg->osl->background_state),
kg->osl_thread_index,
0,
*globals,
nullptr,
nullptr);
#else
ss->execute(octx, *(kg->osl->background_state), *globals);
#endif
}
}
else {
@ -150,8 +160,18 @@ void osl_eval_nodes<SHADER_TYPE_SURFACE>(const KernelGlobalsCPU *kg,
globals->dPdy = TO_VEC3(tmp_dP.dy);
}
/* execute bump shader */
/* execute bump shader */
#if OSL_LIBRARY_VERSION_CODE >= 11304
ss->execute(*octx,
*(kg->osl->bump_state[shader]),
kg->osl_thread_index,
0,
*globals,
nullptr,
nullptr);
#else
ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
#endif
/* reset state */
sd->P = P;
@ -164,7 +184,17 @@ void osl_eval_nodes<SHADER_TYPE_SURFACE>(const KernelGlobalsCPU *kg,
/* surface shader */
if (kg->osl->surface_state[shader]) {
#if OSL_LIBRARY_VERSION_CODE >= 11304
ss->execute(*octx,
*(kg->osl->surface_state[shader]),
kg->osl_thread_index,
0,
*globals,
nullptr,
nullptr);
#else
ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
#endif
}
}
@ -208,7 +238,17 @@ void osl_eval_nodes<SHADER_TYPE_VOLUME>(const KernelGlobalsCPU *kg,
int shader = sd->shader & SHADER_MASK;
if (kg->osl->volume_state[shader]) {
#if OSL_LIBRARY_VERSION_CODE >= 11304
ss->execute(*octx,
*(kg->osl->volume_state[shader]),
kg->osl_thread_index,
0,
*globals,
nullptr,
nullptr);
#else
ss->execute(octx, *(kg->osl->volume_state[shader]), *globals);
#endif
}
/* flatten closure tree */
@ -245,7 +285,17 @@ void osl_eval_nodes<SHADER_TYPE_DISPLACEMENT>(const KernelGlobalsCPU *kg,
int shader = sd->shader & SHADER_MASK;
if (kg->osl->displacement_state[shader]) {
#if OSL_LIBRARY_VERSION_CODE >= 11304
ss->execute(*octx,
*(kg->osl->displacement_state[shader]),
kg->osl_thread_index,
0,
*globals,
nullptr,
nullptr);
#else
ss->execute(octx, *(kg->osl->displacement_state[shader]), *globals);
#endif
}
/* get back position */

View File

@ -14,7 +14,7 @@
CCL_NAMESPACE_BEGIN
void OSLGlobals::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals)
void OSLGlobals::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals, const int thread_index)
{
/* no osl used? */
if (!osl_globals->use) {
@ -37,6 +37,7 @@ void OSLGlobals::thread_init(KernelGlobalsCPU *kg, OSLGlobals *osl_globals)
kg->osl_ss = (OSLShadingSystem *)ss;
kg->osl_tdata = tdata;
kg->osl_thread_index = thread_index;
}
void OSLGlobals::thread_free(KernelGlobalsCPU *kg)

View File

@ -45,7 +45,9 @@ struct OSLGlobals {
}
/* per thread data */
static void thread_init(struct KernelGlobalsCPU *kg, OSLGlobals *osl_globals);
static void thread_init(struct KernelGlobalsCPU *kg,
OSLGlobals *osl_globals,
const int thread_init);
static void thread_free(struct KernelGlobalsCPU *kg);
bool use;

View File

@ -52,6 +52,11 @@ ccl_device_inline void shaderdata_to_shaderglobals(KernelGlobals kg,
/* shader data to be used in services callbacks */
globals->renderstate = sd;
#if OSL_LIBRARY_VERSION_CODE >= 11304
globals->shadingStateUniform = nullptr;
globals->thread_index = 0;
globals->shade_index = 0;
#endif
/* hacky, we leave it to services to fetch actual object matrix */
globals->shader2common = sd;

View File

@ -1165,7 +1165,18 @@ bool OSLRenderServices::get_userdata(
return false; /* disabled by lockgeom */
}
#if OSL_LIBRARY_VERSION_CODE >= 11100
#if OSL_LIBRARY_VERSION_CODE >= 11304
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(OSLUStringHash filename,
OSL::ShadingContext *context,
const TextureOpt *opt)
{
return get_texture_handle(to_ustring(filename), context, opt);
}
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(OSL::ustring filename,
OSL::ShadingContext *,
const TextureOpt *)
#elif OSL_LIBRARY_VERSION_CODE >= 11100
TextureSystem::TextureHandle *OSLRenderServices::get_texture_handle(OSLUStringHash filename,
OSL::ShadingContext *)
#else
@ -1616,7 +1627,17 @@ bool OSLRenderServices::environment(OSLUStringHash filename,
return status;
}
#if OSL_LIBRARY_VERSION_CODE >= 11100
#if OSL_LIBRARY_VERSION_CODE >= 11304
bool OSLRenderServices::get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
OSL::ShaderGlobals *,
int subimage,
OSLUStringHash dataname,
TypeDesc datatype,
void *data,
OSLUStringHash *)
#elif OSL_LIBRARY_VERSION_CODE >= 11100
bool OSLRenderServices::get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
@ -1627,7 +1648,7 @@ bool OSLRenderServices::get_texture_info(OSLUStringHash filename,
void *data,
OSLUStringHash *)
#else
bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *sg,
bool OSLRenderServices::get_texture_info(OSL::ShaderGlobals *,
OSLUStringHash filename,
TextureHandle *texture_handle,
int subimage,

View File

@ -189,7 +189,14 @@ class OSLRenderServices : public OSL::RendererServices {
void *val,
bool derivatives) override;
#if OSL_LIBRARY_VERSION_CODE >= 11100
#if OSL_LIBRARY_VERSION_CODE >= 11304
TextureSystem::TextureHandle *get_texture_handle(OSL::ustring filename,
OSL::ShadingContext *context,
const TextureOpt *options) override;
TextureSystem::TextureHandle *get_texture_handle(OSLUStringHash filename,
OSL::ShadingContext *context,
const TextureOpt *options) override;
#elif OSL_LIBRARY_VERSION_CODE >= 11100
TextureSystem::TextureHandle *get_texture_handle(OSLUStringHash filename,
OSL::ShadingContext *context) override;
#else
@ -245,7 +252,17 @@ class OSLRenderServices : public OSL::RendererServices {
float *dresultdt,
OSLUStringHash *errormessage) override;
#if OSL_LIBRARY_VERSION_CODE >= 11100
#if OSL_LIBRARY_VERSION_CODE >= 11304
bool get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,
OSL::ShaderGlobals *sg,
int subimage,
OSLUStringHash dataname,
TypeDesc datatype,
void *data,
OSLUStringHash *errormessage) override;
#elif OSL_LIBRARY_VERSION_CODE >= 11100
bool get_texture_info(OSLUStringHash filename,
TextureHandle *texture_handle,
TexturePerthread *texture_thread_info,

View File

@ -86,8 +86,10 @@ struct ShaderGlobals {
ccl_private void *tracedata;
ccl_private void *objdata;
void *context;
#if OSL_LIBRARY_VERSION_CODE >= 11302
#if OSL_LIBRARY_VERSION_CODE >= 11304
void *shadingStateUniform;
int thread_index;
int shade_index;
#endif
void *renderer;
ccl_private void *object2common;

View File

@ -0,0 +1,441 @@
/* SPDX-FileCopyrightText: 2020-2021 Contributors to the OpenVDB Project
*
* SPDX-License-Identifier: MPL-2.0
*
* This is an extract from NanoVDB.h, with minimal code needed for kernel side access to grids. The
* original headers are not compatible with Metal due to missing address space qualifiers. */
#pragma once
CCL_NAMESPACE_BEGIN
#define NANOVDB_USE_SINGLE_ROOT_KEY
#define NANOVDB_DATA_ALIGNMENT 32
namespace nanovdb {
/* Utilities */
template<typename DstT, typename SrcT>
ccl_device ccl_global const DstT *PtrAdd(ccl_global const SrcT *p, int64_t offset)
{
return reinterpret_cast<ccl_global const DstT *>(reinterpret_cast<ccl_global const char *>(p) +
offset);
}
/* Coord */
struct Coord {
int x, y, z;
ccl_device_inline_method explicit Coord(int32_t n) : x(n), y(n), z(n) {}
ccl_device_inline_method Coord(int32_t x, int32_t y, int32_t z) : x(x), y(y), z(z) {}
ccl_device_inline_method Coord operator&(int32_t n) const
{
return Coord(x & n, y & n, z & n);
}
};
/* Mask */
template<uint32_t LOG2DIM> struct Mask {
ccl_static_constexpr uint32_t SIZE = 1U << (3 * LOG2DIM);
ccl_static_constexpr uint32_t WORD_COUNT = SIZE >> 6;
uint64_t mWords[WORD_COUNT];
ccl_device_inline_method bool isOff(uint32_t n) const ccl_global
{
return 0 == (mWords[n >> 6] & (uint64_t(1) << (n & 63)));
}
};
/* Grid */
template<typename TreeT> struct alignas(NANOVDB_DATA_ALIGNMENT) Grid {
ccl_static_constexpr int MaxNameSize = 256;
uint64_t mMagic;
uint64_t mChecksum;
uint32_t mVersion;
uint32_t mFlags;
uint32_t mGridIndex;
uint32_t mGridCount;
uint64_t mGridSize;
char mGridName[MaxNameSize];
uint8_t mMap[264];
uint8_t mWorldBBox[48]; // double[6], but no doubles in Metal
uint8_t mVoxelSize[24]; // double[3], but no doubles in Metal
uint32_t mGridClass;
uint32_t mGridType;
uint32_t mData0;
uint64_t mData1, mData2;
using BuildType = typename TreeT::BuildType;
ccl_device_inline_method ccl_global const TreeT &tree() const ccl_global
{
return *reinterpret_cast<ccl_global const TreeT *>(this + 1);
}
};
/* Tree */
template<typename RootT> struct alignas(NANOVDB_DATA_ALIGNMENT) Tree {
int64_t mNodeOffset[4];
uint32_t mNodeCount[3];
uint32_t mTileCount[3];
uint64_t mVoxelCount;
using ValueType = typename RootT::ValueType;
using BuildType = typename RootT::BuildType;
ccl_device_inline_method ccl_global const RootT &root() const ccl_global
{
return *reinterpret_cast<ccl_global const RootT *>(
mNodeOffset[3] ? PtrAdd<uint8_t>(this, mNodeOffset[3]) : nullptr);
}
};
/* RootNode */
template<typename ChildT> struct alignas(NANOVDB_DATA_ALIGNMENT) RootNode {
using ValueType = typename ChildT::ValueType;
using BuildType = typename ChildT::BuildType;
#ifdef NANOVDB_USE_SINGLE_ROOT_KEY
using KeyT = uint64_t;
ccl_device_inline_method static uint64_t CoordToKey(const Coord ijk)
{
return (uint64_t(uint32_t(ijk.z) >> ChildT::TOTAL)) |
(uint64_t(uint32_t(ijk.y) >> ChildT::TOTAL) << 21) |
(uint64_t(uint32_t(ijk.x) >> ChildT::TOTAL) << 42);
}
#else
using KeyT = Coord;
ccl_device_inline_method static Coord CoordToKey(const CoordT ijk)
{
return ijk & ~ChildT::MASK;
}
#endif
Coord mBBox[2];
uint32_t mTableSize;
ValueType mBackground;
ValueType mMinimum;
ValueType mMaximum;
float mAverage;
float mStdDevi;
struct alignas(NANOVDB_DATA_ALIGNMENT) Tile {
KeyT key;
int64_t child;
uint32_t state;
ValueType value;
};
ccl_device_inline_method ccl_global const Tile *probeTile(const Coord ijk) const ccl_global
{
const auto key = CoordToKey(ijk);
ccl_global const Tile *p = reinterpret_cast<ccl_global const Tile *>(this + 1);
ccl_global const Tile *q = p + mTableSize;
for (; p < q; ++p) {
if (p->key == key) {
return p;
}
}
return nullptr;
}
ccl_device_inline_method ccl_global const ChildT *getChild(ccl_global const Tile *tile) const
ccl_global
{
return PtrAdd<ChildT>(this, tile->child);
}
ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
};
/* InternalNode */
template<typename ChildT, uint32_t Log2Dim = ChildT::LOG2DIM + 1>
struct alignas(NANOVDB_DATA_ALIGNMENT) InternalNode {
using ValueType = typename ChildT::ValueType;
using BuildType = typename ChildT::BuildType;
union Tile {
ValueType value;
int64_t child;
};
Coord mBBox[2];
uint64_t mFlags;
Mask<Log2Dim> mValueMask;
Mask<Log2Dim> mChildMask;
ValueType mMinimum;
ValueType mMaximum;
float mAverage;
float mStdDevi;
alignas(32) Tile mTable[1u << (3 * Log2Dim)];
ccl_device_inline_method ccl_global const ChildT *getChild(uint32_t n) const ccl_global
{
return PtrAdd<ChildT>(this, mTable[n].child);
}
ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
ccl_static_constexpr uint32_t TOTAL = LOG2DIM + ChildT::TOTAL;
ccl_static_constexpr uint32_t DIM = 1u << TOTAL;
ccl_static_constexpr uint32_t SIZE = 1u << (3 * LOG2DIM);
ccl_static_constexpr uint32_t MASK = (1u << TOTAL) - 1u;
ccl_static_constexpr uint32_t LEVEL = 1 + ChildT::LEVEL;
ccl_device_inline_method static uint32_t CoordToOffset(const Coord ijk)
{
return (((ijk.x & MASK) >> ChildT::TOTAL) << (2 * LOG2DIM)) |
(((ijk.y & MASK) >> ChildT::TOTAL) << (LOG2DIM)) | ((ijk.z & MASK) >> ChildT::TOTAL);
}
};
/* LeafData */
template<typename ValueT, uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData {
using ValueType = ValueT;
using BuildType = ValueT;
Coord mBBoxMin;
uint8_t mBBoxDif[3];
uint8_t mFlags;
Mask<LOG2DIM> mValueMask;
ValueType mMinimum;
ValueType mMaximum;
float mAverage;
float mStdDevi;
alignas(32) ValueType mValues[1u << 3 * LOG2DIM];
ccl_device_inline_method ValueType getValue(uint32_t i) const ccl_global
{
return mValues[i];
}
};
/* LeafFnBase */
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafFnBase {
Coord mBBoxMin;
uint8_t mBBoxDif[3];
uint8_t mFlags;
Mask<LOG2DIM> mValueMask;
float mMinimum;
float mQuantum;
uint16_t mMin, mMax, mAvg, mDev;
};
/* LeafData<Fp16> */
class Fp16 {
};
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<Fp16, LOG2DIM> {
using ValueType = float;
using BuildType = Fp16;
LeafFnBase<LOG2DIM> base;
alignas(32) uint16_t mCode[1u << 3 * LOG2DIM];
ccl_device_inline_method float getValue(uint32_t i) const ccl_global
{
return mCode[i] * base.mQuantum + base.mMinimum;
}
};
/* LeafData<FpN> */
class FpN {
};
template<uint32_t LOG2DIM> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafData<FpN, LOG2DIM> {
using ValueType = float;
using BuildType = FpN;
LeafFnBase<LOG2DIM> base;
ccl_device_inline_method float getValue(uint32_t i) const ccl_global
{
const int b = base.mFlags >> 5;
uint32_t code = reinterpret_cast<ccl_global const uint32_t *>(this + 1)[i >> (5 - b)];
code >>= (i & ((32 >> b) - 1)) << b;
code &= (1 << (1 << b)) - 1;
return float(code) * base.mQuantum + base.mMinimum;
}
};
/* LeafNode */
template<typename BuildT, uint32_t Log2Dim = 3> struct alignas(NANOVDB_DATA_ALIGNMENT) LeafNode {
using DataType = LeafData<BuildT, Log2Dim>;
using ValueType = typename DataType::ValueType;
using BuildType = typename DataType::BuildType;
DataType data;
ccl_static_constexpr uint32_t LOG2DIM = Log2Dim;
ccl_static_constexpr uint32_t TOTAL = LOG2DIM;
ccl_static_constexpr uint32_t DIM = 1u << TOTAL;
ccl_static_constexpr uint32_t SIZE = 1u << 3 * LOG2DIM;
ccl_static_constexpr uint32_t MASK = (1u << LOG2DIM) - 1u;
ccl_static_constexpr uint32_t LEVEL = 0;
ccl_device_inline_method static uint32_t CoordToOffset(const Coord ijk)
{
return ((ijk.x & MASK) << (2 * LOG2DIM)) | ((ijk.y & MASK) << LOG2DIM) | (ijk.z & MASK);
}
ccl_device_inline_method ValueType getValue(uint32_t offset) const ccl_global
{
return data.getValue(offset);
}
ccl_device_inline_method ValueType getValue(const Coord ijk) const ccl_global
{
return getValue(CoordToOffset(ijk));
}
};
/* Template Specializations */
template<typename BuildT> using NanoLeaf = LeafNode<BuildT, 3>;
template<typename BuildT> using NanoLower = InternalNode<NanoLeaf<BuildT>, 4>;
template<typename BuildT> using NanoUpper = InternalNode<NanoLower<BuildT>, 5>;
template<typename BuildT> using NanoRoot = RootNode<NanoUpper<BuildT>>;
template<typename BuildT> using NanoTree = Tree<NanoRoot<BuildT>>;
template<typename BuildT> using NanoGrid = Grid<NanoTree<BuildT>>;
/* ReadAccessor */
template<typename BuildT> class ReadAccessor {
using RootT = NanoRoot<BuildT>;
using LeafT = NanoLeaf<BuildT>;
mutable ccl_global const RootT *mRoot;
public:
using ValueType = typename RootT::ValueType;
ccl_device_inline_method ReadAccessor(ccl_global const RootT &root) : mRoot(&root) {}
ccl_device_inline_method ValueType getValue(const Coord ijk) const
{
ccl_global const auto *tile = mRoot->probeTile(ijk);
if (tile == nullptr) {
return mRoot->mBackground;
}
if (tile->child == 0) {
return tile->value;
}
ccl_global const auto *upper = mRoot->getChild(tile);
const uint32_t upper_n = upper->CoordToOffset(ijk);
if (upper->mChildMask.isOff(upper_n)) {
return upper->mTable[upper_n].value;
}
ccl_global const auto *lower = upper->getChild(upper_n);
const uint32_t lower_n = lower->CoordToOffset(ijk);
if (lower->mChildMask.isOff(lower_n)) {
return lower->mTable[lower_n].value;
}
ccl_global const LeafT *leaf = lower->getChild(lower_n);
return leaf->getValue(ijk);
}
};
template<typename BuildT> class CachedReadAccessor {
using RootT = NanoRoot<BuildT>;
using UpperT = NanoUpper<BuildT>;
using LowerT = NanoLower<BuildT>;
using LeafT = NanoLeaf<BuildT>;
mutable Coord mKeys[3];
mutable ccl_global const RootT *mRoot;
mutable ccl_global const void *mNode[3];
public:
using ValueType = typename RootT::ValueType;
ccl_device_inline_method CachedReadAccessor(ccl_global const RootT &root)
: mKeys{Coord(INT_MAX), Coord(INT_MAX), Coord(INT_MAX)},
mRoot(&root),
mNode{nullptr, nullptr, nullptr}
{
}
template<typename NodeT> ccl_device_inline_method bool isCached(const Coord ijk) const
{
return (ijk.x & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].x &&
(ijk.y & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].y &&
(ijk.z & int32_t(~NodeT::MASK)) == mKeys[NodeT::LEVEL].z;
}
ccl_device_inline_method ValueType getValueAndCache(ccl_global const RootT &node,
const Coord ijk) const
{
if (ccl_global const auto *tile = node.probeTile(ijk)) {
if (tile->child != 0) {
ccl_global const auto *child = node.getChild(tile);
insert(ijk, child);
return getValueAndCache(*child, ijk);
}
return tile->value;
}
return node.mBackground;
}
ccl_device_inline_method ValueType getValueAndCache(ccl_global const LeafT &node,
const Coord ijk) const
{
return node.getValue(ijk);
}
template<typename NodeT>
ccl_device_inline_method ValueType getValueAndCache(ccl_global const NodeT &node,
const Coord ijk) const
{
const uint32_t n = node.CoordToOffset(ijk);
if (node.mChildMask.isOff(n)) {
return node.mTable[n].value;
}
ccl_global const auto *child = node.getChild(n);
insert(ijk, child);
return getValueAndCache(*child, ijk);
}
ccl_device_inline_method ValueType getValue(const Coord ijk) const
{
if (isCached<LeafT>(ijk)) {
return getValueAndCache(*((ccl_global const LeafT *)mNode[0]), ijk);
}
else if (isCached<LowerT>(ijk)) {
return getValueAndCache(*((ccl_global const LowerT *)mNode[1]), ijk);
}
else if (isCached<UpperT>(ijk)) {
return getValueAndCache(*((ccl_global const UpperT *)mNode[2]), ijk);
}
return getValueAndCache(*mRoot, ijk);
}
template<typename NodeT>
ccl_device_inline_method void insert(const Coord ijk, ccl_global const NodeT *node) const
{
mKeys[NodeT::LEVEL] = ijk & ~NodeT::MASK;
mNode[NodeT::LEVEL] = node;
}
};
} // namespace nanovdb
CCL_NAMESPACE_END

View File

@ -108,8 +108,6 @@ if(WITH_CYCLES_OSL)
list(APPEND LIB
cycles_kernel_osl
)
set_property(SOURCE osl.cpp PROPERTY COMPILE_FLAGS ${RTTI_DISABLE_FLAGS})
endif()
if(WITH_OPENCOLORIO)

View File

@ -35,7 +35,7 @@ void curvebounds(float *lower, float *upper, float3 *p, int dim)
float ta = -1.0f;
float tb = -1.0f;
if (discroot >= 0) {
if (discroot >= 0 && curve_coef[3] != 0.0f) {
discroot = sqrtf(discroot);
ta = (-curve_coef[2] - discroot) / (3 * curve_coef[3]);
tb = (-curve_coef[2] + discroot) / (3 * curve_coef[3]);

View File

@ -11,6 +11,7 @@
# include <openvdb/tools/Dense.h>
#endif
#ifdef WITH_NANOVDB
# define NANOVDB_USE_OPENVDB
# include <nanovdb/util/OpenToNanoVDB.h>
#endif
@ -52,23 +53,49 @@ struct ToNanoOp {
{
if constexpr (!std::is_same_v<GridType, openvdb::MaskGrid>) {
try {
FloatGridType floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
# if NANOVDB_MAJOR_VERSION_NUMBER > 32 || \
(NANOVDB_MAJOR_VERSION_NUMBER == 32 && NANOVDB_MINOR_VERSION_NUMBER >= 6)
/* OpenVDB 11. */
if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
if (precision == 0) {
nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
typename FloatGridType::TreeType,
nanovdb::FpN>(floatgrid);
return true;
nanogrid = nanovdb::createNanoGrid<openvdb::FloatGrid, nanovdb::FpN>(floatgrid);
}
else if (precision == 16) {
nanogrid = nanovdb::openToNanoVDB<nanovdb::HostBuffer,
typename FloatGridType::TreeType,
nanovdb::Fp16>(floatgrid);
return true;
nanogrid = nanovdb::createNanoGrid<openvdb::FloatGrid, nanovdb::Fp16>(floatgrid);
}
else {
nanogrid = nanovdb::createNanoGrid<openvdb::FloatGrid, float>(floatgrid);
}
}
nanogrid = nanovdb::openToNanoVDB(floatgrid);
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec3fGrid>) {
openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
nanogrid = nanovdb::createNanoGrid<openvdb::Vec3fGrid, nanovdb::Vec3f>(
floatgrid, nanovdb::StatsMode::Disable);
}
# else
/* OpenVDB 10. */
if constexpr (std::is_same_v<FloatGridType, openvdb::FloatGrid>) {
openvdb::FloatGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
if (precision == 0) {
nanogrid =
nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::FpN>(
floatgrid);
}
else if (precision == 16) {
nanogrid =
nanovdb::openToNanoVDB<nanovdb::HostBuffer, openvdb::FloatTree, nanovdb::Fp16>(
floatgrid);
}
else {
nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
}
else if constexpr (std::is_same_v<FloatGridType, openvdb::Vec3fGrid>) {
openvdb::Vec3fGrid floatgrid(*openvdb::gridConstPtrCast<GridType>(grid));
nanogrid = nanovdb::openToNanoVDB(floatgrid);
}
# endif
}
catch (const std::exception &e) {
VLOG_WARNING << "Error converting OpenVDB to NanoVDB grid: " << e.what();

View File

@ -3372,14 +3372,23 @@ PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(get_node_type())
closure = CLOSURE_BSDF_HAIR_HUANG_ID;
}
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
/* Treat hair as transparent if the hit is outside of the projected width. */
bool PrincipledHairBsdfNode::has_surface_transparent()
{
if (model == NODE_PRINCIPLED_HAIR_HUANG) {
/* Make sure we have the normal for elliptical cross section tracking. */
if (aspect_ratio != 1.0f || input("Aspect Ratio")->link) {
attributes->add(ATTR_STD_VERTEX_NORMAL);
return true;
}
}
return false;
}
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
{
if (has_surface_transparent()) {
/* Make sure we have the normal for elliptical cross section tracking. */
attributes->add(ATTR_STD_VERTEX_NORMAL);
}
if (!input("Random")->link) {
/* Enable retrieving Hair Info -> Random if Random isn't linked. */

View File

@ -851,6 +851,8 @@ class PrincipledHairBsdfNode : public BsdfBaseNode {
{
return ShaderNode::get_feature() | KERNEL_FEATURE_NODE_PRINCIPLED_HAIR;
}
bool has_surface_transparent();
};
class HairBsdfNode : public BsdfNode {

View File

@ -61,6 +61,7 @@
/* Address spaces for GPU. */
# define ccl_global
# define ccl_inline_constant inline constexpr
# define ccl_static_constexpr static constexpr
# define ccl_constant const
# define ccl_private
# define ccl_ray_data ccl_private

View File

@ -26,7 +26,7 @@ typedef struct DualConInput {
int co_stride;
int totco;
DualConTri looptri;
DualConTri looptris;
int tri_stride;
int tottri;

View File

@ -22,7 +22,7 @@ static void veccopy(float dst[3], const float src[3])
}
#define GET_TRI(_mesh, _n) \
(*(DualConTri)(((char *)(_mesh)->looptri) + ((_n) * (_mesh)->tri_stride)))
(*(DualConTri)(((char *)(_mesh)->looptris) + ((_n) * (_mesh)->tri_stride)))
#define GET_CO(_mesh, _n) (*(DualConCo)(((char *)(_mesh)->co) + ((_n) * (_mesh)->co_stride)))

View File

@ -16,6 +16,7 @@
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
/* Check if our ffmpeg is new enough, avoids user complaints.
* Minimum supported version is currently 3.2.0 which mean the following library versions:
@ -46,6 +47,11 @@
# define FFMPEG_USE_OLD_CHANNEL_VARS
#endif
/* Threaded sws_scale_frame was added in ffmpeg 5.0 (swscale version 6.1). */
#if (LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(6, 1, 100))
# define FFMPEG_SWSCALE_THREADING
#endif
/* AV_CODEC_CAP_AUTO_THREADS was renamed to AV_CODEC_CAP_OTHER_THREADS with
* upstream commit
* github.com/FFmpeg/FFmpeg/commit/7d09579190def3ef7562399489e628f3b65714ce

View File

@ -176,6 +176,13 @@ class GHOST_SystemCocoa : public GHOST_System {
*/
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y);
/**
* Get the color of the pixel at the current mouse cursor location
* \param r_color: returned sRGB float colors
* \return Success value (true == successful and supported by platform)
*/
GHOST_TSuccess getPixelAtCursor(float r_color[3]) const;
/***************************************************************************************
* Access to mouse button and keyboard states.
***************************************************************************************/
@ -318,7 +325,7 @@ class GHOST_SystemCocoa : public GHOST_System {
/** Temporarily ignore momentum scroll events */
bool m_ignoreMomentumScroll;
/** Is the scroll wheel event generated by a multi-touch track-pad or mouse? */
/** Is the scroll wheel event generated by a multi-touch trackpad or mouse? */
bool m_multiTouchScroll;
/** To prevent multiple warp, we store the time of the last warp event
* and ignore mouse moved events generated before that. */

View File

@ -549,7 +549,7 @@ GHOST_SystemCocoa::GHOST_SystemCocoa()
sysctl(mib, 2, &boottime, &len, nullptr, 0);
m_start_time = ((boottime.tv_sec * 1000) + (boottime.tv_usec / 1000));
/* Detect multi-touch track-pad. */
/* Detect multi-touch trackpad. */
mib[0] = CTL_HW;
mib[1] = HW_MODEL;
sysctl(mib, 2, nullptr, &len, nullptr, 0);
@ -888,6 +888,71 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(int32_t x, int32_t y)
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemCocoa::getPixelAtCursor(float r_color[3]) const
{
/* NOTE: There are known issues/limitations at the moment:
*
* - User needs to allow screen capture permission for Blender.
* - Blender has no control of the cursor outside of its window, so it is
* not going to be the eyedropper icon.
* - GHOST does not report click events from outside of the window, so the
* user needs to press Enter instead.
*
* Ref #111303.
*/
@autoreleasepool {
/* Check for screen capture access permission early to prevent issues.
* Without permission, macOS may capture only the Blender window, wallpaper, and taskbar.
* This behavior could confuse users, especially when trying to pick a color from another app,
* potentially capturing the wallpaper under that app window.
*/
if (@available(macOS 11.0, *)) {
/* Although these methods are documented as available for macOS 10.15, they are not actually
* shipped, leading to a crash if used on macOS 10.15.
*
* Ref: https://developer.apple.com/forums/thread/683860?answerId=684400022#684400022
*/
if (!CGPreflightScreenCaptureAccess()) {
CGRequestScreenCaptureAccess();
return GHOST_kFailure;
}
}
CGEventRef event = CGEventCreate(nil);
if (!event) {
return GHOST_kFailure;
}
CGPoint mouseLocation = CGEventGetLocation(event);
CFRelease(event);
CGRect rect = CGRectMake(mouseLocation.x, mouseLocation.y, 1, 1);
CGImageRef image = CGWindowListCreateImage(
rect, kCGWindowListOptionOnScreenOnly, kCGNullWindowID, kCGWindowImageDefault);
if (!image) {
return GHOST_kFailure;
}
NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithCGImage:image];
CGImageRelease(image);
NSColor *color = [bitmap colorAtX:0 y:0];
if (!color) {
return GHOST_kFailure;
}
NSColor *srgbColor = [color colorUsingColorSpace:[NSColorSpace sRGBColorSpace]];
if (!srgbColor) {
return GHOST_kFailure;
}
CGFloat red = 0.0, green = 0.0, blue = 0.0;
[color getRed:&red green:&green blue:&blue alpha:nil];
r_color[0] = red;
r_color[1] = green;
r_color[2] = blue;
}
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemCocoa::setMouseCursorPosition(int32_t x, int32_t y)
{
float xf = (float)x, yf = (float)y;
@ -953,8 +1018,6 @@ GHOST_TCapabilityFlag GHOST_SystemCocoa::getCapabilities() const
~(
/* Cocoa has no support for a primary selection clipboard. */
GHOST_kCapabilityPrimaryClipboard |
/* Cocoa has no support for sampling colors from the desktop. */
GHOST_kCapabilityDesktopSample |
/* This Cocoa back-end has not yet implemented image copy/paste. */
GHOST_kCapabilityClipboardImages));
}

View File

@ -120,6 +120,11 @@ static void gwl_seat_capability_pointer_disable(GWL_Seat *seat);
static void gwl_seat_capability_keyboard_disable(GWL_Seat *seat);
static void gwl_seat_capability_touch_disable(GWL_Seat *seat);
static void gwl_seat_cursor_anim_begin(GWL_Seat *seat);
static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat *seat);
static void gwl_seat_cursor_anim_end(GWL_Seat *seat);
static void gwl_seat_cursor_anim_reset(GWL_Seat *seat);
static bool gwl_registry_entry_remove_by_name(GWL_Display *display,
uint32_t name,
int *r_interface_slot);
@ -135,11 +140,6 @@ static void gwl_display_event_thread_destroy(GWL_Display *display);
static void ghost_wl_display_lock_without_input(wl_display *wl_display, std::mutex *server_mutex);
static void cursor_anim_begin_if_needed(GWL_Seat *seat);
static void cursor_anim_begin(GWL_Seat *seat);
static void cursor_anim_end(GWL_Seat *seat);
static void cursor_anim_reset(GWL_Seat *seat);
/** Default size for pending event vector. */
constexpr size_t events_pending_default_size = 4096 / sizeof(void *);
@ -1336,7 +1336,7 @@ static void gwl_display_destroy(GWL_Display *display)
/* Stop all animated cursors (freeing their #GWL_Cursor_AnimHandle). */
for (GWL_Seat *seat : display->seats) {
cursor_anim_end(seat);
gwl_seat_cursor_anim_end(seat);
}
/* For typical WAYLAND use this will always be set.
@ -1675,6 +1675,11 @@ static void gwl_registry_entry_update_all(GWL_Display *display, const int interf
/** \name Private Utility Functions
* \{ */
static uint64_t sub_abs_u64(const uint64_t a, const uint64_t b)
{
return a > b ? a - b : b - a;
}
/**
* Return milliseconds from a microsecond uint32 pair (used by some wayland functions).
*/
@ -2026,6 +2031,7 @@ static const char *ghost_wl_mime_send[] = {
"text/plain",
};
#ifdef USE_EVENT_BACKGROUND_THREAD
static void pthread_set_min_priority(pthread_t handle)
{
int policy;
@ -2046,6 +2052,7 @@ static void thread_set_min_priority(std::thread &thread)
* This cast might be avoided with clever template use. */
pthread_set_min_priority(reinterpret_cast<pthread_t>(thread.native_handle()));
}
#endif /* USE_EVENT_BACKGROUND_THREAD */
static int memfd_create_sealed(const char *name)
{
@ -2383,6 +2390,321 @@ static char *read_file_as_buffer(const int fd, const bool nil_terminate, size_t
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Cursor API
* \{ */
static void cursor_buffer_set_surface_impl(const wl_cursor_image *wl_image,
wl_buffer *buffer,
wl_surface *wl_surface,
const int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
"The size must be a multiple of the scale!");
wl_surface_set_buffer_scale(wl_surface, scale);
wl_surface_attach(wl_surface, buffer, 0, 0);
wl_surface_damage(wl_surface, 0, 0, image_size_x, image_size_y);
wl_surface_commit(wl_surface);
}
/**
* Needed to ensure the cursor size is always a multiple of scale.
*/
static int cursor_buffer_compatible_scale_from_image(const wl_cursor_image *wl_image, int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
while (scale > 1) {
if ((image_size_x % scale) == 0 && (image_size_y % scale) == 0) {
break;
}
scale -= 1;
}
return scale;
}
static const wl_cursor *gwl_seat_cursor_find_from_shape(GWL_Seat *seat,
const GHOST_TStandardCursor shape,
const char **r_cursor_name)
{
/* Caller must lock `server_mutex`. */
GWL_Cursor *cursor = &seat->cursor;
wl_cursor *wl_cursor = nullptr;
const char *cursor_name = ghost_wl_cursors.names[shape];
if (cursor_name[0] != '\0') {
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
}
}
}
if (r_cursor_name && wl_cursor) {
*r_cursor_name = cursor_name;
}
return wl_cursor;
}
/**
* Show the buffer defined by #gwl_seat_cursor_buffer_set without changing anything else,
* so #gwl_seat_cursor_buffer_hide can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void gwl_seat_cursor_buffer_show(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
if (seat->wl.pointer) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
wl_pointer_set_cursor(
seat->wl.pointer, seat->pointer.serial, cursor->wl.surface_cursor, hotspot_x, hotspot_y);
}
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
tablet_tool->wl.surface_cursor,
hotspot_x,
hotspot_y);
#ifdef USE_KDE_TABLET_HIDDEN_CURSOR_HACK
wl_surface_commit(tablet_tool->wl.surface_cursor);
#endif
}
}
gwl_seat_cursor_anim_reset(seat);
}
/**
* Hide the buffer defined by #gwl_seat_cursor_buffer_set without changing anything else,
* so #gwl_seat_cursor_buffer_show can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void gwl_seat_cursor_buffer_hide(GWL_Seat *seat)
{
gwl_seat_cursor_anim_end(seat);
wl_pointer_set_cursor(seat->wl.pointer, seat->pointer.serial, nullptr, 0, 0);
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, seat->tablet.serial, nullptr, 0, 0);
}
}
static void gwl_seat_cursor_buffer_set(const GWL_Seat *seat,
const wl_cursor_image *wl_image,
wl_buffer *buffer)
{
const GWL_Cursor *cursor = &seat->cursor;
const bool visible = (cursor->visible && cursor->is_hardware);
/* This is a requirement of WAYLAND, when this isn't the case,
* it causes Blender's window to close intermittently. */
if (seat->wl.pointer) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
cursor_buffer_set_surface_impl(wl_image, buffer, cursor->wl.surface_cursor, scale);
wl_pointer_set_cursor(seat->wl.pointer,
seat->pointer.serial,
visible ? cursor->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
/* Set the cursor for all tablet tools as well. */
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
cursor_buffer_set_surface_impl(wl_image, buffer, tablet_tool->wl.surface_cursor, scale);
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
visible ? tablet_tool->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
}
}
static void gwl_seat_cursor_buffer_set_current(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
gwl_seat_cursor_anim_end(seat);
gwl_seat_cursor_buffer_set(seat, &cursor->wl.image, cursor->wl.buffer);
gwl_seat_cursor_anim_begin_if_needed(seat);
}
enum eCursorSetMode {
CURSOR_VISIBLE_ALWAYS_SET = 1,
CURSOR_VISIBLE_ONLY_HIDE,
CURSOR_VISIBLE_ONLY_SHOW,
};
static void gwl_seat_cursor_visible_set(GWL_Seat *seat,
const bool visible,
const bool is_hardware,
const enum eCursorSetMode set_mode)
{
GWL_Cursor *cursor = &seat->cursor;
const bool was_visible = cursor->is_hardware && cursor->visible;
const bool use_visible = is_hardware && visible;
if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
/* Pass. */
}
else if (set_mode == CURSOR_VISIBLE_ONLY_SHOW) {
if (!use_visible) {
return;
}
}
else if (set_mode == CURSOR_VISIBLE_ONLY_HIDE) {
if (use_visible) {
return;
}
}
if (use_visible) {
if (!was_visible) {
gwl_seat_cursor_buffer_show(seat);
}
}
else {
if (was_visible) {
gwl_seat_cursor_buffer_hide(seat);
}
}
cursor->visible = visible;
cursor->is_hardware = is_hardware;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Cursor Animation API
* \{ */
#ifdef USE_EVENT_BACKGROUND_THREAD
static bool gwl_seat_cursor_anim_check(GWL_Seat *seat)
{
const wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
if (!wl_cursor) {
return false;
}
/* NOTE: return true to stress test animated cursor,
* to ensure (otherwise rare) issues are triggered more frequently. */
// return true;
return wl_cursor->image_count > 1;
}
static void gwl_seat_cursor_anim_begin(GWL_Seat *seat)
{
/* Caller must lock `server_mutex`. */
GHOST_ASSERT(seat->cursor.anim_handle == nullptr, "Must be cleared");
/* Callback for updating the cursor animation. */
auto cursor_anim_frame_step_fn =
[](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) {
/* It's possible the `wl_cursor` is reloaded while the cursor is animating.
* Don't access outside the lock, that's why the `delay` is passed in. */
std::mutex *server_mutex = seat->system->server_mutex;
int frame = 0;
while (!anim_handle->exit_pending.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if (!anim_handle->exit_pending.load()) {
std::lock_guard lock_server_guard{*server_mutex};
if (!anim_handle->exit_pending.load()) {
const struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
frame = (frame + 1) % wl_cursor->image_count;
wl_cursor_image *image = wl_cursor->images[frame];
wl_buffer *buffer = wl_cursor_image_get_buffer(image);
gwl_seat_cursor_buffer_set(seat, image, buffer);
delay = wl_cursor->images[frame]->delay;
/* Without this the cursor won't update when other processes are occupied. */
wl_display_flush(seat->system->wl_display_get());
}
}
}
delete anim_handle;
};
/* Allocate so this can be set before the thread begins. */
GWL_Cursor_AnimHandle *anim_handle = new GWL_Cursor_AnimHandle;
seat->cursor.anim_handle = anim_handle;
const int delay = seat->cursor.wl.theme_cursor->images[0]->delay;
std::thread cursor_anim_thread(cursor_anim_frame_step_fn, seat, anim_handle, delay);
/* Application logic should take priority. */
thread_set_min_priority(cursor_anim_thread);
cursor_anim_thread.detach();
}
static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat *seat)
{
if (gwl_seat_cursor_anim_check(seat)) {
gwl_seat_cursor_anim_begin(seat);
}
}
static void gwl_seat_cursor_anim_end(GWL_Seat *seat)
{
GWL_Cursor *cursor = &seat->cursor;
if (cursor->anim_handle) {
GWL_Cursor_AnimHandle *anim_handle = cursor->anim_handle;
cursor->anim_handle = nullptr;
anim_handle->exit_pending.store(true);
}
}
static void gwl_seat_cursor_anim_reset(GWL_Seat *seat)
{
gwl_seat_cursor_anim_end(seat);
gwl_seat_cursor_anim_begin_if_needed(seat);
}
#else
/* Unfortunately cursor animation requires a background thread. */
[[maybe_unused]] static bool gwl_seat_cursor_anim_check(GWL_Seat * /*seat*/)
{
return false;
}
[[maybe_unused]] static void gwl_seat_cursor_anim_begin(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_begin_if_needed(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_end(GWL_Seat * /*seat*/) {}
[[maybe_unused]] static void gwl_seat_cursor_anim_reset(GWL_Seat * /*seat*/) {}
#endif /* !USE_EVENT_BACKGROUND_THREAD */
/** \} */
/* -------------------------------------------------------------------- */
/** \name Private Keyboard Depressed Key Tracking
*
@ -3552,7 +3874,7 @@ static void gesture_pinch_handle_begin(void *data,
seat->pointer_gesture_pinch.rotation.factor = 5;
if (win) {
/* NOTE(@ideasman42): Blender's use of track-pad coordinates is inconsistent and needs work.
/* NOTE(@ideasman42): Blender's use of trackpad coordinates is inconsistent and needs work.
* This isn't specific to WAYLAND, in practice they tend to work well enough in most cases.
* Some operators scale by the UI scale, some don't.
* Even though the window scale is correct, it doesn't account for the UI scale preference
@ -7378,185 +7700,6 @@ GHOST_IWindow *GHOST_SystemWayland::createWindow(const char *title,
return window;
}
/**
* Show the buffer defined by #cursor_buffer_set without changing anything else,
* so #cursor_buffer_hide can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void cursor_buffer_show(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
if (seat->wl.pointer) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
wl_pointer_set_cursor(
seat->wl.pointer, seat->pointer.serial, cursor->wl.surface_cursor, hotspot_x, hotspot_y);
}
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale;
const int32_t hotspot_x = int32_t(cursor->wl.image.hotspot_x) / scale;
const int32_t hotspot_y = int32_t(cursor->wl.image.hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
tablet_tool->wl.surface_cursor,
hotspot_x,
hotspot_y);
#ifdef USE_KDE_TABLET_HIDDEN_CURSOR_HACK
wl_surface_commit(tablet_tool->wl.surface_cursor);
#endif
}
}
cursor_anim_reset(seat);
}
/**
* Hide the buffer defined by #cursor_buffer_set without changing anything else,
* so #cursor_buffer_show can be used to display it again.
*
* The caller is responsible for setting `seat->cursor.visible`.
*/
static void cursor_buffer_hide(GWL_Seat *seat)
{
cursor_anim_end(seat);
wl_pointer_set_cursor(seat->wl.pointer, seat->pointer.serial, nullptr, 0, 0);
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2, seat->tablet.serial, nullptr, 0, 0);
}
}
/**
* Needed to ensure the cursor size is always a multiple of scale.
*/
static int cursor_buffer_compatible_scale_from_image(const wl_cursor_image *wl_image, int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
while (scale > 1) {
if ((image_size_x % scale) == 0 && (image_size_y % scale) == 0) {
break;
}
scale -= 1;
}
return scale;
}
static void cursor_buffer_set_surface_impl(const wl_cursor_image *wl_image,
wl_buffer *buffer,
wl_surface *wl_surface,
const int scale)
{
const int32_t image_size_x = int32_t(wl_image->width);
const int32_t image_size_y = int32_t(wl_image->height);
GHOST_ASSERT((image_size_x % scale) == 0 && (image_size_y % scale) == 0,
"The size must be a multiple of the scale!");
wl_surface_set_buffer_scale(wl_surface, scale);
wl_surface_attach(wl_surface, buffer, 0, 0);
wl_surface_damage(wl_surface, 0, 0, image_size_x, image_size_y);
wl_surface_commit(wl_surface);
}
static void cursor_buffer_set(const GWL_Seat *seat,
const wl_cursor_image *wl_image,
wl_buffer *buffer)
{
const GWL_Cursor *cursor = &seat->cursor;
const bool visible = (cursor->visible && cursor->is_hardware);
/* This is a requirement of WAYLAND, when this isn't the case,
* it causes Blender's window to close intermittently. */
if (seat->wl.pointer) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->pointer.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
cursor_buffer_set_surface_impl(wl_image, buffer, cursor->wl.surface_cursor, scale);
wl_pointer_set_cursor(seat->wl.pointer,
seat->pointer.serial,
visible ? cursor->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
/* Set the cursor for all tablet tools as well. */
if (!seat->wp.tablet_tools.empty()) {
const int scale = cursor_buffer_compatible_scale_from_image(
wl_image, cursor->is_custom ? cursor->custom_scale : seat->tablet.theme_scale);
const int32_t hotspot_x = int32_t(wl_image->hotspot_x) / scale;
const int32_t hotspot_y = int32_t(wl_image->hotspot_y) / scale;
for (zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->wp.tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
cursor_buffer_set_surface_impl(wl_image, buffer, tablet_tool->wl.surface_cursor, scale);
zwp_tablet_tool_v2_set_cursor(zwp_tablet_tool_v2,
seat->tablet.serial,
visible ? tablet_tool->wl.surface_cursor : nullptr,
hotspot_x,
hotspot_y);
}
}
}
static void cursor_buffer_set_from_seat(GWL_Seat *seat)
{
const GWL_Cursor *cursor = &seat->cursor;
cursor_anim_end(seat);
cursor_buffer_set(seat, &cursor->wl.image, cursor->wl.buffer);
cursor_anim_begin_if_needed(seat);
}
enum eCursorSetMode {
CURSOR_VISIBLE_ALWAYS_SET = 1,
CURSOR_VISIBLE_ONLY_HIDE,
CURSOR_VISIBLE_ONLY_SHOW,
};
static void cursor_visible_set(GWL_Seat *seat,
const bool visible,
const bool is_hardware,
const enum eCursorSetMode set_mode)
{
GWL_Cursor *cursor = &seat->cursor;
const bool was_visible = cursor->is_hardware && cursor->visible;
const bool use_visible = is_hardware && visible;
if (set_mode == CURSOR_VISIBLE_ALWAYS_SET) {
/* Pass. */
}
else if (set_mode == CURSOR_VISIBLE_ONLY_SHOW) {
if (!use_visible) {
return;
}
}
else if (set_mode == CURSOR_VISIBLE_ONLY_HIDE) {
if (use_visible) {
return;
}
}
if (use_visible) {
if (!was_visible) {
cursor_buffer_show(seat);
}
}
else {
if (was_visible) {
cursor_buffer_hide(seat);
}
}
cursor->visible = visible;
cursor->is_hardware = is_hardware;
}
static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_software_confine)
{
if (mode == GHOST_kGrabWrap) {
@ -7574,114 +7717,6 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_
return false;
}
static bool cursor_anim_check(GWL_Seat *seat)
{
const wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
if (!wl_cursor) {
return false;
}
/* NOTE: return true to stress test animated cursor,
* to ensure (otherwise rare) issues are triggered more frequently. */
// return true;
return wl_cursor->image_count > 1;
}
static void cursor_anim_begin(GWL_Seat *seat)
{
/* Caller must lock `server_mutex`. */
GHOST_ASSERT(seat->cursor.anim_handle == nullptr, "Must be cleared");
/* Callback for updating the cursor animation. */
auto cursor_anim_frame_step_fn =
[](GWL_Seat *seat, GWL_Cursor_AnimHandle *anim_handle, int delay) {
/* It's possible the `wl_cursor` is reloaded while the cursor is animating.
* Don't access outside the lock, that's why the `delay` is passed in. */
std::mutex *server_mutex = seat->system->server_mutex;
int frame = 0;
while (!anim_handle->exit_pending.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
if (!anim_handle->exit_pending.load()) {
std::lock_guard lock_server_guard{*server_mutex};
if (!anim_handle->exit_pending.load()) {
const struct wl_cursor *wl_cursor = seat->cursor.wl.theme_cursor;
frame = (frame + 1) % wl_cursor->image_count;
wl_cursor_image *image = wl_cursor->images[frame];
wl_buffer *buffer = wl_cursor_image_get_buffer(image);
cursor_buffer_set(seat, image, buffer);
delay = wl_cursor->images[frame]->delay;
/* Without this the cursor won't update when other processes are occupied. */
wl_display_flush(seat->system->wl_display_get());
}
}
}
delete anim_handle;
};
/* Allocate so this can be set before the thread begins. */
GWL_Cursor_AnimHandle *anim_handle = new GWL_Cursor_AnimHandle;
seat->cursor.anim_handle = anim_handle;
const int delay = seat->cursor.wl.theme_cursor->images[0]->delay;
std::thread cursor_anim_thread(cursor_anim_frame_step_fn, seat, anim_handle, delay);
/* Application logic should take priority. */
thread_set_min_priority(cursor_anim_thread);
cursor_anim_thread.detach();
}
static void cursor_anim_begin_if_needed(GWL_Seat *seat)
{
if (cursor_anim_check(seat)) {
cursor_anim_begin(seat);
}
}
static void cursor_anim_end(GWL_Seat *seat)
{
GWL_Cursor *cursor = &seat->cursor;
if (cursor->anim_handle) {
GWL_Cursor_AnimHandle *anim_handle = cursor->anim_handle;
cursor->anim_handle = nullptr;
anim_handle->exit_pending.store(true);
}
}
static void cursor_anim_reset(GWL_Seat *seat)
{
cursor_anim_end(seat);
cursor_anim_begin_if_needed(seat);
}
static const wl_cursor *cursor_find_from_shape(GWL_Seat *seat,
const GHOST_TStandardCursor shape,
const char **r_cursor_name)
{
/* Caller must lock `server_mutex`. */
GWL_Cursor *cursor = &seat->cursor;
wl_cursor *wl_cursor = nullptr;
const char *cursor_name = ghost_wl_cursors.names[shape];
if (cursor_name[0] != '\0') {
if (!cursor->wl.theme) {
/* The cursor wl_surface hasn't entered an output yet. Initialize theme with scale 1. */
cursor->wl.theme = wl_cursor_theme_load(
cursor->theme_name.c_str(), cursor->theme_size, seat->system->wl_shm_get());
}
if (cursor->wl.theme) {
wl_cursor = wl_cursor_theme_get_cursor(cursor->wl.theme, cursor_name);
if (!wl_cursor) {
GHOST_PRINT("cursor '" << cursor_name << "' does not exist" << std::endl);
}
}
}
if (r_cursor_name && wl_cursor) {
*r_cursor_name = cursor_name;
}
return wl_cursor;
}
GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor shape)
{
/* Caller must lock `server_mutex`. */
@ -7692,7 +7727,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
}
const char *cursor_name = nullptr;
const wl_cursor *wl_cursor = cursor_find_from_shape(seat, shape, &cursor_name);
const wl_cursor *wl_cursor = gwl_seat_cursor_find_from_shape(seat, shape, &cursor_name);
if (wl_cursor == nullptr) {
return GHOST_kFailure;
}
@ -7711,7 +7746,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_set(const GHOST_TStandardCursor
cursor->wl.theme_cursor = wl_cursor;
cursor->wl.theme_cursor_name = cursor_name;
cursor_buffer_set_from_seat(seat);
gwl_seat_cursor_buffer_set_current(seat);
return GHOST_kSuccess;
}
@ -7720,7 +7755,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_check(const GHOST_TStandardCurs
{
/* No need to lock `server_mutex`. */
GWL_Seat *seat = gwl_display_seat_active_get(display_);
const wl_cursor *wl_cursor = cursor_find_from_shape(seat, cursorShape, nullptr);
const wl_cursor *wl_cursor = gwl_seat_cursor_find_from_shape(seat, cursorShape, nullptr);
if (wl_cursor == nullptr) {
return GHOST_kFailure;
}
@ -7800,7 +7835,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_custom_set(const uint8_t *bitma
cursor->wl.theme_cursor = nullptr;
cursor->wl.theme_cursor_name = nullptr;
cursor_buffer_set_from_seat(seat);
gwl_seat_cursor_buffer_set_current(seat);
return GHOST_kSuccess;
}
@ -7840,7 +7875,7 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_visibility_set(const bool visible)
return GHOST_kFailure;
}
cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
gwl_seat_cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@ -8231,15 +8266,31 @@ uint64_t GHOST_SystemWayland::ms_from_input_time(const uint32_t timestamp_as_uin
* use `timestamp_as_uint` to calculate an offset which is applied to future events.
* This is updated because time may have passed between generating the time-stamp and `now`.
* The method here is used by SDL. */
uint64_t timestamp = uint64_t(timestamp_as_uint);
GWL_DisplayTimeStamp &input_timestamp = display_->input_timestamp;
if (timestamp_as_uint < input_timestamp.last) {
/* 32-bit timer rollover, bump the offset. */
input_timestamp.offset += uint64_t(std::numeric_limits<uint32_t>::max()) + 1;
if (UNLIKELY(timestamp_as_uint < input_timestamp.last)) {
/* NOTE(@ideasman42): Sometimes event times are out of order,
* while this should _never_ happen, it occasionally does when resizing the window then
* clicking on the window with GNOME+LIBDECOR.
* Accept events must occur within ~25 days, out-of-order time-stamps above this time-frame
* will be treated as a wrapped integer. */
if (input_timestamp.last - timestamp_as_uint > std::numeric_limits<uint32_t>::max() / 2) {
/* Finally check to avoid invalid rollover,
* ensure the rolled over time is closer to "now" than it is currently. */
const uint64_t offset_test = input_timestamp.offset +
uint64_t(std::numeric_limits<uint32_t>::max()) + 1;
const uint64_t now = getMilliSeconds();
if (sub_abs_u64(now, timestamp + offset_test) <
sub_abs_u64(now, timestamp + input_timestamp.offset))
{
/* 32-bit timer rollover, bump the offset. */
input_timestamp.offset = offset_test;
}
}
}
input_timestamp.last = timestamp_as_uint;
uint64_t timestamp = uint64_t(timestamp_as_uint);
if (input_timestamp.exact_match) {
timestamp += input_timestamp.offset;
}
@ -8432,7 +8483,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
/* Only hide so the cursor is not made visible before it's location is restored.
* This function is called again at the end of this function which only shows. */
cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
gwl_seat_cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_HIDE);
/* Switching from one grab mode to another,
* in this case disable the current locks as it makes logic confusing,
@ -8574,7 +8625,7 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
}
/* Only show so the cursor is made visible as the last step. */
cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
gwl_seat_cursor_visible_set(seat, use_visible, is_hardware_cursor, CURSOR_VISIBLE_ONLY_SHOW);
#ifdef USE_GNOME_CONFINE_HACK
seat->use_pointer_software_confine = use_software_confine;

View File

@ -1785,8 +1785,6 @@ GHOST_TCapabilityFlag GHOST_SystemX11::getCapabilities() const
{
return GHOST_TCapabilityFlag(GHOST_CAPABILITY_FLAG_ALL &
~(
/* No support yet for desktop sampling. */
GHOST_kCapabilityDesktopSample |
/* No support yet for image copy/paste. */
GHOST_kCapabilityClipboardImages |
/* No support yet for IME input methods. */

View File

@ -62,29 +62,37 @@ static constexpr size_t base_dpi = 96;
#endif
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
struct WGL_LibDecor_Window {
struct GWL_LibDecor_Window {
libdecor_frame *frame = nullptr;
/**
* Used at startup to set the initial window size
* (before fractional scale information is available).
* Store the last size applied from #libdecor_frame_interface::configure
* This is meant to be equivalent of calling:
* `libdecor_frame_get_content_width(frame)`
* `libdecor_frame_get_content_height(frame)`
* However these functions are only available via the plugin API,
* so they need to be stored somewhere.
*/
int scale_fractional_from_output = 0;
struct {
int32_t size[2] = {0, 0};
} applied;
/** The window has been configured (see #xdg_surface_ack_configure). */
bool initial_configure_seen = false;
/** The window size has been configured. */
bool initial_configure_seen_with_size = false;
/** The window state has been configured. */
bool initial_state_seen = false;
};
static void gwl_libdecor_window_destroy(WGL_LibDecor_Window *decor)
static void gwl_libdecor_window_destroy(GWL_LibDecor_Window *decor)
{
libdecor_frame_unref(decor->frame);
delete decor;
}
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
struct WGL_XDG_Decor_Window {
struct GWL_XDG_Decor_Window {
xdg_surface *surface = nullptr;
zxdg_toplevel_decoration_v1 *toplevel_decor = nullptr;
xdg_toplevel *toplevel = nullptr;
@ -105,7 +113,7 @@ struct WGL_XDG_Decor_Window {
bool initial_configure_seen = false;
};
static void gwl_xdg_decor_window_destroy(WGL_XDG_Decor_Window *decor)
static void gwl_xdg_decor_window_destroy(GWL_XDG_Decor_Window *decor)
{
if (decor->toplevel_decor) {
zxdg_toplevel_decoration_v1_destroy(decor->toplevel_decor);
@ -295,9 +303,9 @@ struct GWL_Window {
std::vector<GWL_Output *> outputs;
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
WGL_LibDecor_Window *libdecor = nullptr;
GWL_LibDecor_Window *libdecor = nullptr;
#endif
WGL_XDG_Decor_Window *xdg_decor = nullptr;
GWL_XDG_Decor_Window *xdg_decor = nullptr;
/**
* The current value of frame, copied from `frame_pending` when applying updates.
@ -352,13 +360,13 @@ static void gwl_window_title_set(GWL_Window *win, const char *title)
{
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
WGL_LibDecor_Window &decor = *win->libdecor;
GWL_LibDecor_Window &decor = *win->libdecor;
libdecor_frame_set_title(decor.frame, title);
}
else
#endif
{
WGL_XDG_Decor_Window &decor = *win->xdg_decor;
GWL_XDG_Decor_Window &decor = *win->xdg_decor;
xdg_toplevel_set_title(decor.toplevel, title);
}
@ -669,16 +677,9 @@ static void gwl_window_activate(GWL_Window *win)
/** \name Internal #GWL_Window Pending Actions
* \{ */
static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win,
bool *r_surface_needs_commit,
bool *r_surface_needs_buffer_scale)
static void gwl_window_frame_pending_fractional_scale_set_notest(
GWL_Window *win, bool *r_surface_needs_commit, bool *r_surface_needs_buffer_scale)
{
if (win->frame_pending.fractional_scale == win->frame.fractional_scale &&
win->frame_pending.buffer_scale == win->frame.buffer_scale)
{
return;
}
if (win->frame_pending.fractional_scale) {
win->frame.fractional_scale = win->frame_pending.fractional_scale;
gwl_window_viewport_set(win, r_surface_needs_commit, r_surface_needs_buffer_scale);
@ -706,6 +707,19 @@ static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win,
}
}
static void gwl_window_frame_pending_fractional_scale_set(GWL_Window *win,
bool *r_surface_needs_commit,
bool *r_surface_needs_buffer_scale)
{
if (win->frame_pending.fractional_scale == win->frame.fractional_scale &&
win->frame_pending.buffer_scale == win->frame.buffer_scale)
{
return;
}
gwl_window_frame_pending_fractional_scale_set_notest(
win, r_surface_needs_commit, r_surface_needs_buffer_scale);
}
static void gwl_window_frame_pending_size_set(GWL_Window *win,
bool *r_surface_needs_commit,
bool *r_surface_needs_resize_for_backend,
@ -830,7 +844,7 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
}
if (win->xdg_decor) {
WGL_XDG_Decor_Window &decor = *win->xdg_decor;
GWL_XDG_Decor_Window &decor = *win->xdg_decor;
if (decor.pending.ack_configure) {
xdg_surface_ack_configure(decor.surface, decor.pending.ack_configure_serial);
/* The XDG spec states a commit event is required after ACK configure. */
@ -885,7 +899,7 @@ static void gwl_window_frame_update_from_pending_no_lock(GWL_Window *win)
win->frame_pending.size[1] = 0;
}
static void gwl_window_frame_update_from_pending(GWL_Window *win)
[[maybe_unused]] static void gwl_window_frame_update_from_pending(GWL_Window *win)
{
#ifdef USE_EVENT_BACKGROUND_THREAD
std::lock_guard lock_frame_guard{win->frame_pending_mutex};
@ -1150,20 +1164,27 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
}();
# endif
GWL_WindowFrame *frame_pending = &static_cast<GWL_Window *>(data)->frame_pending;
GWL_WindowFrame &frame_pending = static_cast<GWL_Window *>(data)->frame_pending;
/* Set the size. */
int size_decor[2] = {
libdecor_frame_get_content_width(frame),
libdecor_frame_get_content_height(frame),
};
int size_next[2] = {0, 0};
bool has_size = false;
/* Keep track the current size of window decorations (last set by this function). */
int size_decor[2] = {0, 0};
{
const GWL_Window *win = static_cast<GWL_Window *>(data);
const GWL_LibDecor_Window &decor = *win->libdecor;
if (decor.initial_configure_seen_with_size) {
size_decor[0] = decor.applied.size[0];
size_decor[1] = decor.applied.size[1];
}
}
{
GWL_Window *win = static_cast<GWL_Window *>(data);
const int fractional_scale = win->frame.fractional_scale ?
win->frame.fractional_scale :
win->libdecor->scale_fractional_from_output;
const int fractional_scale = win->frame.fractional_scale;
/* It's important `fractional_scale` has a fractional component or rounding up will fail
* to produce the correct whole-number scale. */
GHOST_ASSERT((fractional_scale == 0) ||
@ -1177,26 +1198,24 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
const int scale_as_fractional = scale * FRACTIONAL_DENOMINATOR;
if (libdecor_configuration_get_content_size(
configuration, frame, &size_next[0], &size_next[1])) {
if (win->frame.fractional_scale) {
win->frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[0]);
win->frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame,
size_next[1]);
if (fractional_scale) {
frame_pending.size[0] = gwl_window_fractional_to_viewport_round(win->frame, size_next[0]);
frame_pending.size[1] = gwl_window_fractional_to_viewport_round(win->frame, size_next[1]);
}
else if (fractional_scale && (fractional_scale != (scale * FRACTIONAL_DENOMINATOR))) {
/* The windows `preferred_scale` is not yet available,
* set the size as if fractional scale is available. */
frame_pending->size[0] = ((size_next[0] * scale) * fractional_scale) / scale_as_fractional;
frame_pending->size[1] = ((size_next[1] * scale) * fractional_scale) / scale_as_fractional;
frame_pending.size[0] = ((size_next[0] * scale) * fractional_scale) / scale_as_fractional;
frame_pending.size[1] = ((size_next[1] * scale) * fractional_scale) / scale_as_fractional;
}
else {
frame_pending->size[0] = size_next[0] * scale;
frame_pending->size[1] = size_next[1] * scale;
frame_pending.size[0] = size_next[0] * scale;
frame_pending.size[1] = size_next[1] * scale;
}
/* Account for buffer rounding requirement, once fractional scaling is enabled
* the buffer scale will be 1, rounding is a requirement until then. */
gwl_round_int2_by(frame_pending->size, win->frame.buffer_scale);
gwl_round_int2_by(frame_pending.size, win->frame.buffer_scale);
has_size = true;
}
@ -1218,25 +1237,15 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
}
}
}
# ifdef USE_EVENT_BACKGROUND_THREAD
/* NOTE(@ideasman42): when running from the event handling thread,
* don't apply the new window size back to LIBDECOR, otherwise the window content
* (which uses a deferred update) and the window get noticeably out of sync.
* Rely on the new `frame_pending->size` to resize the window later. */
if (is_main_thread == false) {
has_size = false;
}
# endif
}
/* Set the state. */
{
enum libdecor_window_state window_state;
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
frame_pending->is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
frame_pending->is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
frame_pending->is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
frame_pending.is_maximised = window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED;
frame_pending.is_fullscreen = window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN;
frame_pending.is_active = window_state & LIBDECOR_WINDOW_STATE_ACTIVE;
}
}
@ -1257,18 +1266,23 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
/* Commit the changes. */
{
GWL_Window *win = static_cast<GWL_Window *>(data);
WGL_LibDecor_Window &decor = *win->libdecor;
GWL_LibDecor_Window &decor = *win->libdecor;
if (has_size == false) {
/* Keep the current decor size. */
size_next[0] = size_decor[0];
size_next[1] = size_decor[1];
}
libdecor_state *state = libdecor_state_new(UNPACK2(size_next));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
else {
/* Store the new size for later reuse. */
decor.applied.size[0] = size_next[0];
decor.applied.size[1] = size_next[1];
}
/* Only ever use this once, after initial creation:
* #wp_fractional_scale_v1_listener::preferred_scale provides fractional scaling values. */
decor.scale_fractional_from_output = 0;
if (size_next[0] && size_next[1]) {
libdecor_state *state = libdecor_state_new(UNPACK2(size_next));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
}
if (decor.initial_configure_seen == false) {
decor.initial_configure_seen = true;
@ -1278,6 +1292,11 @@ static void libdecor_frame_handle_configure(libdecor_frame *frame,
decor.initial_state_seen = true;
}
}
if (decor.initial_configure_seen_with_size == false) {
if (size_next[0] && size_next[1]) {
decor.initial_configure_seen_with_size = true;
}
}
}
}
@ -1489,25 +1508,18 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
* So leave the buffer scaled up because there is no *guarantee* the fractional scaling support
* will run which could result in an incorrect buffer scale. */
int scale_fractional_from_output;
window_->frame.buffer_scale = outputs_uniform_scale_or_default(
system_->outputs_get(), 1, &scale_fractional_from_output);
window_->frame_pending.buffer_scale = window_->frame.buffer_scale;
const int buffer_scale_from_output = outputs_uniform_scale_or_default(
system_->outputs_get(), 0, &scale_fractional_from_output);
window_->frame.size[0] = int32_t(width);
window_->frame.size[1] = int32_t(height);
/* The window surface must be rounded to the scale,
* failing to do so causes the WAYLAND-server to close the window immediately. */
gwl_round_int2_by(window_->frame.size, window_->frame.buffer_scale);
window_->is_dialog = is_dialog;
/* Window surfaces. */
window_->wl.surface = wl_compositor_create_surface(system_->wl_compositor_get());
ghost_wl_surface_tag(window_->wl.surface);
wl_surface_set_buffer_scale(window_->wl.surface, window_->frame.buffer_scale);
wl_surface_add_listener(window_->wl.surface, &wl_surface_listener, window_);
wp_fractional_scale_manager_v1 *fractional_scale_manager =
@ -1529,8 +1541,8 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
window_->libdecor = new WGL_LibDecor_Window;
WGL_LibDecor_Window &decor = *window_->libdecor;
window_->libdecor = new GWL_LibDecor_Window;
GWL_LibDecor_Window &decor = *window_->libdecor;
/* create window decorations */
decor.frame = libdecor_decorate(
@ -1541,7 +1553,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
libdecor_frame_set_app_id(decor.frame, xdg_app_id);
if (parentWindow) {
WGL_LibDecor_Window &decor_parent =
GWL_LibDecor_Window &decor_parent =
*dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->window_->libdecor;
libdecor_frame_set_parent(decor.frame, decor_parent.frame);
}
@ -1549,8 +1561,8 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
else
#endif
{
window_->xdg_decor = new WGL_XDG_Decor_Window;
WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
window_->xdg_decor = new GWL_XDG_Decor_Window;
GWL_XDG_Decor_Window &decor = *window_->xdg_decor;
decor.surface = xdg_wm_base_get_xdg_surface(system_->xdg_decor_shell_get(),
window_->wl.surface);
decor.toplevel = xdg_surface_get_toplevel(decor.surface);
@ -1562,7 +1574,7 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
xdg_toplevel_add_listener(decor.toplevel, &xdg_toplevel_listener, window_);
if (parentWindow && is_dialog) {
WGL_XDG_Decor_Window &decor_parent =
GWL_XDG_Decor_Window &decor_parent =
*dynamic_cast<const GHOST_WindowWayland *>(parentWindow)->window_->xdg_decor;
xdg_toplevel_set_parent(decor.toplevel, decor_parent.toplevel);
}
@ -1578,15 +1590,131 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
/* Causes a glitch with `libdecor` for some reason. */
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
WGL_LibDecor_Window &decor = *window_->libdecor;
if (fractional_scale_manager &&
(gwl_round_int_test(scale_fractional_from_output, FRACTIONAL_DENOMINATOR) == false))
{
decor.scale_fractional_from_output = scale_fractional_from_output;
/* Pass. */
}
else
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
{
GWL_XDG_Decor_Window &decor = *window_->xdg_decor;
if (system_->xdg_decor_manager_get()) {
decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
system_->xdg_decor_manager_get(), decor.toplevel);
zxdg_toplevel_decoration_v1_add_listener(
decor.toplevel_decor, &xdg_toplevel_decoration_v1_listener, window_);
zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
/* Commit needed to so configure callback runs. */
wl_surface_commit(window_->wl.surface);
while (!decor.initial_configure_seen) {
wl_display_flush(system->wl_display_get());
wl_display_dispatch(system->wl_display_get());
}
}
/* If the scale is known early, setup the window scale.
* Otherwise accept an unsightly flicker once the outputs scale can be found. */
int early_buffer_scale = 0;
int early_fractional_scale = 0;
if (const int test_fractional_scale =
fractional_scale_manager ? (window_->frame_pending.fractional_scale_preferred ?
window_->frame_pending.fractional_scale_preferred :
scale_fractional_from_output) :
0)
{
if (!gwl_round_int_test(test_fractional_scale, FRACTIONAL_DENOMINATOR)) {
early_fractional_scale = test_fractional_scale;
}
else {
/* Rounded, use simple integer buffer scaling. */
early_buffer_scale = test_fractional_scale / FRACTIONAL_DENOMINATOR;
early_fractional_scale = 0;
}
}
else if (buffer_scale_from_output) {
early_buffer_scale = buffer_scale_from_output;
}
if (early_fractional_scale != 0) {
/* Fractional scale is known. */
window_->frame.fractional_scale_preferred = early_fractional_scale;
window_->frame.fractional_scale = early_fractional_scale;
window_->frame.buffer_scale = 1;
window_->frame_pending.fractional_scale_preferred = early_fractional_scale;
window_->frame_pending.fractional_scale = early_fractional_scale;
window_->frame_pending.buffer_scale = 1;
/* The scale is considered initialized now. */
window_->frame_pending.is_scale_init = true;
/* Always commit and set the scale. */
bool surface_needs_commit_dummy = false, surface_needs_buffer_scale_dummy = false;
gwl_window_frame_pending_fractional_scale_set_notest(
window_, &surface_needs_commit_dummy, &surface_needs_buffer_scale_dummy);
}
else if (early_buffer_scale != 0) {
/* Non-fractional scale is known. */
/* No fractional scale, simple initialization. */
window_->frame.buffer_scale = early_buffer_scale;
window_->frame_pending.buffer_scale = early_buffer_scale;
/* The scale is considered initialized now. */
window_->frame_pending.is_scale_init = true;
/* The window surface must be rounded to the scale,
* failing to do so causes the WAYLAND-server to close the window immediately. */
gwl_round_int2_by(window_->frame.size, window_->frame.buffer_scale);
}
else {
/* Scale isn't known (the windows size may flicker when #outputs_changed_update_scale runs). */
window_->frame.buffer_scale = 1;
window_->frame_pending.buffer_scale = 1;
GHOST_ASSERT(window_->frame_pending.is_scale_init == false,
"An initialized scale is not expected");
}
if (window_->frame_pending.is_scale_init) {
/* If the output scale changes here it means the scale settings were not properly set. */
GHOST_ASSERT(outputs_changed_update_scale() == false,
"Fractional scale was not properly initialized");
}
wl_surface_set_buffer_scale(window_->wl.surface, window_->frame.buffer_scale);
/* Postpone binding the buffer until after it's decor has been configured:
* - Ensure the window is sized properly (with XDG window decorations), see: #113059.
* - Avoids flickering on startup.
*/
#ifdef WITH_OPENGL_BACKEND
if (type == GHOST_kDrawingContextTypeOpenGL) {
window_->backend.egl_window = wl_egl_window_create(
window_->wl.surface, int(window_->frame.size[0]), int(window_->frame.size[1]));
}
#endif
#ifdef WITH_VULKAN_BACKEND
if (type == GHOST_kDrawingContextTypeVulkan) {
window_->backend.vulkan_window_info = new GHOST_ContextVK_WindowInfo;
window_->backend.vulkan_window_info->size[0] = window_->frame.size[0];
window_->backend.vulkan_window_info->size[1] = window_->frame.size[1];
}
#endif
/* Drawing context. */
if (setDrawingContextType(type) == GHOST_kFailure) {
GHOST_PRINT("Failed to create drawing context" << std::endl);
}
#ifdef WITH_GHOST_WAYLAND_LIBDECOR
if (use_libdecor) {
/* Commit needed so the top-level callbacks run (and `toplevel` can be accessed). */
wl_surface_commit(window_->wl.surface);
GWL_LibDecor_Window &decor = *window_->libdecor;
/* Additional round-trip is needed to ensure `xdg_toplevel` is set. */
wl_display_roundtrip(system_->wl_display_get());
@ -1618,53 +1746,14 @@ GHOST_WindowWayland::GHOST_WindowWayland(GHOST_SystemWayland *system,
else
#endif /* WITH_GHOST_WAYLAND_LIBDECOR */
{
WGL_XDG_Decor_Window &decor = *window_->xdg_decor;
if (system_->xdg_decor_manager_get()) {
decor.toplevel_decor = zxdg_decoration_manager_v1_get_toplevel_decoration(
system_->xdg_decor_manager_get(), decor.toplevel);
zxdg_toplevel_decoration_v1_add_listener(
decor.toplevel_decor, &xdg_toplevel_decoration_v1_listener, window_);
zxdg_toplevel_decoration_v1_set_mode(decor.toplevel_decor,
ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}
gwl_window_state_set(window_, state);
/* Commit needed to so configure callback runs. */
wl_surface_commit(window_->wl.surface);
while (!decor.initial_configure_seen) {
wl_display_flush(system->wl_display_get());
wl_display_dispatch(system->wl_display_get());
}
}
/* Postpone binding the buffer until after it's decor has been configured:
* - Ensure the window is sized properly (with XDG window decorations), see: #113059.
* - Avoids flickering on startup.
*/
#ifdef WITH_OPENGL_BACKEND
if (type == GHOST_kDrawingContextTypeOpenGL) {
window_->backend.egl_window = wl_egl_window_create(
window_->wl.surface, int(window_->frame.size[0]), int(window_->frame.size[1]));
}
#endif
#ifdef WITH_VULKAN_BACKEND
if (type == GHOST_kDrawingContextTypeVulkan) {
window_->backend.vulkan_window_info = new GHOST_ContextVK_WindowInfo;
window_->backend.vulkan_window_info->size[0] = window_->frame.size[0];
window_->backend.vulkan_window_info->size[1] = window_->frame.size[1];
}
#endif
/* Commit after setting the buffer. */
/* Commit after setting the buffer.
* While postponing until after the buffer drawing is context is set
* isn't essential, it reduces flickering. */
wl_surface_commit(window_->wl.surface);
/* Drawing context. */
if (setDrawingContextType(type) == GHOST_kFailure) {
GHOST_PRINT("Failed to create drawing context" << std::endl);
}
/* Set swap interval to 0 to prevent blocking. */
setSwapInterval(0);
}

View File

@ -51,6 +51,9 @@
*
* - Lock #GWL_Window.frame_pending_mutex before changing window size & frame settings,
* this is flushed in #GHOST_WindowWayland::pending_actions_handle.
*
* \note Keep this define as it can be useful to disable threading when troubleshooting
* issues with events.
*/
#define USE_EVENT_BACKGROUND_THREAD

View File

@ -10,11 +10,11 @@ set(INC_SYS
)
set(SRC
opensubdiv_capi.h
opensubdiv_capi_type.h
opensubdiv_converter_capi.h
opensubdiv_evaluator_capi.h
opensubdiv_topology_refiner_capi.h
opensubdiv_capi.hh
opensubdiv_capi_type.hh
opensubdiv_converter_capi.hh
opensubdiv_evaluator_capi.hh
opensubdiv_topology_refiner_capi.hh
)
set(LIB

View File

@ -2,7 +2,7 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "opensubdiv_capi.h"
#include "opensubdiv_capi.hh"
#include "opensubdiv/version.h"
#ifdef _MSC_VER
# include <iso646.h>

View File

@ -14,7 +14,7 @@
#include <opensubdiv/sdc/options.h>
#include <opensubdiv/sdc/types.h>
#include "opensubdiv_capi_type.h"
#include "opensubdiv_capi_type.hh"
struct OpenSubdiv_Converter;

View File

@ -15,7 +15,7 @@
#include "internal/base/type.h"
#include "internal/evaluator/evaluator_impl.h"
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_evaluator_capi.hh"
using OpenSubdiv::Far::PatchTable;
using OpenSubdiv::Far::StencilTable;

View File

@ -6,7 +6,7 @@
#include "internal/evaluator/eval_output_gpu.h"
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_evaluator_capi.hh"
using OpenSubdiv::Osd::PatchArray;
using OpenSubdiv::Osd::PatchArrayVector;

View File

@ -7,7 +7,7 @@
#include "internal/base/memory.h"
#include "opensubdiv_capi_type.h"
#include "opensubdiv_capi_type.hh"
struct OpenSubdiv_EvaluatorCacheImpl {
public:

View File

@ -4,7 +4,7 @@
*
* Author: Sergey Sharybin. */
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_evaluator_capi.hh"
#include <opensubdiv/osd/glslPatchShaderSource.h>

View File

@ -28,8 +28,8 @@
#include "internal/evaluator/evaluator_cache_impl.h"
#include "internal/evaluator/patch_map.h"
#include "internal/topology/topology_refiner_impl.h"
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_topology_refiner_capi.h"
#include "opensubdiv_evaluator_capi.hh"
#include "opensubdiv_topology_refiner_capi.hh"
using OpenSubdiv::Far::PatchTable;
using OpenSubdiv::Far::PatchTableFactory;

View File

@ -16,7 +16,7 @@
#include "internal/base/memory.h"
#include "opensubdiv_capi_type.h"
#include "opensubdiv_capi_type.hh"
struct OpenSubdiv_Buffer;
struct OpenSubdiv_EvaluatorCacheImpl;

View File

@ -12,7 +12,7 @@
#include "internal/base/type.h"
#include "opensubdiv_converter_capi.h"
#include "opensubdiv_converter_capi.hh"
namespace blender {
namespace opensubdiv {

View File

@ -4,7 +4,7 @@
*
* Author: Sergey Sharybin. */
#include "opensubdiv_topology_refiner_capi.h"
#include "opensubdiv_topology_refiner_capi.hh"
#include "MEM_guardedalloc.h"
#include "internal/base/type_convert.h"

View File

@ -19,7 +19,7 @@
#include "internal/base/type_convert.h"
#include "internal/topology/mesh_topology.h"
#include "opensubdiv_converter_capi.h"
#include "opensubdiv_converter_capi.hh"
using blender::opensubdiv::min;
using blender::opensubdiv::stack;

View File

@ -15,7 +15,7 @@
#include "internal/base/memory.h"
#include "internal/topology/mesh_topology.h"
#include "opensubdiv_topology_refiner_capi.h"
#include "opensubdiv_topology_refiner_capi.hh"
struct OpenSubdiv_Converter;

View File

@ -11,7 +11,7 @@
#include "internal/topology/mesh_topology.h"
#include "internal/topology/topology_refiner_impl.h"
#include "opensubdiv_converter_capi.h"
#include "opensubdiv_converter_capi.hh"
namespace blender {
namespace opensubdiv {

View File

@ -1,28 +0,0 @@
/* SPDX-FileCopyrightText: 2013 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
#ifndef OPENSUBDIV_CAPI_H_
#define OPENSUBDIV_CAPI_H_
#include "opensubdiv_capi_type.h"
#ifdef __cplusplus
extern "C" {
#endif
// Global initialization/deinitialization.
//
// Supposed to be called from main thread.
void openSubdiv_init(void);
void openSubdiv_cleanup(void);
int openSubdiv_getVersionHex(void);
#ifdef __cplusplus
}
#endif
#endif // OPENSUBDIV_CAPI_H_

View File

@ -0,0 +1,15 @@
/* SPDX-FileCopyrightText: 2013 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include "opensubdiv_capi_type.hh"
// Global initialization/deinitialization.
//
// Supposed to be called from main thread.
void openSubdiv_init();
void openSubdiv_cleanup();
int openSubdiv_getVersionHex();

View File

@ -1,54 +1,41 @@
/* SPDX-FileCopyrightText: 2013 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENSUBDIV_CAPI_TYPES_H_
#define OPENSUBDIV_CAPI_TYPES_H_
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef enum eOpenSubdivEvaluator {
enum eOpenSubdivEvaluator {
OPENSUBDIV_EVALUATOR_CPU = 0,
OPENSUBDIV_EVALUATOR_GPU = 1,
} eOpenSubdivEvaluator;
};
typedef enum OpenSubdiv_SchemeType {
enum OpenSubdiv_SchemeType {
OSD_SCHEME_BILINEAR,
OSD_SCHEME_CATMARK,
OSD_SCHEME_LOOP,
} OpenSubdiv_SchemeType;
};
typedef enum OpenSubdiv_VtxBoundaryInterpolation {
enum OpenSubdiv_VtxBoundaryInterpolation {
// Do not interpolate boundaries
OSD_VTX_BOUNDARY_NONE,
// Sharpen edges.
OSD_VTX_BOUNDARY_EDGE_ONLY,
// sharpen edges and corners,
OSD_VTX_BOUNDARY_EDGE_AND_CORNER,
} OpenSubdiv_VtxBoundaryInterpolation;
};
typedef enum OpenSubdiv_FVarLinearInterpolation {
enum OpenSubdiv_FVarLinearInterpolation {
OSD_FVAR_LINEAR_INTERPOLATION_NONE,
OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_ONLY,
OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS1,
OSD_FVAR_LINEAR_INTERPOLATION_CORNERS_PLUS2,
OSD_FVAR_LINEAR_INTERPOLATION_BOUNDARIES,
OSD_FVAR_LINEAR_INTERPOLATION_ALL,
} OpenSubdiv_FVarLinearInterpolation;
};
typedef struct OpenSubdiv_PatchCoord {
struct OpenSubdiv_PatchCoord {
int ptex_face;
// Parametric location on patch.
float u, v;
} OpenSubdiv_PatchCoord;
#ifdef __cplusplus
}
#endif
#endif // OPENSUBDIV_CAPI_TYPES_H_
};

View File

@ -1,27 +1,20 @@
/* SPDX-FileCopyrightText: 2015 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENSUBDIV_CONVERTER_CAPI_H_
#define OPENSUBDIV_CONVERTER_CAPI_H_
#pragma once
#include <stdint.h> // for bool
#include <cstdint> // for bool
#include "opensubdiv_capi_type.h"
#include "opensubdiv_capi_type.hh"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct OpenSubdiv_Converter {
OpenSubdiv_SchemeType (*getSchemeType)(const struct OpenSubdiv_Converter *converter);
struct OpenSubdiv_Converter {
OpenSubdiv_SchemeType (*getSchemeType)(const OpenSubdiv_Converter *converter);
OpenSubdiv_VtxBoundaryInterpolation (*getVtxBoundaryInterpolation)(
const struct OpenSubdiv_Converter *converter);
const OpenSubdiv_Converter *converter);
OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)(
const struct OpenSubdiv_Converter *converter);
const OpenSubdiv_Converter *converter);
// Denotes whether this converter specifies full topology, which includes
// vertices, edges, faces, vertices+edges of a face and edges/faces of a
@ -32,29 +25,29 @@ typedef struct OpenSubdiv_Converter {
// NOTE: Even if converter does not provide full topology, it still needs
// to provide number of edges and vertices-of-edge. Those are used to assign
// topology tags.
bool (*specifiesFullTopology)(const struct OpenSubdiv_Converter *converter);
bool (*specifiesFullTopology)(const OpenSubdiv_Converter *converter);
//////////////////////////////////////////////////////////////////////////////
// Global geometry counters.
// Number of faces/edges/vertices in the base mesh.
int (*getNumFaces)(const struct OpenSubdiv_Converter *converter);
int (*getNumEdges)(const struct OpenSubdiv_Converter *converter);
int (*getNumVertices)(const struct OpenSubdiv_Converter *converter);
int (*getNumFaces)(const OpenSubdiv_Converter *converter);
int (*getNumEdges)(const OpenSubdiv_Converter *converter);
int (*getNumVertices)(const OpenSubdiv_Converter *converter);
//////////////////////////////////////////////////////////////////////////////
// Face relationships.
// Number of vertices the face consists of.
int (*getNumFaceVertices)(const struct OpenSubdiv_Converter *converter, const int face_index);
int (*getNumFaceVertices)(const OpenSubdiv_Converter *converter, const int face_index);
// Array of vertex indices the face consists of.
void (*getFaceVertices)(const struct OpenSubdiv_Converter *converter,
void (*getFaceVertices)(const OpenSubdiv_Converter *converter,
const int face_index,
int *face_vertices);
// Array of edge indices the face consists of.
// Aligned with the vertex indices array, edge i connects face vertex i
// with face index i+1.
void (*getFaceEdges)(const struct OpenSubdiv_Converter *converter,
void (*getFaceEdges)(const OpenSubdiv_Converter *converter,
const int face_index,
int *face_edges);
@ -62,42 +55,38 @@ typedef struct OpenSubdiv_Converter {
// Edge relationships.
// Vertices the edge consists of.
void (*getEdgeVertices)(const struct OpenSubdiv_Converter *converter,
void (*getEdgeVertices)(const OpenSubdiv_Converter *converter,
const int edge_index,
int edge_vertices[2]);
// Number of faces which are sharing the given edge.
int (*getNumEdgeFaces)(const struct OpenSubdiv_Converter *converter, const int edge_index);
int (*getNumEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge_index);
// Array of face indices which are sharing the given edge.
void (*getEdgeFaces)(const struct OpenSubdiv_Converter *converter,
const int edge,
int *edge_faces);
void (*getEdgeFaces)(const OpenSubdiv_Converter *converter, const int edge, int *edge_faces);
// Edge sharpness (aka crease).
float (*getEdgeSharpness)(const struct OpenSubdiv_Converter *converter, const int edge_index);
float (*getEdgeSharpness)(const OpenSubdiv_Converter *converter, const int edge_index);
//////////////////////////////////////////////////////////////////////////////
// Vertex relationships.
// Number of edges which are adjacent to the given vertex.
int (*getNumVertexEdges)(const struct OpenSubdiv_Converter *converter, const int vertex_index);
int (*getNumVertexEdges)(const OpenSubdiv_Converter *converter, const int vertex_index);
// Array fo edge indices which are adjacent to the given vertex.
void (*getVertexEdges)(const struct OpenSubdiv_Converter *converter,
void (*getVertexEdges)(const OpenSubdiv_Converter *converter,
const int vertex_index,
int *vertex_edges);
// Number of faces which are adjacent to the given vertex.
int (*getNumVertexFaces)(const struct OpenSubdiv_Converter *converter, const int vertex_index);
int (*getNumVertexFaces)(const OpenSubdiv_Converter *converter, const int vertex_index);
// Array fo face indices which are adjacent to the given vertex.
void (*getVertexFaces)(const struct OpenSubdiv_Converter *converter,
void (*getVertexFaces)(const OpenSubdiv_Converter *converter,
const int vertex_index,
int *vertex_faces);
// Check whether vertex is to be marked as an infinite sharp.
// This is a way to make sharp vertices which are adjacent to a loose edges.
bool (*isInfiniteSharpVertex)(const struct OpenSubdiv_Converter *converter,
const int vertex_index);
bool (*isInfiniteSharpVertex)(const OpenSubdiv_Converter *converter, const int vertex_index);
// If vertex is not infinitely sharp, this is its actual sharpness.
float (*getVertexSharpness)(const struct OpenSubdiv_Converter *converter,
const int vertex_index);
float (*getVertexSharpness)(const OpenSubdiv_Converter *converter, const int vertex_index);
//////////////////////////////////////////////////////////////////////////////
// Face-varying data.
@ -106,7 +95,7 @@ typedef struct OpenSubdiv_Converter {
// UV coordinates.
// Number of UV layers.
int (*getNumUVLayers)(const struct OpenSubdiv_Converter *converter);
int (*getNumUVLayers)(const OpenSubdiv_Converter *converter);
// We need some corner connectivity information, which might not be trivial
// to be gathered (might require multiple matching calculations per corver
@ -116,27 +105,21 @@ typedef struct OpenSubdiv_Converter {
// complex complex-to-calculate information.
// finish() is called after converter is done porting UV layer to OpenSubdiv,
// allowing to free cached data.
void (*precalcUVLayer)(const struct OpenSubdiv_Converter *converter, const int layer_index);
void (*finishUVLayer)(const struct OpenSubdiv_Converter *converter);
void (*precalcUVLayer)(const OpenSubdiv_Converter *converter, const int layer_index);
void (*finishUVLayer)(const OpenSubdiv_Converter *converter);
// Get number of UV coordinates in the current layer (layer which was
// specified in precalcUVLayer().
int (*getNumUVCoordinates)(const struct OpenSubdiv_Converter *converter);
int (*getNumUVCoordinates)(const OpenSubdiv_Converter *converter);
// For the given face index and its corner (known as loop in Blender)
// get corresponding UV coordinate index.
int (*getFaceCornerUVIndex)(const struct OpenSubdiv_Converter *converter,
int (*getFaceCornerUVIndex)(const OpenSubdiv_Converter *converter,
const int face_index,
const int corner_index);
//////////////////////////////////////////////////////////////////////////////
// User data associated with this converter.
void (*freeUserData)(const struct OpenSubdiv_Converter *converter);
void (*freeUserData)(const OpenSubdiv_Converter *converter);
void *user_data;
} OpenSubdiv_Converter;
#ifdef __cplusplus
}
#endif
#endif /* OPENSUBDIV_CONVERTER_CAPI_H_ */
};

View File

@ -1,51 +1,46 @@
/* SPDX-FileCopyrightText: 2013 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENSUBDIV_EVALUATOR_CAPI_H_
#define OPENSUBDIV_EVALUATOR_CAPI_H_
#pragma once
#include <stdint.h> // for uint64_t
#include <cstdint> // for uint64_t
#include "opensubdiv_capi_type.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "opensubdiv_capi_type.hh"
struct OpenSubdiv_EvaluatorCacheImpl;
struct OpenSubdiv_EvaluatorImpl;
struct OpenSubdiv_EvaluatorInternal;
struct OpenSubdiv_PatchCoord;
struct OpenSubdiv_TopologyRefiner;
typedef struct OpenSubdiv_EvaluatorSettings {
struct OpenSubdiv_EvaluatorSettings {
// Number of smoothly interpolated vertex data channels.
int num_vertex_data;
} OpenSubdiv_EvaluatorSettings;
};
// Callback type for doing input/output operations on buffers.
// Useful to abstract GPU buffers.
typedef struct OpenSubdiv_Buffer {
struct OpenSubdiv_Buffer {
// Bind the buffer to the GPU.
void (*bind_gpu)(const struct OpenSubdiv_Buffer *buffer);
void (*bind_gpu)(const OpenSubdiv_Buffer *buffer);
// Allocate the buffer directly on the host for the given size in bytes. This has to return
// a pointer to the newly allocated memory.
void *(*alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size);
void *(*alloc)(const OpenSubdiv_Buffer *buffer, const unsigned int size);
// Allocate the buffer directly on the device for the given size in bytes.
void (*device_alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size);
void (*device_alloc)(const OpenSubdiv_Buffer *buffer, const unsigned int size);
// Update the given range of the buffer with new data.
void (*device_update)(const struct OpenSubdiv_Buffer *buffer,
void (*device_update)(const OpenSubdiv_Buffer *buffer,
unsigned int start,
unsigned int len,
const void *data);
// Wrap an existing GPU buffer, given its device handle, into the client's buffer type for
// read-only use.
void (*wrap_device_handle)(const struct OpenSubdiv_Buffer *buffer, uint64_t device_ptr);
void (*wrap_device_handle)(const OpenSubdiv_Buffer *buffer, uint64_t device_ptr);
// Offset in the buffer where the data starts, if a single buffer is used for multiple data
// channels.
@ -54,25 +49,25 @@ typedef struct OpenSubdiv_Buffer {
// Pointer to the client buffer data, which is modified or initialized through the various
// callbacks.
void *data;
} OpenSubdiv_Buffer;
};
typedef struct OpenSubdiv_Evaluator {
struct OpenSubdiv_Evaluator {
// Set settings for data buffers used.
void (*setSettings)(struct OpenSubdiv_Evaluator *evaluator,
void (*setSettings)(OpenSubdiv_Evaluator *evaluator,
const OpenSubdiv_EvaluatorSettings *settings);
// Set coarse positions from a continuous array of coordinates.
void (*setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator,
void (*setCoarsePositions)(OpenSubdiv_Evaluator *evaluator,
const float *positions,
const int start_vertex_index,
const int num_vertices);
// Set vertex data from a continuous array of coordinates.
void (*setVertexData)(struct OpenSubdiv_Evaluator *evaluator,
void (*setVertexData)(OpenSubdiv_Evaluator *evaluator,
const float *data,
const int start_vertex_index,
const int num_vertices);
// Set varying data from a continuous array of data.
void (*setVaryingData)(struct OpenSubdiv_Evaluator *evaluator,
void (*setVaryingData)(OpenSubdiv_Evaluator *evaluator,
const float *varying_data,
const int start_vertex_index,
const int num_vertices);
@ -80,7 +75,7 @@ typedef struct OpenSubdiv_Evaluator {
//
// TODO(sergey): Find a better name for vertex here. It is not the vertex of
// geometry, but a vertex of UV map.
void (*setFaceVaryingData)(struct OpenSubdiv_Evaluator *evaluator,
void (*setFaceVaryingData)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
const float *face_varying_data,
const int start_vertex_index,
@ -89,7 +84,7 @@ typedef struct OpenSubdiv_Evaluator {
// Set coarse vertex position from a continuous memory buffer where
// first coordinate starts at offset of `start_offset` and there is `stride`
// bytes between adjacent vertex coordinates.
void (*setCoarsePositionsFromBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*setCoarsePositionsFromBuffer)(OpenSubdiv_Evaluator *evaluator,
const void *buffer,
const int start_offset,
const int stride,
@ -98,7 +93,7 @@ typedef struct OpenSubdiv_Evaluator {
// Set varying data from a continuous memory buffer where
// first coordinate starts at offset of `start_offset` and there is `stride`
// bytes between adjacent vertex coordinates.
void (*setVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*setVaryingDataFromBuffer)(OpenSubdiv_Evaluator *evaluator,
const void *buffer,
const int start_offset,
const int stride,
@ -110,7 +105,7 @@ typedef struct OpenSubdiv_Evaluator {
//
// TODO(sergey): Find a better name for vertex here. It is not the vertex of
// geometry, but a vertex of UV map.
void (*setFaceVaryingDataFromBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*setFaceVaryingDataFromBuffer)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
const void *buffer,
const int start_offset,
@ -119,11 +114,11 @@ typedef struct OpenSubdiv_Evaluator {
const int num_vertices);
// Refine after coarse positions update.
void (*refine)(struct OpenSubdiv_Evaluator *evaluator);
void (*refine)(OpenSubdiv_Evaluator *evaluator);
// Evaluate given ptex face at given bilinear coordinate.
// If derivatives are NULL, they will not be evaluated.
void (*evaluateLimit)(struct OpenSubdiv_Evaluator *evaluator,
void (*evaluateLimit)(OpenSubdiv_Evaluator *evaluator,
const int ptex_face_index,
float face_u,
float face_v,
@ -132,14 +127,14 @@ typedef struct OpenSubdiv_Evaluator {
float dPdv[3]);
// Evaluate vertex data at a given bilinear coordinate of given ptex face.
void (*evaluateVertexData)(struct OpenSubdiv_Evaluator *evaluator,
void (*evaluateVertexData)(OpenSubdiv_Evaluator *evaluator,
const int ptex_face_index,
float face_u,
float face_v,
float data[]);
// Evaluate varying data at a given bilinear coordinate of given ptex face.
void (*evaluateVarying)(struct OpenSubdiv_Evaluator *evaluator,
void (*evaluateVarying)(OpenSubdiv_Evaluator *evaluator,
const int ptex_face_index,
float face_u,
float face_v,
@ -147,7 +142,7 @@ typedef struct OpenSubdiv_Evaluator {
// Evaluate face-varying data at a given bilinear coordinate of given
// ptex face.
void (*evaluateFaceVarying)(struct OpenSubdiv_Evaluator *evaluator,
void (*evaluateFaceVarying)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
const int ptex_face_index,
float face_u,
@ -160,79 +155,77 @@ typedef struct OpenSubdiv_Evaluator {
// If derivatives are NULL, they will not be evaluated.
//
// NOTE: Output arrays must point to a memory of size float[3]*num_patch_coords.
void (*evaluatePatchesLimit)(struct OpenSubdiv_Evaluator *evaluator,
const struct OpenSubdiv_PatchCoord *patch_coords,
void (*evaluatePatchesLimit)(OpenSubdiv_Evaluator *evaluator,
const OpenSubdiv_PatchCoord *patch_coords,
const int num_patch_coords,
float *P,
float *dPdu,
float *dPdv);
// Copy the patch map to the given buffers, and output some topology information.
void (*getPatchMap)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *patch_map_handles,
struct OpenSubdiv_Buffer *patch_map_quadtree,
void (*getPatchMap)(OpenSubdiv_Evaluator *evaluator,
OpenSubdiv_Buffer *patch_map_handles,
OpenSubdiv_Buffer *patch_map_quadtree,
int *min_patch_face,
int *max_patch_face,
int *max_depth,
int *patches_are_triangular);
// Fill the given buffer with data from the evaluator's patch array buffer.
void (*fillPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *patch_array_buffer);
void (*fillPatchArraysBuffer)(OpenSubdiv_Evaluator *evaluator,
OpenSubdiv_Buffer *patch_array_buffer);
// Fill the given buffer with data from the evaluator's patch index buffer.
void (*wrapPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *patch_index_buffer);
void (*wrapPatchIndexBuffer)(OpenSubdiv_Evaluator *evaluator,
OpenSubdiv_Buffer *patch_index_buffer);
// Fill the given buffer with data from the evaluator's patch parameter buffer.
void (*wrapPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *patch_param_buffer);
void (*wrapPatchParamBuffer)(OpenSubdiv_Evaluator *evaluator,
OpenSubdiv_Buffer *patch_param_buffer);
// Fill the given buffer with data from the evaluator's source buffer.
void (*wrapSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *src_buffer);
void (*wrapSrcBuffer)(OpenSubdiv_Evaluator *evaluator, OpenSubdiv_Buffer *src_buffer);
// Fill the given buffer with data from the evaluator's extra source buffer.
void (*wrapSrcVertexDataBuffer)(struct OpenSubdiv_Evaluator *evaluator,
struct OpenSubdiv_Buffer *src_buffer);
void (*wrapSrcVertexDataBuffer)(OpenSubdiv_Evaluator *evaluator, OpenSubdiv_Buffer *src_buffer);
// Fill the given buffer with data from the evaluator's face varying patch array buffer.
void (*fillFVarPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*fillFVarPatchArraysBuffer)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *patch_array_buffer);
OpenSubdiv_Buffer *patch_array_buffer);
// Fill the given buffer with data from the evaluator's face varying patch index buffer.
void (*wrapFVarPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*wrapFVarPatchIndexBuffer)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *patch_index_buffer);
OpenSubdiv_Buffer *patch_index_buffer);
// Fill the given buffer with data from the evaluator's face varying patch parameter buffer.
void (*wrapFVarPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*wrapFVarPatchParamBuffer)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *patch_param_buffer);
OpenSubdiv_Buffer *patch_param_buffer);
// Fill the given buffer with data from the evaluator's face varying source buffer.
void (*wrapFVarSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator,
void (*wrapFVarSrcBuffer)(OpenSubdiv_Evaluator *evaluator,
const int face_varying_channel,
struct OpenSubdiv_Buffer *src_buffer);
OpenSubdiv_Buffer *src_buffer);
// Return true if the evaluator has source vertex data set.
bool (*hasVertexData)(struct OpenSubdiv_Evaluator *evaluator);
bool (*hasVertexData)(OpenSubdiv_Evaluator *evaluator);
// Implementation of the evaluator.
struct OpenSubdiv_EvaluatorImpl *impl;
OpenSubdiv_EvaluatorImpl *impl;
// Type of the evaluator.
eOpenSubdivEvaluator type;
} OpenSubdiv_Evaluator;
};
typedef struct OpenSubdiv_EvaluatorCache {
struct OpenSubdiv_EvaluatorCache {
// Implementation of the evaluator cache.
struct OpenSubdiv_EvaluatorCacheImpl *impl;
} OpenSubdiv_EvaluatorCache;
OpenSubdiv_EvaluatorCacheImpl *impl;
};
OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner(
struct OpenSubdiv_TopologyRefiner *topology_refiner,
OpenSubdiv_TopologyRefiner *topology_refiner,
eOpenSubdivEvaluator evaluator_type,
OpenSubdiv_EvaluatorCache *evaluator_cache);
@ -245,9 +238,3 @@ void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache *evaluator_cache)
// Return the GLSL source code from the OpenSubDiv library used for patch evaluation.
// This function is not thread-safe.
const char *openSubdiv_getGLSLPatchBasisSource(void);
#ifdef __cplusplus
}
#endif
#endif // OPENSUBDIV_EVALUATOR_CAPI_H_

View File

@ -1,19 +1,12 @@
/* SPDX-FileCopyrightText: 2018 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* Author: Sergey Sharybin. */
* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
#define OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
#pragma once
#include <stdint.h> // for bool
#include <cstdint> // for bool
#include "opensubdiv_capi_type.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "opensubdiv_capi_type.hh"
struct OpenSubdiv_Converter;
struct OpenSubdiv_TopologyRefinerImpl;
@ -23,19 +16,19 @@ struct OpenSubdiv_TopologyRefinerImpl;
// make it possible to ensure we are not trying to abuse same OpenSubdiv's
// topology refiner with different subdivision levels or with different
// adaptive settings.
typedef struct OpenSubdiv_TopologyRefinerSettings {
struct OpenSubdiv_TopologyRefinerSettings {
bool is_adaptive;
int level;
} OpenSubdiv_TopologyRefinerSettings;
};
// C-style wrapper around actual topology refiner.
//
// The only purpose is to allow C-only code to access C++ implementation of the
// topology refiner.
typedef struct OpenSubdiv_TopologyRefiner {
struct OpenSubdiv_TopologyRefiner {
// Query subdivision level the refiner is created for.
int (*getSubdivisionLevel)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
bool (*getIsAdaptive)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getSubdivisionLevel)(const OpenSubdiv_TopologyRefiner *topology_refiner);
bool (*getIsAdaptive)(const OpenSubdiv_TopologyRefiner *topology_refiner);
// NOTE: All queries are querying base level.
//
@ -47,28 +40,27 @@ typedef struct OpenSubdiv_TopologyRefiner {
//////////////////////////////////////////////////////////////////////////////
// Query basic topology information from base level.
int (*getNumVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFaces)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
int (*getNumFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
void (*getFaceVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
void (*getFaceVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_vertices_indices);
int (*getNumFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
void (*getFaceEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
int (*getNumFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int face_index);
void (*getFaceEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
int *face_edges_indices);
void (*getEdgeVertices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
void (*getEdgeVertices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int edge_index,
int edge_vertices_indices[2]);
int (*getNumVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
int (*getNumVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index);
void (*getVertexEdges)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
void (*getVertexEdges)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int vertex_index,
int *vertex_edges_indices);
@ -82,9 +74,9 @@ typedef struct OpenSubdiv_TopologyRefiner {
// - Quad face consists of a single ptex face.
// - N-gons (similar to triangle) consists of N ptex faces, ordered same
// way as for triangle.
int (*getNumFacePtexFaces)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
int (*getNumFacePtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index);
int (*getNumPtexFaces)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumPtexFaces)(const OpenSubdiv_TopologyRefiner *topology_refiner);
// Initialize a per-base-face offset measured in ptex face indices.
//
@ -92,25 +84,24 @@ typedef struct OpenSubdiv_TopologyRefiner {
// faces created for bases faces [0 .. base_face_index - 1].
//
// The array must contain at least total number of ptex faces elements.
void (*fillFacePtexIndexOffset)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
void (*fillFacePtexIndexOffset)(const OpenSubdiv_TopologyRefiner *topology_refiner,
int *face_ptex_index_offset);
//////////////////////////////////////////////////////////////////////////////
// Face-varying data.
// Number of face-varying channels (or how they are called in Blender layers).
int (*getNumFVarChannels)(const struct OpenSubdiv_TopologyRefiner *topology_refiner);
int (*getNumFVarChannels)(const OpenSubdiv_TopologyRefiner *topology_refiner);
// Get face-varying interpolation type.
OpenSubdiv_FVarLinearInterpolation (*getFVarLinearInterpolation)(
const struct OpenSubdiv_TopologyRefiner *topology_refiner);
const OpenSubdiv_TopologyRefiner *topology_refiner);
// Get total number of face-varying values in a particular channel.
int (*getNumFVarValues)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int channel);
int (*getNumFVarValues)(const OpenSubdiv_TopologyRefiner *topology_refiner, const int channel);
// Get face-varying value indices associated with a particular face.
//
// This is an array of indices inside of face-varying array, array elements
// are aligned with face corners (or loops in Blender terminology).
const int *(*getFaceFVarValueIndices)(const struct OpenSubdiv_TopologyRefiner *topology_refiner,
const int *(*getFaceFVarValueIndices)(const OpenSubdiv_TopologyRefiner *topology_refiner,
const int face_index,
const int channel);
@ -118,13 +109,13 @@ typedef struct OpenSubdiv_TopologyRefiner {
// Internal use.
// Implementation of the topology refiner.
struct OpenSubdiv_TopologyRefinerImpl *impl;
} OpenSubdiv_TopologyRefiner;
OpenSubdiv_TopologyRefinerImpl *impl;
};
// NOTE: Will return NULL in cases of bad topology.
// NOTE: Mesh without faces is considered a bad topology.
OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter(
struct OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings);
OpenSubdiv_Converter *converter, const OpenSubdiv_TopologyRefinerSettings *settings);
void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner);
@ -135,11 +126,4 @@ void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refin
// and compare with existing refiner before going into more computationally
// complicated parts of subdivision process.
bool openSubdiv_topologyRefinerCompareWithConverter(
const OpenSubdiv_TopologyRefiner *topology_refiner,
const struct OpenSubdiv_Converter *converter);
#ifdef __cplusplus
}
#endif
#endif // OPENSUBDIV_TOPOLOGY_REFINER_CAPI_H_
const OpenSubdiv_TopologyRefiner *topology_refiner, const OpenSubdiv_Converter *converter);

View File

@ -4,7 +4,7 @@
*
* Author: Sergey Sharybin. */
#include "opensubdiv_evaluator_capi.h"
#include "opensubdiv_evaluator_capi.hh"
#include <cstddef>

View File

@ -4,7 +4,7 @@
*
* Author: Sergey Sharybin. */
#include "opensubdiv_capi.h"
#include "opensubdiv_capi.hh"
#include <cstddef>

View File

@ -4,7 +4,7 @@
*
* Author: Sergey Sharybin. */
#include "opensubdiv_topology_refiner_capi.h"
#include "opensubdiv_topology_refiner_capi.hh"
#include <cstddef>

View File

@ -21,8 +21,6 @@ WAYLAND_DYNLOAD_FN(libdecor_configuration_get_window_state)
WAYLAND_DYNLOAD_FN(libdecor_decorate)
WAYLAND_DYNLOAD_FN(libdecor_dispatch)
WAYLAND_DYNLOAD_FN(libdecor_frame_commit)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_content_height)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_content_width)
WAYLAND_DYNLOAD_FN(libdecor_frame_get_xdg_toplevel)
WAYLAND_DYNLOAD_FN(libdecor_frame_map)
WAYLAND_DYNLOAD_FN(libdecor_frame_set_app_id)
@ -78,8 +76,6 @@ struct WaylandDynload_Libdecor {
void WL_DYN_FN(libdecor_frame_commit)(struct libdecor_frame *frame,
struct libdecor_state *state,
struct libdecor_configuration *configuration);
int WL_DYN_FN(libdecor_frame_get_content_width)(struct libdecor_frame *frame);
int WL_DYN_FN(libdecor_frame_get_content_height)(struct libdecor_frame *frame);
struct xdg_toplevel *WL_DYN_FN(libdecor_frame_get_xdg_toplevel)(struct libdecor_frame *frame);
void WL_DYN_FN(libdecor_frame_map)(struct libdecor_frame *frame);
void WL_DYN_FN(libdecor_frame_set_app_id)(struct libdecor_frame *frame, const char *app_id);
@ -116,10 +112,6 @@ struct WaylandDynload_Libdecor {
# define libdecor_dispatch(...) (*wayland_dynload_libdecor.libdecor_dispatch)(__VA_ARGS__)
# define libdecor_frame_commit(...) \
(*wayland_dynload_libdecor.libdecor_frame_commit)(__VA_ARGS__)
# define libdecor_frame_get_content_height(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_content_height)(__VA_ARGS__)
# define libdecor_frame_get_content_width(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_content_width)(__VA_ARGS__)
# define libdecor_frame_get_xdg_toplevel(...) \
(*wayland_dynload_libdecor.libdecor_frame_get_xdg_toplevel)(__VA_ARGS__)
# define libdecor_frame_map(...) (*wayland_dynload_libdecor.libdecor_frame_map)(__VA_ARGS__)

View File

@ -17,6 +17,8 @@
8:French (Français):fr_FR
2:Japanese (日本語):ja_JP
47:Slovak (Slovenčina):sk_SK
41:Vietnamese (Tiếng Việt):vi_VN
13:Simplified Chinese (简体中文):zh_HANS
#
0:In Progress:
11:Czech (Čeština):cs_CZ
@ -28,15 +30,13 @@
12:Portuguese (Português):pt_PT
15:Russian (Русский):ru_RU
18:Ukrainian (Українська):uk_UA
41:Vietnamese (Tiếng Việt):vi_VN
13:Simplified Chinese (简体中文):zh_HANS
14:Traditional Chinese (繁體中文):zh_HANT
#
0:Starting:
45:Abkhaz (Аԥсуа бызшәа):ab
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #37:Amharic (አማርኛ):am_ET
21:Arabic (ﺔﻴﺑﺮﻌﻟﺍ):ar_EG
# Skipped (see IMPORT_LANGUAGES_SKIP in settings.py). #52:Belarusian (беларуску):be
52:Belarusian (беларуску):be
22:Bulgarian (Български):bg_BG
23:Greek (Ελληνικά):el_GR
35:Esperanto (Esperanto):eo

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"\"POT-Creation-Date: 2019-02-25 20:41:30\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2016-04-23 22:41+0300\n"
"Last-Translator: Yousef Harfoush <bat3a@msn.com>\n"
"Language-Team: Yousef Harfoush, Amine Moussaoui <bat3a@msn.com>\n"
@ -7373,6 +7373,18 @@ msgid "Whether this path is saved in bookmarks, or generated from OS"
msgstr "ﻡﺎﻈﻨﻟﺍ ﻦﻣ ﺓﺪﻟﻮﺘﻤﻟﺍ ﻭﺍ ﻦﻳﻭﺎﻨﻌﻟﺍ ﻲﻓ ﻅﻮﻔﺤﻣ ﺭﺎﺴﻤﻟﺍ ﺍﺬﻫ ﻥﺎﻛ ﺎﻣ ﺍﺫﺍ"
msgid "File Extensions"
msgstr "ﻒﻠﻤﻟﺍ ﺕﺎﺌﻴﻫ"
msgid "Operator"
msgstr "ﻞﻣﺎﻋ"
msgid "Label"
msgstr "ﻖﺼﻠﻣ"
msgid "Animations"
msgstr "ﺕﺎﻜﻳﺮﺤﺘﻟﺍ"
@ -11899,10 +11911,6 @@ msgid "Node tree consisting of linked nodes used for shading, textures and compo
msgstr "ﺐﻴﻛﺮﺘﻟﺍ ﻭ ,ﺔﺠﺴﻧﻷﺍ ,ﻞﻴﻠﻈﺘﻠﻟ ﺔﻣﺪﺨﺘﺴﻤﻟﺍ ﻭ ﺔﻄﺒﺗﺮﻤﻟﺍ ﺪﻘﻌﻟﺍ ﻦﻣ ﺔﻧﻮﻜﻤﻟﺍ ﺓﺪﻘﻌﻟﺍ ﺓﺮﺠﺷ"
msgid "Label"
msgstr "ﻖﺼﻠﻣ"
msgid "The node tree label"
msgstr "ﺓﺪﻘﻌﻟﺍ ﺓﺮﺠﺷ ﻖﺼﻠﻣ"
@ -27689,10 +27697,6 @@ msgid "Falloff Type"
msgstr "ﻲﺷﻼﺘﻟﺍ ﻉﻮﻧ"
msgid "Operator"
msgstr "ﻞﻣﺎﻋ"
msgid "Sharpen"
msgstr "ﺩﺎﺣ"
@ -29741,10 +29745,6 @@ msgid "Palette Color"
msgstr "ﻥﻮﻠﻟﺍ ﺔﺣﻮﻟ"
msgid "Refraction"
msgstr "ﺭﺎﺴﻜﻧﻻﺍ"
msgid "Integrator Presets"
msgstr "ﻞﻣﺎﻜﻤﻠﻟ ﺔﻘﺒﺴﻤﻟﺍ ﺕﺍﺩﺍﺪﻋﻹﺍ"
@ -32822,10 +32822,6 @@ msgid "Process the render result through the compositing pipeline, if compositin
msgstr "ﺔﻠﻌﻔﻣ ﺐﻴﻛﺮﺘﻟﺍ ﺪﻘﻋ ﺖﻧﺎﻛ ﺍﺫﺇ ،ﺐﻴﻛﺮﺘﻟﺍ ﻞﺣﺍﺮﻣ ﺮﺒﻋ ﺮﻴﻴﺼﺘﻟﺍ ﺔﺠﻴﺘﻧ ﺔﺠﻟﺎﻌﻣ"
msgid "File Extensions"
msgstr "ﻒﻠﻤﻟﺍ ﺕﺎﺌﻴﻫ"
msgid "Add the file format extensions to the rendered file name (eg: filename + .jpg)"
msgstr " (jpg. + ﻒﻠﻣ_ﻢﺳﺇ :ﻝﺎﺜﻣ) ﺮﻴّﺼﻤﻟﺍ ﻒﻠﻤﻟﺍ ﻢﺳﺇ ﻰﻟﺇ ﻒﻠﻤﻟﺍ ﺔﺌﻴﻫ ﻒﺿﺃ"
@ -35481,10 +35477,6 @@ msgid "Display vertex-per-face normals as lines"
msgstr "ﻁﻮﻄﺨﻛ ﻪﺟﻭ-ﻞﻜﻟ-ﺔﻄﻘﻧ ﻢﻇﺍﻮﻧ ﺽﺮﻋﺇ"
msgid "Stat Vis"
msgstr "ﺔﻴﺋﺎﺼﺣﺇ ﺔﻨﻳﺎﻌﻣ"
msgid "Display statistical information about the mesh"
msgstr "ﻢﺴﺠﻤﻟﺍ ﻦﻋ ﺔﻴﺋﺎﺼﺣﺇ ﺕﺎﻣﻮﻠﻌﻣ ﺽﺮﻋﺇ"
@ -36431,6 +36423,10 @@ msgid "Auto-Step"
msgstr "ﻲﺋﺎﻘﻠﺗ ﻡﺪﻘﺗ"
msgid "Refraction"
msgstr "ﺭﺎﺴﻜﻧﻻﺍ"
msgid "Paths:"
msgstr ":ﺕﺍﺭﺎﺴﻤﻟﺍ"

360
locale/po/be.po Normal file
View File

@ -0,0 +1,360 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2023-12-11 10:35+0000\n"
"Last-Translator: Aleh <zucchini.enjoyer@protonmail.com>\n"
"Language-Team: Belarusian <https://translate.blender.org/projects/blender-ui/ui/be/>\n"
"Language: be\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.0.1"
msgid "Shader AOV"
msgstr "Шэйдар АВП"
msgid "Valid"
msgstr "Сапраўдны"
msgid "Is the name of the AOV conflicting"
msgstr "Ці канфліктуе назва АВП"
msgid "Name"
msgstr "Назва"
msgid "Name of the AOV"
msgstr "Назва АВП"
msgid "Type"
msgstr "Тып"
msgid "Data type of the AOV"
msgstr "Тып дадзеных АВП"
msgid "Color"
msgstr "Колер"
msgid "Value"
msgstr "Значэнне"
msgid "List of AOVs"
msgstr "Спіс АВП"
msgid "Collection of AOVs"
msgstr "Калекцыя АВП"
msgid "Action F-Curves"
msgstr "Ф-крывыя дзеянняў"
msgid "Collection of action F-Curves"
msgstr "Калекцыя Ф-крывых дзеянняў"
msgid "Action Group"
msgstr "Група дзеянняў"
msgid "Groups of F-Curves"
msgstr "Групы Ф-крывых"
msgid "Channels"
msgstr "Каналы"
msgid "F-Curves in this group"
msgstr "Ф-крывыя ў гэтай групе"
msgid "Color Set"
msgstr "Набор колераў"
msgid "Custom color set to use"
msgstr "Карыстальніцкі набор колераў для выкарыстання"
msgid "Default Colors"
msgstr "Колеры па змаўчанні"
msgid "01 - Theme Color Set"
msgstr "01 - Колеравая тэма"
msgid "02 - Theme Color Set"
msgstr "02 - Колеравая тэма"
msgid "03 - Theme Color Set"
msgstr "03 - Колеравая тэма"
msgid "04 - Theme Color Set"
msgstr "04 - Колеравая тэма"
msgid "05 - Theme Color Set"
msgstr "05 - Колеравая тэма"
msgid "06 - Theme Color Set"
msgstr "06 - Колеравая тэма"
msgid "07 - Theme Color Set"
msgstr "07 - Колеравая тэма"
msgid "08 - Theme Color Set"
msgstr "08 - Колеравая тэма"
msgid "09 - Theme Color Set"
msgstr "09 - Колеравая тэма"
msgid "10 - Theme Color Set"
msgstr "10 - Колеравая тэма"
msgid "11 - Theme Color Set"
msgstr "11 - Колеравая тэма"
msgid "12 - Theme Color Set"
msgstr "12 - Колеравая тэма"
msgid "13 - Theme Color Set"
msgstr "13 - Колеравая тэма"
msgid "14 - Theme Color Set"
msgstr "14 - Колеравая тэма"
msgid "15 - Theme Color Set"
msgstr "15 - Колеравая тэма"
msgid "16 - Theme Color Set"
msgstr "16 - Колеравая тэма"
msgid "17 - Theme Color Set"
msgstr "17 - Колеравая тэма"
msgid "18 - Theme Color Set"
msgstr "18 - Колеравая тэма"
msgid "19 - Theme Color Set"
msgstr "19 - Колеравая тэма"
msgid "20 - Theme Color Set"
msgstr "20 - Колеравая тэма"
msgid "Custom Color Set"
msgstr "Карыстальніцкі набор колераў"
msgid "Colors"
msgstr "Колеры"
msgid "Copy of the colors associated with the group's color set"
msgstr "Копія колераў, асацыяваных з наборам колераў групы"
msgid "Color set is user-defined instead of a fixed theme color set"
msgstr "Набор колераў, зададзены карыстальнікам, замест фіксаванай колеравай тэмы"
msgid "Lock"
msgstr "Заблакаваць"
msgid "Action group is locked"
msgstr "Група дзеянняў заблакавана"
msgid "Mute"
msgstr "Прыглушыць"
msgid "Action group is muted"
msgstr "Група дзеянняў прыглушана"
msgid "Select"
msgstr "Выбраць"
msgid "Action group is selected"
msgstr "Група дзеянняў выбрана"
msgid "Expanded"
msgstr "Разгорнуты"
msgid "Action group is expanded except in graph editor"
msgstr "Група дзеянняў разгорнута, акрамя рэдактара графаў"
msgid "Expanded in Graph Editor"
msgstr "Разгорнута ў рэдактары графаў"
msgid "Action group is expanded in graph editor"
msgstr "Група дзеянняў разгорнута ў рэдактары графаў"
msgid "Pin in Graph Editor"
msgstr "Прышпіліць у рэдактары графаў"
msgid "Action Groups"
msgstr "Групы дзеянняў"
msgid "Collection of action groups"
msgstr "Калекцыя груп дзеянняў"
msgid "Action Pose Markers"
msgstr "Маркеры поз дзеянняў"
msgid "Collection of timeline markers"
msgstr "Калекцыя маркераў шкалы часу"
msgid "Active Pose Marker"
msgstr "Актыўны маркер позы"
msgid "Active pose marker for this action"
msgstr "Актыўны маркер позы для гэтага дзеяння"
msgid "Active Pose Marker Index"
msgstr "Індэкс актыўнага маркера позы"
msgid "Index of active pose marker"
msgstr "Індэкс актыўнага маркера позы"
msgid "Add-on"
msgstr "Дадатак"
msgid "Python add-ons to be loaded automatically"
msgstr "Дадаткі Python, якія будуць загружацца аўтаматычна"
msgid "Module"
msgstr "Модуль"
msgid "Module name"
msgstr "Назва модуля"
msgid "Add-on Preferences"
msgstr "Налады дадатка"
msgid "Password"
msgstr "Пароль"
msgid "E-mail address"
msgstr "Адрасы электроннай пошты"
msgid "Error Message"
msgstr "Паведамленне аб памылцы"
msgid "Message"
msgstr "Паведамленне"
msgid "Compute Device Type"
msgstr "Тып вылічальнай прылады"
msgid "Device to use for computation (rendering with Cycles)"
msgstr "Прылада, якая выкарыстоўваецца для вылічэння (рэндэрынг з дапамогай Cycles)"
msgid "Kernel Optimization"
msgstr "Аптымізацыя ядра"
msgid "Kernels can be optimized based on scene content. Optimized kernels are requested at the start of a render. If optimized kernels are not available, rendering will proceed using generic kernels until the optimized set is available in the cache. This can result in additional CPU usage for a brief time (tens of seconds)"
msgstr "Ядры могуць быць аптымізаваныя на грунце змесціва сцэны. Аптымізаваныя ядры запытваюцца ў пачатку рэндэрынгу. Калі аптымізаваныя ядры недаступныя, рэндэрынг будзе адбывацца з выкарыстаннем агульных ядраў, пакуль аптымізаваны набор не будзе даступны ў кэшы. Гэта можа прывесці да дадатковага выкарыстання ЦП на кароткі час (дзясяткі секундаў)"
msgid "Off"
msgstr "Выключана"
msgid "Disable kernel optimization. Slowest rendering, no extra background CPU usage"
msgstr "Адключэнне аптымізацыі ядра. Самы павольны рэндэрынг, без дадатковай фонавай загрузкі ЦП"
msgid "Intersection only"
msgstr "Толькі перасячэнні"
msgid "Optimize only intersection kernels. Faster rendering, negligible extra background CPU usage"
msgstr "Аптымізацыя толькі ядраў перасячэння. Больш хуткі рэндэрынг, нязначнае дадатковае выкарыстанне ЦП ў фонавым рэжыме"
msgid "Full"
msgstr "Поўнае"
msgid "Optimize all kernels. Fastest rendering, may result in extra background CPU usage"
msgstr "Аптымізацыя ўсіх ядраў. Самы хуткі рэндэрынг, можа прывесці да дадатковай загрузцы ЦП ў фонавым рэжыме"
msgid "MetalRT"
msgstr "MetalRT"
msgid "MetalRT for ray tracing uses less memory for scenes which use curves extensively, and can give better performance in specific cases"
msgstr "MetalRT выкарыстоўвае менш памяці для трасіроўкі прамянёў у сцэнах, якія актыўна выкарыстоўваюць крывыя, і можа даць лепшую прадукцыйнасць у пэўных выпадках"
msgid "On"
msgstr "Уключана"
msgid "Import Paths"
msgstr "Шляхі імпарту"

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2023-09-26 10:37+0000\n"
"Last-Translator: Gilberto Rodrigues <gilbertorodrigues@outlook.com>\n"
"Language-Team: Bulgarian <https://translate.blender.org/projects/blender-ui/ui/bg/>\n"

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2023-10-12 15:54+0000\n"
"Last-Translator: Zdeněk Doležal <Griperis@outlook.cz>\n"
"Language-Team: Czech <https://translate.blender.org/projects/blender-ui/ui/cs/>\n"
@ -7131,6 +7131,18 @@ msgid "Save"
msgstr "Uložit"
msgid "File Extensions"
msgstr "Přípony souborů"
msgid "Operator"
msgstr "Operátor"
msgid "Label"
msgstr "Úroveň"
msgid "Icon ID"
msgstr "ID Ikony"
@ -10713,10 +10725,6 @@ msgid "Proxy Custom Directory"
msgstr "Adresář zvuků"
msgid "Label"
msgstr "Úroveň"
msgid "Grease Pencil Data"
msgstr "Kresba skicovací tužkou"
@ -23894,10 +23902,6 @@ msgid "Reverse Colors"
msgstr "Nová vertexová barva"
msgid "Flip direction of vertex colors inside faces"
msgstr "Přepíná směr vybraných ploškových vrcholů a ploškových normál"
msgctxt "Operator"
msgid "Rotate Colors"
msgstr "Vložit barvu"
@ -29179,10 +29183,6 @@ msgid "Decrease Contrast"
msgstr "Snížit Kontrast"
msgid "Operator"
msgstr "Operátor"
msgctxt "Operator"
msgid "Filter Mesh"
msgstr "Filtrovat Síť"
@ -32427,14 +32427,6 @@ msgid "Restrict"
msgstr "Omezit"
msgid "Refraction"
msgstr "Lom"
msgid "Denoising"
msgstr "Odstranění šumu"
msgid "Integrator Presets"
msgstr "Generátory"
@ -33019,6 +33011,10 @@ msgid "Indirect Lighting"
msgstr "Nepřímé osvětlení"
msgid "Denoising"
msgstr "Odstranění šumu"
msgid "Shadows"
msgstr "Stíny"
@ -35915,10 +35911,6 @@ msgid "Crop the rendered frame to the defined render region size"
msgstr "Oříznout vykreslený snímek do definovaný velikosti vykreslovací oblasti"
msgid "File Extensions"
msgstr "Přípony souborů"
msgid "Draw stylized strokes using Freestyle"
msgstr "Kreslení stylizovaných tahů pomocí Freestyle"
@ -39715,6 +39707,10 @@ msgid "Show dashed lines indicating parent or constraint relationships"
msgstr "Zobrazuje čárkované čáry naznačující vztahy s nadřazenými objekty, nebo vazby mezi objekty"
msgid "Mesh Analysis"
msgstr "Analýza sítě"
msgid "Display vertex normals as lines"
msgstr "Zobrazí normály vertexů pomocí čárek"
@ -41214,6 +41210,10 @@ msgid "Light Clamping"
msgstr "Svorka Světla"
msgid "Refraction"
msgstr "Lom"
msgid "Cascade Size"
msgstr "Velikost kaskády"
@ -43108,16 +43108,6 @@ msgid "Face Set from Visible"
msgstr "Sada Ploch z Viditelného"
msgctxt "Operator"
msgid "Invert Visible Face Sets"
msgstr "Invertovat Viditelné Sady Ploch"
msgctxt "Operator"
msgid "Show All Face Sets"
msgstr "Zobrazit Všechny Viditelné Sady Ploch"
msgctxt "Operator"
msgid "Randomize Colors"
msgstr "Randomizovat barvy"
@ -43350,10 +43340,6 @@ msgid "Seams"
msgstr "Švy"
msgid "Mesh Analysis"
msgstr "Analýza sítě"
msgid "Face Angle"
msgstr "Úhel plochy"
@ -45875,6 +45861,10 @@ msgid "Mask not found"
msgstr "Maska nebyla nalezena"
msgid "Please select all related strips"
msgstr "Odstranit označené značky"
msgid "Cannot apply effects to audio sequence strips"
msgstr "První frame animace"
@ -45887,10 +45877,6 @@ msgid "No valid inputs to swap"
msgstr "Jméno skriptu"
msgid "Please select all related strips"
msgstr "Odstranit označené značky"
msgid "Please select two strips"
msgstr "Odstranit označené značky"

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: \n"
"Last-Translator: Martin Reininger <martinreininger@gmx.net>\n"
"Language-Team: German translation team\n"
@ -9759,6 +9759,18 @@ msgid "Save"
msgstr "Speichern"
msgid "File Extensions"
msgstr "Dateiendungen"
msgid "Operator"
msgstr "Operator"
msgid "Label"
msgstr "Beschriftung"
msgid "File Select Entry"
msgstr "Eintrag zur Dateiauswahl"
@ -15435,10 +15447,6 @@ msgid "Node tree consisting of linked nodes used for shading, textures and compo
msgstr "Knotenbaum beinhaltet verknüpfte Knoten, die für Shading, Texturen und Kompositionen verwendet wurden"
msgid "Label"
msgstr "Beschriftung"
msgid "Grease Pencil Data"
msgstr "Wachsstift-Daten"
@ -32957,10 +32965,6 @@ msgid "Reverse Colors"
msgstr "Farben umkehren"
msgid "Flip direction of vertex colors inside faces"
msgstr "Umkehrrichtung der Punktfarben innerhalb von Flächen"
msgctxt "Operator"
msgid "Rotate Colors"
msgstr "Farben drehen"
@ -38493,10 +38497,6 @@ msgid "Decrease Contrast"
msgstr "Kontrast verringern"
msgid "Operator"
msgstr "Operator"
msgctxt "Operator"
msgid "Init Mask"
msgstr "Maske initializieren"
@ -42136,14 +42136,6 @@ msgid "Active Palette Color"
msgstr "Aktive Farbpalette"
msgid "Refraction"
msgstr "Strahlenbrechnung"
msgid "Denoising"
msgstr "Rauschreduzierung"
msgid "Integrator Presets"
msgstr "Integrator-Voreinstellungen"
@ -42748,6 +42740,10 @@ msgid "Indirect Lighting"
msgstr "Indirekte Beleuchtung"
msgid "Denoising"
msgstr "Rauschreduzierung"
msgid "Shadows"
msgstr "Schatten"
@ -46682,10 +46678,6 @@ msgid "Crop the rendered frame to the defined render region size"
msgstr "Beschneidet den gerenderten Rahmen auf die definierte Größe des Renderbereichs"
msgid "File Extensions"
msgstr "Dateiendungen"
msgid "Add the file format extensions to the rendered file name (eg: filename + .jpg)"
msgstr "Dateiformaterweiterungen zu Dateinamen hinzufügen (z.B.: Dateiname + .jpg)"
@ -54936,6 +54928,10 @@ msgid "Auto-Step"
msgstr "Auto-Schritt"
msgid "Refraction"
msgstr "Strahlenbrechnung"
msgctxt "Operator"
msgid "Bake Indirect Lighting"
msgstr "Indirekte Beleuchtung backen"
@ -58671,10 +58667,6 @@ msgid "Int"
msgstr "Int"
msgid "PreviewCol"
msgstr "Vorschaufarbe"
msgid "TexturedCol"
msgstr "Texturierte Farbe"
@ -61689,14 +61681,6 @@ msgid "File '%s' could not be loaded"
msgstr "Datei '%s' konnte nicht geladen werden"
msgid "Cannot apply effects to audio sequence strips"
msgstr "Effekt kann nicht auf Audio-Sequenzstreifen angewandt werden"
msgid "Cannot apply effect to more than 3 sequence strips"
msgstr "Effekt kann nicht auf mehr als 3 Sequenzstreifen angewandt werden"
msgid "Please select all related strips"
msgstr "Bitte alle beziehenden Streifen auswählen"
@ -61705,6 +61689,14 @@ msgid "No strips to paste"
msgstr "Keine Streifen zum einfügen"
msgid "Cannot apply effects to audio sequence strips"
msgstr "Effekt kann nicht auf Audio-Sequenzstreifen angewandt werden"
msgid "Cannot apply effect to more than 3 sequence strips"
msgstr "Effekt kann nicht auf mehr als 3 Sequenzstreifen angewandt werden"
msgid "Please select two strips"
msgstr "Bitte zwei Steifen auswählen"

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2008-03-23 12:20+0200\n"
"Last-Translator: Kostas Karvouniaris <neogen556@yahoo.gr>\n"
"Language-Team: \n"

View File

@ -1,11 +1,11 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"PO-Revision-Date: 2023-12-04 05:17+0000\n"
"Last-Translator: Gabriel Gazzán <gabcorreo@gmail.com>\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: 2023-12-09 04:50+0000\n"
"Last-Translator: Darwin Yip <yipdarwin+blender@gmail.com>\n"
"Language-Team: Spanish <https://translate.blender.org/projects/blender-ui/ui/es/>\n"
"Language: es\n"
"MIME-Version: 1.0\n"
@ -1458,6 +1458,10 @@ msgid "Custom"
msgstr "Personalizado"
msgid "Show assets from the asset libraries configured in the Preferences"
msgstr "Mostrar recursos de las bibliotecas de recursos configurados en las preferencias"
msgid "ID Name"
msgstr "Nombre"
@ -13118,6 +13122,18 @@ msgid "Whether this path is saved in bookmarks, or generated from OS"
msgstr "Indica si esta ruta se encuentra guardada en los marcadores o proviene del sistema operativo"
msgid "File Extensions"
msgstr "Extensiones de archivo"
msgid "Operator"
msgstr "Operador"
msgid "Label"
msgstr "Etiqueta"
msgid "File Select Entry"
msgstr "Archivo seleccionado"
@ -25425,6 +25441,14 @@ msgid "True if this material has grease pencil data"
msgstr "Verdadero si este material contiene datos de lápiz de cera"
msgid "Light Probe Volume Single Sided"
msgstr "Volumen de sonda de luz de un solo lado"
msgid "Consider material single sided for light probe volume capture. Additionally helps rejecting probes inside the object to avoid light leaks"
msgstr "Considere el material de un solo lado para la captura del volumen de la sonda de luz. Además ayuda a rechazar sondas dentro del objeto para evitar fugas de luz"
msgid "Line Color"
msgstr "Color de línea"
@ -25625,6 +25649,18 @@ msgid "How intense (bright) the specular reflection is"
msgstr "Qué tan intensa es la reflectividad"
msgid "Surface Render Method"
msgstr "Método de procesar superficie"
msgid "Controls the blending and the compatibility with certain features"
msgstr "Controla la mezcla y la compatibilidad con ciertas características"
msgid "Blended"
msgstr "Mezclado"
msgid "Texture Slot Images"
msgstr "Imágenes del contenedor de texturas"
@ -26073,10 +26109,6 @@ msgid "Node tree consisting of linked nodes used for shading, textures and compo
msgstr "Árbol de nodos compuesto por nodos vinculados entre sí; usados para sombreado, texturizado y composición"
msgid "Label"
msgstr "Etiqueta"
msgid "The node tree label"
msgstr "Etiqueta del árbol de nodos"
@ -51356,11 +51388,6 @@ msgid "Name of the bone collection to unassign this bone from; empty to unassign
msgstr "Nombre de la colección de la cual quitar este hueso; dejar vacío para quitarlo de la colección activa"
msgctxt "Operator"
msgid "Remove Bone from Bone collections"
msgstr "Eliminar hueso de colección de huesos"
msgid "Unassign the bone from this bone collection"
msgstr "Quita el hueso de esta colección de huesos"
@ -63015,19 +63042,11 @@ msgid "Reverse Colors"
msgstr "Invertir colores"
msgid "Flip direction of vertex colors inside faces"
msgstr "Invierte la dirección de los colores de vértices dentro de las caras"
msgctxt "Operator"
msgid "Rotate Colors"
msgstr "Rotar colores"
msgid "Rotate color attributes inside faces"
msgstr "Rota los atributos de color dentro de las caras"
msgid "Counter Clockwise"
msgstr "Antihorario"
@ -75207,19 +75226,6 @@ msgid "Modify Hidden"
msgstr "Modificar ocultos"
msgid "Apply the edit operation to hidden Face Sets"
msgstr "Permite aplicar la operación de edición a los conjuntos de caras ocultos"
msgctxt "Operator"
msgid "Invert Face Set Visibility"
msgstr "Invertir visibilidad de conjuntos de caras"
msgid "Invert the visibility of the Face Sets of the sculpt"
msgstr "Permite invertir la visibilidad de los conjuntos de caras de la escultura"
msgctxt "Operator"
msgid "Face Set Lasso Gesture"
msgstr "Gesto de conjunto de caras con lazo"
@ -75483,10 +75489,6 @@ msgid "Use settings from here"
msgstr "Usar opciones de aquí"
msgid "Operator"
msgstr "Operador"
msgid "Use settings from operator properties"
msgstr "Usar opciones de propiedades del operador"
@ -84706,18 +84708,6 @@ msgid "Panel containing UI elements"
msgstr "Panel que contiene elementos de la interfaz"
msgid "Refraction"
msgstr "Refracción"
msgid "Screen Tracing"
msgstr "Trazado en pantalla"
msgid "Denoising"
msgstr "Reducción de ruidos"
msgid "Light Groups"
msgstr "Grupos de luces"
@ -85596,10 +85586,18 @@ msgid "Indirect Lighting"
msgstr "Iluminación indirecta"
msgid "Denoising"
msgstr "Reducción de ruidos"
msgid "Raytracing"
msgstr "Trazado de rayos"
msgid "Screen Tracing"
msgstr "Trazado en pantalla"
msgid "Shadows"
msgstr "Sombras"
@ -93603,10 +93601,6 @@ msgid "Crop the rendered frame to the defined render region size"
msgstr "Recorta la imagen procesada al tamaño definido por la región"
msgid "File Extensions"
msgstr "Extensiones de archivo"
msgid "Add the file format extensions to the rendered file name (eg: filename + .jpg)"
msgstr "Agrega la extensión del formato de archivo al nombre del archivo procesado (p.ej: nombre + .jpg)"
@ -94775,14 +94769,6 @@ msgid "Brightness threshold for using sprite base depth of field"
msgstr "Umbral de brillo para la profundidad de campo basada en sprites"
msgid "Diffuse Trace Options"
msgstr "Opciones de trazado de difusión"
msgid "EEVEE settings for tracing diffuse reflections"
msgstr "Opciones de EEVEE para el trazado de rayos de reflexión difusa"
msgid "Auto Bake"
msgstr "Captura automática"
@ -94995,26 +94981,6 @@ msgid "Percentage of render size to add as overscan to the internal render buffe
msgstr "Porcentaje del tamaño de procesamiento a agregar como sobrebarrido a los buffers internos de procesamiento"
msgid "Options Split"
msgstr "División de opciones"
msgid "Split settings per ray type"
msgstr "Divide las opciones por tipo de rayo"
msgid "Unified"
msgstr "Unificado"
msgid "All ray types use the same settings"
msgstr "Todos los tipos de rayo usarán las mismas opciones"
msgid "Settings are individual to each ray type"
msgstr "Opciones individuales para cada tipo de rayo"
msgid "Tracing Method"
msgstr "Método de trazado"
@ -95043,14 +95009,6 @@ msgid "EEVEE settings for tracing reflections"
msgstr "Opciones de EEVEE para el trazado de reflexiones"
msgid "Refraction Trace Options"
msgstr "Opciones de trazado de refracción"
msgid "EEVEE settings for tracing refractions"
msgstr "Opciones de EEVEE para el trazado de refracciones"
msgid "Directional Shadows Resolution"
msgstr "Resolución de sombras direccionales"
@ -104642,8 +104600,8 @@ msgid "Display scene statistics overlay text"
msgstr "Mostrar sobreimpreso texto con estadísticas de la escena"
msgid "Stat Vis"
msgstr "Vis. estad."
msgid "Mesh Analysis"
msgstr "Análisis de mallas"
msgid "Display statistical information about the mesh"
@ -106110,10 +106068,6 @@ msgid "Vector2D"
msgstr "Vector2D"
msgid "2D float vector action, representing a thumbstick or trackpad"
msgstr "Acción vectorial 2D decimal, representando un panel táctil"
msgid "3D pose action, representing a controller's location and rotation"
msgstr "Acción de pose 3D, representando la posición y rotación de un controlador"
@ -107589,11 +107543,6 @@ msgid "Stop Move Left"
msgstr "Detener mov a izquierda"
msgctxt "WindowManager"
msgid "Stop Mode Right"
msgstr "Detener mov a derecha"
msgctxt "WindowManager"
msgid "Teleport"
msgstr "Teletransportación"
@ -109151,6 +109100,10 @@ msgid "No glTF Animation"
msgstr "No existe ninguna animación glTF"
msgid "No Actions in .blend file"
msgstr "No hay acciones en el archivo .blend"
msgid "Variant"
msgstr "Variante"
@ -112436,6 +112389,10 @@ msgid "Light Clamping"
msgstr "Limitación de luz"
msgid "Refraction"
msgstr "Refracción"
msgid "Cascade Size"
msgstr "Tamaño cascada"
@ -113638,6 +113595,16 @@ msgid "Sound"
msgstr "Sonido"
msgctxt "Operator"
msgid "Move Up"
msgstr "Mover arriba"
msgctxt "Operator"
msgid "Move Down"
msgstr "Mover abajo"
msgctxt "Operator"
msgid "Rename..."
msgstr "Renombrar..."
@ -116140,16 +116107,6 @@ msgid "Extract Face Set"
msgstr "Extraer conjunto de caras"
msgctxt "Operator"
msgid "Invert Visible Face Sets"
msgstr "Invertir conjuntos de caras visibles"
msgctxt "Operator"
msgid "Show All Face Sets"
msgstr "Mostrar todos los conjuntos de caras"
msgctxt "Operator"
msgid "Randomize Colors"
msgstr "Aleatorizar colores"
@ -116574,10 +116531,6 @@ msgid "Vertex Group Weights"
msgstr "Influencias de grupos de vértices"
msgid "Mesh Analysis"
msgstr "Análisis de mallas"
msgid "Face Angle"
msgstr "Ángulo de caras"
@ -117997,10 +117950,6 @@ msgid "Int"
msgstr "Entero"
msgid "PreviewCol"
msgstr "ColPrevisualización"
msgid "TexturedCol"
msgstr "ColTexturizado"
@ -118025,10 +117974,6 @@ msgid "OS Loop"
msgstr "Bucle del SO"
msgid "PreviewLoopCol"
msgstr "ColPrevisualizaciónBucle"
msgid "Int8"
msgstr "Entero8"
@ -118596,10 +118541,6 @@ msgid "No valid formats found"
msgstr "No se encontraron formatos válidos"
msgid "Can't allocate ffmpeg format context"
msgstr "No es posible asignar el contexto del formato FFmpeg"
msgid "Render width has to be 720 pixels for DV!"
msgstr "¡El ancho de la imagen procesada debe ser de 720 píxeles para DV!"
@ -118612,10 +118553,6 @@ msgid "Render height has to be 576 pixels for DV-PAL!"
msgstr "¡La altura de la imagen procesada debe ser de 576 píxeles para DV-PAL!"
msgid "FFmpeg only supports 48khz / stereo audio for DV!"
msgstr "¡FFmpeg sólo soporta audio estéreo de 48khz para DV!"
msgid "Error initializing video stream"
msgstr "Error inicializando flujo de video"
@ -125894,6 +125831,14 @@ msgid "File '%s' could not be loaded"
msgstr "No fue posible cargar el archivo '%s'"
msgid "Please select all related strips"
msgstr "Por favor seleccionar todos los clips relacionados"
msgid "No strips to paste"
msgstr "No hay clips para pegar"
msgid "Slip offset: %s"
msgstr "Deslizamiento: %s"
@ -125934,14 +125879,6 @@ msgid "No valid inputs to swap"
msgstr "No hay entradas válidas para intercambiar"
msgid "Please select all related strips"
msgstr "Por favor seleccionar todos los clips relacionados"
msgid "No strips to paste"
msgstr "No hay clips para pegar"
msgid "Please select two strips"
msgstr "Por favor seleccionar dos clips"
@ -132073,10 +132010,6 @@ msgid "Incident"
msgstr "Incidente"
msgid "Ior"
msgstr "IR"
msgid "No mesh in active object"
msgstr "Ninguna malla en el objeto activo"
@ -133831,6 +133764,10 @@ msgid "Interpolates existing guide curves on a surface mesh"
msgstr "Interpola las curvas guía existentes sobre la superficie de una malla"
msgid "Follow Surface Normal"
msgstr "Seguir la normal de la superficie"
msgid "Redistribute Curve Points"
msgstr "Redistribuir puntos de curva"
@ -133855,6 +133792,18 @@ msgid "Rolls up hair curves starting from their tips"
msgstr "Enrolla las curvas de pelo, desde sus puntas"
msgid "Variation Level"
msgstr "Nivel de variación"
msgid "Retain Overall Shape"
msgstr "Conservar la forma general"
msgid "Roll Direction"
msgstr "Dirección de rollo"
msgid "Rotate Hair Curves"
msgstr "Rotar curvas de pelo"
@ -133867,6 +133816,14 @@ msgid "Sets the radius attribute of hair curves according to a profile shape"
msgstr "Define el atributo de radio de las curvas de pelo mediante una forma de perfil"
msgid "Replace Radius"
msgstr "Reemplazar radio"
msgid "Replace the original radius"
msgstr "Reemplazar el radio original"
msgid "Shrinkwrap Hair Curves"
msgstr "Envolver curvas de pelo"
@ -133875,6 +133832,10 @@ msgid "Shrinkwraps hair curves to a mesh surface from below and optionally from
msgstr "Envuelve las curvas de pelo alrededor de la superficie de una malla situada por debajo y opcionalmente por encima"
msgid "Lock Roots"
msgstr "Encerrar raíces"
msgid "Smooth Hair Curves"
msgstr "Suavizar curvas de pelo"
@ -133883,6 +133844,14 @@ msgid "Smoothes the shape of hair curves"
msgstr "Suaviza la forma de las curvas de pelo"
msgid "Lock Tips"
msgstr "Encerrar puntas"
msgid "Lock tip position when smoothing"
msgstr "Encerrar posición de la punta al alisar"
msgid "Straighten Hair Curves"
msgstr "Enderezar curvas de pelo"
@ -133891,6 +133860,10 @@ msgid "Straightens hair curves between root and tip"
msgstr "Endereza las curvas de pelo, de su raíz a su punta"
msgid "Amount of straightening"
msgstr "Cantidad de alisado"
msgid "Trim Hair Curves"
msgstr "Recortar curvas de pelo"
@ -133899,6 +133872,22 @@ msgid "Trims or scales hair curves to a certain length"
msgstr "Recorta o escala las curvas de pelo a una cierta longitud"
msgid "Multiply the original length by a factor"
msgstr "Multiplicar el largo original por un factor"
msgid "Mask to blend overall effect"
msgstr "Máscara para mezclar el efecto general"
msgid "Smooth by Angle"
msgstr "Suavizar por ángulo"
msgid "Maximum face angle for smooth edges"
msgstr "Ángulo de cara máximo para bordes lisos"
msgid "Ignore Sharpness"
msgstr "Ignorar nitidez"

View File

@ -1,9 +1,9 @@
msgid ""
msgstr ""
"Project-Id-Version: Blender 4.1.0 Alpha (b'72b6c44e759b')\n"
"Project-Id-Version: Blender 4.1.0 Alpha (b'274dc815eb35')\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-12-04 11:06:00\n"
"POT-Creation-Date: 2023-12-11 11:18:04\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Ainhize & Miriam <agoenaga006@ikasle.ehu.eus>\n"
"Language-Team: Euskara <agoenaga006@ikasle.ehu.eus>\n"
@ -1706,10 +1706,6 @@ msgid "Save System Info"
msgstr "Sistemaren Informazioa Gorde"
msgid "Refraction"
msgstr "Errefrakzioa"
msgctxt "Operator"
msgid "Scale"
msgstr "Eskalatu"
@ -1908,6 +1904,10 @@ msgid "Upper"
msgstr "Altua"
msgid "Refraction"
msgstr "Errefrakzioa"
msgctxt "Image"
msgid "New"
msgstr "Berria"

Some files were not shown because too many files have changed in this diff Show More