Simulation Nodes: bake simulation states to disk #106937
|
@ -174,7 +174,7 @@ if(SYSTEMSTUBS_LIBRARY)
|
|||
list(APPEND PLATFORM_LINKLIBS SystemStubs)
|
||||
endif()
|
||||
|
||||
string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing")
|
||||
string(APPEND PLATFORM_CFLAGS " -pipe -funsigned-char -fno-strict-aliasing -ffp-contract=off")
|
||||
set(PLATFORM_LINKFLAGS
|
||||
"-fexceptions -framework CoreServices -framework Foundation -framework IOKit -framework AppKit -framework Cocoa -framework Carbon -framework AudioUnit -framework AudioToolbox -framework CoreAudio -framework Metal -framework QuartzCore"
|
||||
)
|
||||
|
|
|
@ -803,8 +803,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||
# Automatically turned on when building with "-march=native". This is
|
||||
# explicitly turned off here as it will make floating point math give a bit
|
||||
# different results. This will lead to automated test failures. So disable
|
||||
# this until we support it. Seems to default to off in clang and the intel
|
||||
# compiler.
|
||||
# this until we support it.
|
||||
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off")
|
||||
|
||||
# `maybe-uninitialized` is unreliable in release builds, but fine in debug builds.
|
||||
|
@ -892,7 +891,7 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||
|
||||
# CLang is the same as GCC for now.
|
||||
elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
|
||||
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing")
|
||||
set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing -ffp-contract=off")
|
||||
|
||||
if(WITH_LINKER_MOLD AND _IS_LINKER_DEFAULT)
|
||||
find_program(MOLD_BIN "mold")
|
||||
|
|
|
@ -111,9 +111,13 @@ BVHEmbree::~BVHEmbree()
|
|||
}
|
||||
}
|
||||
|
||||
void BVHEmbree::build(Progress &progress, Stats *stats, RTCDevice rtc_device_)
|
||||
void BVHEmbree::build(Progress &progress,
|
||||
Stats *stats,
|
||||
RTCDevice rtc_device_,
|
||||
const bool rtc_device_is_sycl_)
|
||||
{
|
||||
rtc_device = rtc_device_;
|
||||
rtc_device_is_sycl = rtc_device_is_sycl_;
|
||||
assert(rtc_device);
|
||||
|
||||
rtcSetDeviceErrorFunction(rtc_device, rtc_error_func, NULL);
|
||||
|
@ -266,15 +270,29 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i)
|
|||
rtcSetGeometryTimeStepCount(geom_id, num_motion_steps);
|
||||
|
||||
const int *triangles = mesh->get_triangles().data();
|
||||
rtcSetSharedGeometryBuffer(geom_id,
|
||||
RTC_BUFFER_TYPE_INDEX,
|
||||
0,
|
||||
RTC_FORMAT_UINT3,
|
||||
triangles,
|
||||
0,
|
||||
sizeof(int) * 3,
|
||||
num_triangles);
|
||||
|
||||
if (!rtc_device_is_sycl) {
|
||||
rtcSetSharedGeometryBuffer(geom_id,
|
||||
RTC_BUFFER_TYPE_INDEX,
|
||||
0,
|
||||
RTC_FORMAT_UINT3,
|
||||
triangles,
|
||||
0,
|
||||
sizeof(int) * 3,
|
||||
num_triangles);
|
||||
}
|
||||
else {
|
||||
/* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
|
||||
* happen on GPU, and we cannot use standard host pointers at this point. So instead
|
||||
* of making a shared geometry buffer - a new Embree buffer will be created and data
|
||||
* will be copied. */
|
||||
int *triangles_buffer = (int *)rtcSetNewGeometryBuffer(
|
||||
geom_id, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(int) * 3, num_triangles);
|
||||
assert(triangles_buffer);
|
||||
if (triangles_buffer) {
|
||||
static_assert(sizeof(int) == sizeof(uint));
|
||||
std::memcpy(triangles_buffer, triangles, sizeof(int) * 3 * (num_triangles));
|
||||
}
|
||||
}
|
||||
set_tri_vertex_buffer(geom_id, mesh, false);
|
||||
|
||||
rtcSetGeometryUserData(geom_id, (void *)prim_offset);
|
||||
|
@ -323,14 +341,38 @@ void BVHEmbree::set_tri_vertex_buffer(RTCGeometry geom_id, const Mesh *mesh, con
|
|||
rtcUpdateGeometryBuffer(geom_id, RTC_BUFFER_TYPE_VERTEX, t);
|
||||
}
|
||||
else {
|
||||
rtcSetSharedGeometryBuffer(geom_id,
|
||||
RTC_BUFFER_TYPE_VERTEX,
|
||||
t,
|
||||
RTC_FORMAT_FLOAT3,
|
||||
verts,
|
||||
0,
|
||||
sizeof(float3),
|
||||
num_verts + 1);
|
||||
if (!rtc_device_is_sycl) {
|
||||
rtcSetSharedGeometryBuffer(geom_id,
|
||||
RTC_BUFFER_TYPE_VERTEX,
|
||||
t,
|
||||
RTC_FORMAT_FLOAT3,
|
||||
verts,
|
||||
0,
|
||||
sizeof(float3),
|
||||
num_verts + 1);
|
||||
}
|
||||
else {
|
||||
/* NOTE(sirgienko): If the Embree device is a SYCL device, then Embree execution will
|
||||
* happen on GPU, and we cannot use standard host pointers at this point. So instead
|
||||
* of making a shared geometry buffer - a new Embree buffer will be created and data
|
||||
* will be copied. */
|
||||
/* As float3 is packed on GPU side, we map it to packed_float3. */
|
||||
packed_float3 *verts_buffer = (packed_float3 *)rtcSetNewGeometryBuffer(
|
||||
geom_id,
|
||||
RTC_BUFFER_TYPE_VERTEX,
|
||||
t,
|
||||
RTC_FORMAT_FLOAT3,
|
||||
sizeof(packed_float3),
|
||||
num_verts + 1);
|
||||
assert(verts_buffer);
|
||||
if (verts_buffer) {
|
||||
for (size_t i = (size_t)0; i < num_verts + 1; ++i) {
|
||||
verts_buffer[i].x = verts[i].x;
|
||||
verts_buffer[i].y = verts[i].y;
|
||||
verts_buffer[i].z = verts[i].z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,10 @@ class PointCloud;
|
|||
|
||||
class BVHEmbree : public BVH {
|
||||
public:
|
||||
void build(Progress &progress, Stats *stats, RTCDevice rtc_device);
|
||||
void build(Progress &progress,
|
||||
Stats *stats,
|
||||
RTCDevice rtc_device,
|
||||
const bool isSyclEmbreeDevice = false);
|
||||
void refit(Progress &progress);
|
||||
|
||||
RTCScene scene;
|
||||
|
@ -55,6 +58,7 @@ class BVHEmbree : public BVH {
|
|||
const bool update);
|
||||
|
||||
RTCDevice rtc_device;
|
||||
bool rtc_device_is_sycl;
|
||||
enum RTCBuildQuality build_quality;
|
||||
};
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ void OneapiDevice::build_bvh(BVH *bvh, Progress &progress, bool refit)
|
|||
bvh_embree->refit(progress);
|
||||
}
|
||||
else {
|
||||
bvh_embree->build(progress, &stats, embree_device);
|
||||
bvh_embree->build(progress, &stats, embree_device, true);
|
||||
}
|
||||
if (bvh->params.top_level) {
|
||||
embree_scene = bvh_embree->scene;
|
||||
|
@ -866,9 +866,9 @@ char *OneapiDevice::device_capabilities()
|
|||
|
||||
sycl::id<3> max_work_item_sizes =
|
||||
device.get_info<sycl::info::device::max_work_item_sizes<3>>();
|
||||
WRITE_ATTR("max_work_item_sizes_dim0", ((size_t)max_work_item_sizes.get(0)))
|
||||
WRITE_ATTR("max_work_item_sizes_dim1", ((size_t)max_work_item_sizes.get(1)))
|
||||
WRITE_ATTR("max_work_item_sizes_dim2", ((size_t)max_work_item_sizes.get(2)))
|
||||
WRITE_ATTR(max_work_item_sizes_dim0, ((size_t)max_work_item_sizes.get(0)))
|
||||
WRITE_ATTR(max_work_item_sizes_dim1, ((size_t)max_work_item_sizes.get(1)))
|
||||
WRITE_ATTR(max_work_item_sizes_dim2, ((size_t)max_work_item_sizes.get(2)))
|
||||
|
||||
GET_NUM_ATTR(max_work_group_size)
|
||||
GET_NUM_ATTR(max_num_sub_groups)
|
||||
|
@ -891,7 +891,7 @@ char *OneapiDevice::device_capabilities()
|
|||
GET_NUM_ATTR(native_vector_width_half)
|
||||
|
||||
size_t max_clock_frequency = device.get_info<sycl::info::device::max_clock_frequency>();
|
||||
WRITE_ATTR("max_clock_frequency", max_clock_frequency)
|
||||
WRITE_ATTR(max_clock_frequency, max_clock_frequency)
|
||||
|
||||
GET_NUM_ATTR(address_bits)
|
||||
GET_NUM_ATTR(max_mem_alloc_size)
|
||||
|
@ -900,7 +900,7 @@ char *OneapiDevice::device_capabilities()
|
|||
* supported so we always return false, even if device supports HW texture usage acceleration.
|
||||
*/
|
||||
bool image_support = false;
|
||||
WRITE_ATTR("image_support", (size_t)image_support)
|
||||
WRITE_ATTR(image_support, (size_t)image_support)
|
||||
|
||||
GET_NUM_ATTR(max_parameter_size)
|
||||
GET_NUM_ATTR(mem_base_addr_align)
|
||||
|
|
|
@ -778,8 +778,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI)
|
|||
|
||||
# Host execution won't use GPU binaries, no need to compile them.
|
||||
if(WITH_CYCLES_ONEAPI_BINARIES AND NOT WITH_CYCLES_ONEAPI_HOST_TASK_EXECUTION)
|
||||
# AoT binaries aren't currently reused when calling sycl::build.
|
||||
list(APPEND sycl_compiler_flags -DWITH_CYCLES_ONEAPI_BINARIES)
|
||||
# Iterate over all targest and their options
|
||||
list(JOIN CYCLES_ONEAPI_SYCL_TARGETS "," targets_string)
|
||||
list(APPEND sycl_compiler_flags -fsycl-targets=${targets_string})
|
||||
|
|
|
@ -289,6 +289,15 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
|||
return false;
|
||||
}
|
||||
|
||||
# ifdef __EMBREE__
|
||||
IF_USING_EMBREE
|
||||
{
|
||||
if (kernel_data.device_bvh) {
|
||||
return kernel_embree_intersect_volume(kg, ray, isect, visibility);
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
IF_NOT_USING_EMBREE
|
||||
{
|
||||
# ifdef __OBJECT_MOTION__
|
||||
|
|
|
@ -109,7 +109,9 @@ struct CCLVolumeContext
|
|||
#if EMBREE_MAJOR_VERSION >= 4
|
||||
KernelGlobals kg;
|
||||
const Ray *ray;
|
||||
# ifdef __VOLUME_RECORD_ALL__
|
||||
numhit_t max_hits;
|
||||
# endif
|
||||
numhit_t num_hits;
|
||||
#endif
|
||||
Intersection *vol_isect;
|
||||
|
@ -505,8 +507,10 @@ ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(
|
|||
#endif
|
||||
const Ray *cray = ctx->ray;
|
||||
|
||||
#ifdef __VOLUME_RECORD_ALL__
|
||||
/* Append the intersection to the end of the array. */
|
||||
if (ctx->num_hits < ctx->max_hits) {
|
||||
#endif
|
||||
Intersection current_isect;
|
||||
kernel_embree_convert_hit(
|
||||
kg, ray, hit, ¤t_isect, reinterpret_cast<intptr_t>(args->geometryUserPtr));
|
||||
|
@ -523,10 +527,17 @@ ccl_device_forceinline void kernel_embree_filter_occluded_volume_all_func_impl(
|
|||
int object_flag = kernel_data_fetch(object_flag, tri_object);
|
||||
if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
|
||||
--ctx->num_hits;
|
||||
#ifndef __VOLUME_RECORD_ALL__
|
||||
/* Without __VOLUME_RECORD_ALL__ we need only a first counted hit, so we will
|
||||
* continue tracing only if a current hit is not counted. */
|
||||
*args->valid = 0;
|
||||
#endif
|
||||
}
|
||||
#ifdef __VOLUME_RECORD_ALL__
|
||||
/* This tells Embree to continue tracing. */
|
||||
*args->valid = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if EMBREE_MAJOR_VERSION < 4
|
||||
|
@ -844,7 +855,9 @@ ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
|
|||
ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
|
||||
ccl_private const Ray *ray,
|
||||
ccl_private Intersection *isect,
|
||||
# ifdef __VOLUME_RECORD_ALL__
|
||||
const uint max_hits,
|
||||
# endif
|
||||
const uint visibility)
|
||||
{
|
||||
# if EMBREE_MAJOR_VERSION >= 4
|
||||
|
@ -864,7 +877,9 @@ ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
|
|||
rtcInitIntersectContext(&ctx);
|
||||
# endif
|
||||
ctx.vol_isect = isect;
|
||||
# ifdef __VOLUME_RECORD_ALL__
|
||||
ctx.max_hits = numhit_t(max_hits);
|
||||
# endif
|
||||
ctx.num_hits = numhit_t(0);
|
||||
ctx.ray = ray;
|
||||
RTCRay rtc_ray;
|
||||
|
|
|
@ -174,6 +174,14 @@ bool oneapi_kernel_is_required_for_features(const std::string &kernel_name,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool oneapi_kernel_is_raytrace_or_mnee(const std::string &kernel_name)
|
||||
{
|
||||
return (kernel_name.find(device_kernel_as_string(DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE)) !=
|
||||
std::string::npos) ||
|
||||
(kernel_name.find(device_kernel_as_string(
|
||||
DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE)) != std::string::npos);
|
||||
}
|
||||
|
||||
bool oneapi_kernel_is_using_embree(const std::string &kernel_name)
|
||||
{
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
|
@ -182,8 +190,7 @@ bool oneapi_kernel_is_using_embree(const std::string &kernel_name)
|
|||
DeviceKernel kernel = (DeviceKernel)i;
|
||||
if (device_kernel_has_intersection(kernel)) {
|
||||
if (kernel_name.find(device_kernel_as_string(kernel)) != std::string::npos) {
|
||||
return !(kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE ||
|
||||
kernel == DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE);
|
||||
return !oneapi_kernel_is_raytrace_or_mnee(kernel_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -241,10 +248,6 @@ bool oneapi_load_kernels(SyclQueue *queue_,
|
|||
}
|
||||
# endif
|
||||
|
||||
# ifdef WITH_CYCLES_ONEAPI_BINARIES
|
||||
(void)queue_;
|
||||
(void)kernel_features;
|
||||
# else
|
||||
try {
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> all_kernels_bundle =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(),
|
||||
|
@ -260,18 +263,22 @@ bool oneapi_load_kernels(SyclQueue *queue_,
|
|||
continue;
|
||||
}
|
||||
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
/* This is expected to be the default, we set it again to be sure. */
|
||||
if (one_kernel_bundle_input
|
||||
.has_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>()) {
|
||||
# ifdef WITH_EMBREE_GPU
|
||||
if (oneapi_kernel_is_using_embree(kernel_name) ||
|
||||
oneapi_kernel_is_raytrace_or_mnee(kernel_name)) {
|
||||
sycl::kernel_bundle<sycl::bundle_state::input> one_kernel_bundle_input =
|
||||
sycl::get_kernel_bundle<sycl::bundle_state::input>(queue->get_context(), {kernel_id});
|
||||
one_kernel_bundle_input
|
||||
.set_specialization_constant<ONEAPIKernelContext::oneapi_embree_features>(
|
||||
RTC_FEATURE_FLAG_NONE);
|
||||
sycl::build(one_kernel_bundle_input);
|
||||
continue;
|
||||
}
|
||||
# endif
|
||||
sycl::build(one_kernel_bundle_input);
|
||||
# endif
|
||||
/* This call will ensure that AoT or cached JIT binaries are available
|
||||
* for execution. It will trigger compilation if it is not already the case. */
|
||||
(void)sycl::get_kernel_bundle<sycl::bundle_state::executable>(queue->get_context(),
|
||||
{kernel_id});
|
||||
}
|
||||
}
|
||||
catch (sycl::exception const &e) {
|
||||
|
@ -280,7 +287,6 @@ bool oneapi_load_kernels(SyclQueue *queue_,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,12 @@ set(SRC
|
|||
camera.cpp
|
||||
colorspace.cpp
|
||||
constant_fold.cpp
|
||||
devicescene.cpp
|
||||
film.cpp
|
||||
geometry.cpp
|
||||
geometry_attributes.cpp
|
||||
geometry_bvh.cpp
|
||||
geometry_mesh.cpp
|
||||
hair.cpp
|
||||
image.cpp
|
||||
image_oiio.cpp
|
||||
|
@ -55,6 +59,7 @@ set(SRC_HEADERS
|
|||
camera.h
|
||||
colorspace.h
|
||||
constant_fold.h
|
||||
devicescene.h
|
||||
film.h
|
||||
geometry.h
|
||||
hair.h
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "scene/devicescene.h"
|
||||
#include "device/device.h"
|
||||
#include "device/memory.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
DeviceScene::DeviceScene(Device *device)
|
||||
: bvh_nodes(device, "bvh_nodes", MEM_GLOBAL),
|
||||
bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL),
|
||||
object_node(device, "object_node", MEM_GLOBAL),
|
||||
prim_type(device, "prim_type", MEM_GLOBAL),
|
||||
prim_visibility(device, "prim_visibility", MEM_GLOBAL),
|
||||
prim_index(device, "prim_index", MEM_GLOBAL),
|
||||
prim_object(device, "prim_object", MEM_GLOBAL),
|
||||
prim_time(device, "prim_time", MEM_GLOBAL),
|
||||
tri_verts(device, "tri_verts", MEM_GLOBAL),
|
||||
tri_shader(device, "tri_shader", MEM_GLOBAL),
|
||||
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
|
||||
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
|
||||
tri_patch(device, "tri_patch", MEM_GLOBAL),
|
||||
tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
|
||||
curves(device, "curves", MEM_GLOBAL),
|
||||
curve_keys(device, "curve_keys", MEM_GLOBAL),
|
||||
curve_segments(device, "curve_segments", MEM_GLOBAL),
|
||||
patches(device, "patches", MEM_GLOBAL),
|
||||
points(device, "points", MEM_GLOBAL),
|
||||
points_shader(device, "points_shader", MEM_GLOBAL),
|
||||
objects(device, "objects", MEM_GLOBAL),
|
||||
object_motion_pass(device, "object_motion_pass", MEM_GLOBAL),
|
||||
object_motion(device, "object_motion", MEM_GLOBAL),
|
||||
object_flag(device, "object_flag", MEM_GLOBAL),
|
||||
object_volume_step(device, "object_volume_step", MEM_GLOBAL),
|
||||
object_prim_offset(device, "object_prim_offset", MEM_GLOBAL),
|
||||
camera_motion(device, "camera_motion", MEM_GLOBAL),
|
||||
attributes_map(device, "attributes_map", MEM_GLOBAL),
|
||||
attributes_float(device, "attributes_float", MEM_GLOBAL),
|
||||
attributes_float2(device, "attributes_float2", MEM_GLOBAL),
|
||||
attributes_float3(device, "attributes_float3", MEM_GLOBAL),
|
||||
attributes_float4(device, "attributes_float4", MEM_GLOBAL),
|
||||
attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL),
|
||||
light_distribution(device, "light_distribution", MEM_GLOBAL),
|
||||
lights(device, "lights", MEM_GLOBAL),
|
||||
light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL),
|
||||
light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL),
|
||||
light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL),
|
||||
light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL),
|
||||
light_to_tree(device, "light_to_tree", MEM_GLOBAL),
|
||||
object_to_tree(device, "object_to_tree", MEM_GLOBAL),
|
||||
object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL),
|
||||
triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL),
|
||||
particles(device, "particles", MEM_GLOBAL),
|
||||
svm_nodes(device, "svm_nodes", MEM_GLOBAL),
|
||||
shaders(device, "shaders", MEM_GLOBAL),
|
||||
lookup_table(device, "lookup_table", MEM_GLOBAL),
|
||||
sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL),
|
||||
ies_lights(device, "ies", MEM_GLOBAL)
|
||||
{
|
||||
memset((void *)&data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -0,0 +1,101 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#ifndef __DEVICESCENE_H__
|
||||
#define __DEVICESCENE_H__
|
||||
|
||||
#include "device/device.h"
|
||||
#include "device/memory.h"
|
||||
|
||||
#include "util/types.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class DeviceScene {
|
||||
public:
|
||||
/* BVH */
|
||||
device_vector<int4> bvh_nodes;
|
||||
device_vector<int4> bvh_leaf_nodes;
|
||||
device_vector<int> object_node;
|
||||
device_vector<int> prim_type;
|
||||
device_vector<uint> prim_visibility;
|
||||
device_vector<int> prim_index;
|
||||
device_vector<int> prim_object;
|
||||
device_vector<float2> prim_time;
|
||||
|
||||
/* mesh */
|
||||
device_vector<packed_float3> tri_verts;
|
||||
device_vector<uint> tri_shader;
|
||||
device_vector<packed_float3> tri_vnormal;
|
||||
device_vector<packed_uint3> tri_vindex;
|
||||
device_vector<uint> tri_patch;
|
||||
device_vector<float2> tri_patch_uv;
|
||||
|
||||
device_vector<KernelCurve> curves;
|
||||
device_vector<float4> curve_keys;
|
||||
device_vector<KernelCurveSegment> curve_segments;
|
||||
|
||||
device_vector<uint> patches;
|
||||
|
||||
/* point-cloud */
|
||||
device_vector<float4> points;
|
||||
device_vector<uint> points_shader;
|
||||
|
||||
/* objects */
|
||||
device_vector<KernelObject> objects;
|
||||
device_vector<Transform> object_motion_pass;
|
||||
device_vector<DecomposedTransform> object_motion;
|
||||
device_vector<uint> object_flag;
|
||||
device_vector<float> object_volume_step;
|
||||
device_vector<uint> object_prim_offset;
|
||||
|
||||
/* cameras */
|
||||
device_vector<DecomposedTransform> camera_motion;
|
||||
|
||||
/* attributes */
|
||||
device_vector<AttributeMap> attributes_map;
|
||||
device_vector<float> attributes_float;
|
||||
device_vector<float2> attributes_float2;
|
||||
device_vector<packed_float3> attributes_float3;
|
||||
device_vector<float4> attributes_float4;
|
||||
device_vector<uchar4> attributes_uchar4;
|
||||
|
||||
/* lights */
|
||||
device_vector<KernelLightDistribution> light_distribution;
|
||||
device_vector<KernelLight> lights;
|
||||
device_vector<float2> light_background_marginal_cdf;
|
||||
device_vector<float2> light_background_conditional_cdf;
|
||||
|
||||
/* light tree */
|
||||
device_vector<KernelLightTreeNode> light_tree_nodes;
|
||||
device_vector<KernelLightTreeEmitter> light_tree_emitters;
|
||||
device_vector<uint> light_to_tree;
|
||||
device_vector<uint> object_to_tree;
|
||||
device_vector<uint> object_lookup_offset;
|
||||
device_vector<uint> triangle_to_tree;
|
||||
|
||||
/* particles */
|
||||
device_vector<KernelParticle> particles;
|
||||
|
||||
/* shaders */
|
||||
device_vector<int4> svm_nodes;
|
||||
device_vector<KernelShader> shaders;
|
||||
|
||||
/* lookup tables */
|
||||
device_vector<float> lookup_table;
|
||||
|
||||
/* integrator */
|
||||
device_vector<float> sample_pattern_lut;
|
||||
|
||||
/* IES lights */
|
||||
device_vector<float> ies_lights;
|
||||
|
||||
KernelData data;
|
||||
|
||||
DeviceScene(Device *device);
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __DEVICESCENE_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -30,6 +30,38 @@ class Shader;
|
|||
class Volume;
|
||||
struct PackedBVH;
|
||||
|
||||
/* Set of flags used to help determining what data has been modified or needs reallocation, so we
|
||||
* can decide which device data to free or update. */
|
||||
enum {
|
||||
DEVICE_CURVE_DATA_MODIFIED = (1 << 0),
|
||||
DEVICE_MESH_DATA_MODIFIED = (1 << 1),
|
||||
DEVICE_POINT_DATA_MODIFIED = (1 << 2),
|
||||
|
||||
ATTR_FLOAT_MODIFIED = (1 << 3),
|
||||
ATTR_FLOAT2_MODIFIED = (1 << 4),
|
||||
ATTR_FLOAT3_MODIFIED = (1 << 5),
|
||||
ATTR_FLOAT4_MODIFIED = (1 << 6),
|
||||
ATTR_UCHAR4_MODIFIED = (1 << 7),
|
||||
|
||||
CURVE_DATA_NEED_REALLOC = (1 << 8),
|
||||
MESH_DATA_NEED_REALLOC = (1 << 9),
|
||||
POINT_DATA_NEED_REALLOC = (1 << 10),
|
||||
|
||||
ATTR_FLOAT_NEEDS_REALLOC = (1 << 11),
|
||||
ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12),
|
||||
ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13),
|
||||
ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14),
|
||||
|
||||
ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15),
|
||||
|
||||
ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC |
|
||||
ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC |
|
||||
ATTR_UCHAR4_NEEDS_REALLOC),
|
||||
DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_POINT_DATA_NEEDS_REALLOC = (POINT_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC),
|
||||
};
|
||||
|
||||
/* Geometry
|
||||
*
|
||||
* Base class for geometric types like Mesh and Hair. */
|
||||
|
|
|
@ -0,0 +1,722 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "bvh/bvh.h"
|
||||
#include "bvh/bvh2.h"
|
||||
|
||||
#include "device/device.h"
|
||||
|
||||
#include "scene/attribute.h"
|
||||
#include "scene/camera.h"
|
||||
#include "scene/geometry.h"
|
||||
#include "scene/hair.h"
|
||||
#include "scene/light.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
#include "scene/stats.h"
|
||||
#include "scene/volume.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#include "kernel/osl/globals.h"
|
||||
|
||||
#include "util/foreach.h"
|
||||
#include "util/log.h"
|
||||
#include "util/progress.h"
|
||||
#include "util/task.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
bool Geometry::need_attribute(Scene *scene, AttributeStandard std)
|
||||
{
|
||||
if (std == ATTR_STD_NONE)
|
||||
return false;
|
||||
|
||||
if (scene->need_global_attribute(std))
|
||||
return true;
|
||||
|
||||
foreach (Node *node, used_shaders) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->attributes.find(std))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Geometry::need_attribute(Scene * /*scene*/, ustring name)
|
||||
{
|
||||
if (name == ustring())
|
||||
return false;
|
||||
|
||||
foreach (Node *node, used_shaders) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
if (shader->attributes.find(name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
AttributeRequestSet Geometry::needed_attributes()
|
||||
{
|
||||
AttributeRequestSet result;
|
||||
|
||||
foreach (Node *node, used_shaders) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
result.add(shader->attributes);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Geometry::has_voxel_attributes() const
|
||||
{
|
||||
foreach (const Attribute &attr, attributes.attributes) {
|
||||
if (attr.element == ATTR_ELEMENT_VOXEL) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generate a normal attribute map entry from an attribute descriptor. */
|
||||
static void emit_attribute_map_entry(AttributeMap *attr_map,
|
||||
size_t index,
|
||||
uint64_t id,
|
||||
TypeDesc type,
|
||||
const AttributeDescriptor &desc)
|
||||
{
|
||||
attr_map[index].id = id;
|
||||
attr_map[index].element = desc.element;
|
||||
attr_map[index].offset = as_uint(desc.offset);
|
||||
|
||||
if (type == TypeDesc::TypeFloat)
|
||||
attr_map[index].type = NODE_ATTR_FLOAT;
|
||||
else if (type == TypeDesc::TypeMatrix)
|
||||
attr_map[index].type = NODE_ATTR_MATRIX;
|
||||
else if (type == TypeFloat2)
|
||||
attr_map[index].type = NODE_ATTR_FLOAT2;
|
||||
else if (type == TypeFloat4)
|
||||
attr_map[index].type = NODE_ATTR_FLOAT4;
|
||||
else if (type == TypeRGBA)
|
||||
attr_map[index].type = NODE_ATTR_RGBA;
|
||||
else
|
||||
attr_map[index].type = NODE_ATTR_FLOAT3;
|
||||
|
||||
attr_map[index].flags = desc.flags;
|
||||
}
|
||||
|
||||
/* Generate an attribute map end marker, optionally including a link to another map.
|
||||
* Links are used to connect object attribute maps to mesh attribute maps. */
|
||||
static void emit_attribute_map_terminator(AttributeMap *attr_map,
|
||||
size_t index,
|
||||
bool chain,
|
||||
uint chain_link)
|
||||
{
|
||||
for (int j = 0; j < ATTR_PRIM_TYPES; j++) {
|
||||
attr_map[index + j].id = ATTR_STD_NONE;
|
||||
attr_map[index + j].element = chain; /* link is valid flag */
|
||||
attr_map[index + j].offset = chain ? chain_link + j : 0; /* link to the correct sub-entry */
|
||||
attr_map[index + j].type = 0;
|
||||
attr_map[index + j].flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate all necessary attribute map entries from the attribute request. */
|
||||
static void emit_attribute_mapping(
|
||||
AttributeMap *attr_map, size_t index, uint64_t id, AttributeRequest &req, Geometry *geom)
|
||||
{
|
||||
emit_attribute_map_entry(attr_map, index, id, req.type, req.desc);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->get_num_subd_faces()) {
|
||||
emit_attribute_map_entry(attr_map, index + 1, id, req.subd_type, req.subd_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryManager::update_svm_attributes(Device *,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
vector<AttributeRequestSet> &geom_attributes,
|
||||
vector<AttributeRequestSet> &object_attributes)
|
||||
{
|
||||
/* for SVM, the attributes_map table is used to lookup the offset of an
|
||||
* attribute, based on a unique shader attribute id. */
|
||||
|
||||
/* compute array stride */
|
||||
size_t attr_map_size = 0;
|
||||
|
||||
for (size_t i = 0; i < scene->geometry.size(); i++) {
|
||||
Geometry *geom = scene->geometry[i];
|
||||
geom->attr_map_offset = attr_map_size;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
size_t attr_count = 0;
|
||||
foreach (AttributeRequest &req, geom_attributes[i].requests) {
|
||||
if (req.std != ATTR_STD_NONE &&
|
||||
scene->shader_manager->get_attribute_id(req.std) != (uint64_t)req.std)
|
||||
attr_count += 2;
|
||||
else
|
||||
attr_count += 1;
|
||||
}
|
||||
#else
|
||||
const size_t attr_count = geom_attributes[i].size();
|
||||
#endif
|
||||
|
||||
attr_map_size += (attr_count + 1) * ATTR_PRIM_TYPES;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scene->objects.size(); i++) {
|
||||
Object *object = scene->objects[i];
|
||||
|
||||
/* only allocate a table for the object if it actually has attributes */
|
||||
if (object_attributes[i].size() == 0) {
|
||||
object->attr_map_offset = 0;
|
||||
}
|
||||
else {
|
||||
object->attr_map_offset = attr_map_size;
|
||||
attr_map_size += (object_attributes[i].size() + 1) * ATTR_PRIM_TYPES;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr_map_size == 0)
|
||||
return;
|
||||
|
||||
if (!dscene->attributes_map.need_realloc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* create attribute map */
|
||||
AttributeMap *attr_map = dscene->attributes_map.alloc(attr_map_size);
|
||||
memset(attr_map, 0, dscene->attributes_map.size() * sizeof(*attr_map));
|
||||
|
||||
for (size_t i = 0; i < scene->geometry.size(); i++) {
|
||||
Geometry *geom = scene->geometry[i];
|
||||
AttributeRequestSet &attributes = geom_attributes[i];
|
||||
|
||||
/* set geometry attributes */
|
||||
size_t index = geom->attr_map_offset;
|
||||
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
uint64_t id;
|
||||
if (req.std == ATTR_STD_NONE)
|
||||
id = scene->shader_manager->get_attribute_id(req.name);
|
||||
else
|
||||
id = scene->shader_manager->get_attribute_id(req.std);
|
||||
|
||||
emit_attribute_mapping(attr_map, index, id, req, geom);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
|
||||
#ifdef WITH_OSL
|
||||
/* Some standard attributes are explicitly referenced via their standard ID, so add those
|
||||
* again in case they were added under a different attribute ID. */
|
||||
if (req.std != ATTR_STD_NONE && id != (uint64_t)req.std) {
|
||||
emit_attribute_mapping(attr_map, index, (uint64_t)req.std, req, geom);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
emit_attribute_map_terminator(attr_map, index, false, 0);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scene->objects.size(); i++) {
|
||||
Object *object = scene->objects[i];
|
||||
AttributeRequestSet &attributes = object_attributes[i];
|
||||
|
||||
/* set object attributes */
|
||||
if (attributes.size() > 0) {
|
||||
size_t index = object->attr_map_offset;
|
||||
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
uint64_t id;
|
||||
if (req.std == ATTR_STD_NONE)
|
||||
id = scene->shader_manager->get_attribute_id(req.name);
|
||||
else
|
||||
id = scene->shader_manager->get_attribute_id(req.std);
|
||||
|
||||
emit_attribute_mapping(attr_map, index, id, req, object->geometry);
|
||||
index += ATTR_PRIM_TYPES;
|
||||
}
|
||||
|
||||
emit_attribute_map_terminator(attr_map, index, true, object->geometry->attr_map_offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* copy to device */
|
||||
dscene->attributes_map.copy_to_device();
|
||||
}
|
||||
|
||||
void GeometryManager::update_attribute_element_offset(Geometry *geom,
|
||||
device_vector<float> &attr_float,
|
||||
size_t &attr_float_offset,
|
||||
device_vector<float2> &attr_float2,
|
||||
size_t &attr_float2_offset,
|
||||
device_vector<packed_float3> &attr_float3,
|
||||
size_t &attr_float3_offset,
|
||||
device_vector<float4> &attr_float4,
|
||||
size_t &attr_float4_offset,
|
||||
device_vector<uchar4> &attr_uchar4,
|
||||
size_t &attr_uchar4_offset,
|
||||
Attribute *mattr,
|
||||
AttributePrimitive prim,
|
||||
TypeDesc &type,
|
||||
AttributeDescriptor &desc)
|
||||
{
|
||||
if (mattr) {
|
||||
/* store element and type */
|
||||
desc.element = mattr->element;
|
||||
desc.flags = mattr->flags;
|
||||
type = mattr->type;
|
||||
|
||||
/* store attribute data in arrays */
|
||||
size_t size = mattr->element_size(geom, prim);
|
||||
|
||||
AttributeElement &element = desc.element;
|
||||
int &offset = desc.offset;
|
||||
|
||||
if (mattr->element == ATTR_ELEMENT_VOXEL) {
|
||||
/* store slot in offset value */
|
||||
ImageHandle &handle = mattr->data_voxel();
|
||||
offset = handle.svm_slot();
|
||||
}
|
||||
else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
uchar4 *data = mattr->data_uchar4();
|
||||
offset = attr_uchar4_offset;
|
||||
|
||||
assert(attr_uchar4.size() >= offset + size);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_uchar4[offset + k] = data[k];
|
||||
}
|
||||
attr_uchar4.tag_modified();
|
||||
}
|
||||
attr_uchar4_offset += size;
|
||||
}
|
||||
else if (mattr->type == TypeDesc::TypeFloat) {
|
||||
float *data = mattr->data_float();
|
||||
offset = attr_float_offset;
|
||||
|
||||
assert(attr_float.size() >= offset + size);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float[offset + k] = data[k];
|
||||
}
|
||||
attr_float.tag_modified();
|
||||
}
|
||||
attr_float_offset += size;
|
||||
}
|
||||
else if (mattr->type == TypeFloat2) {
|
||||
float2 *data = mattr->data_float2();
|
||||
offset = attr_float2_offset;
|
||||
|
||||
assert(attr_float2.size() >= offset + size);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float2[offset + k] = data[k];
|
||||
}
|
||||
attr_float2.tag_modified();
|
||||
}
|
||||
attr_float2_offset += size;
|
||||
}
|
||||
else if (mattr->type == TypeDesc::TypeMatrix) {
|
||||
Transform *tfm = mattr->data_transform();
|
||||
offset = attr_float4_offset;
|
||||
|
||||
assert(attr_float4.size() >= offset + size * 3);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size * 3; k++) {
|
||||
attr_float4[offset + k] = (&tfm->x)[k];
|
||||
}
|
||||
attr_float4.tag_modified();
|
||||
}
|
||||
attr_float4_offset += size * 3;
|
||||
}
|
||||
else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
|
||||
float4 *data = mattr->data_float4();
|
||||
offset = attr_float4_offset;
|
||||
|
||||
assert(attr_float4.size() >= offset + size);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float4[offset + k] = data[k];
|
||||
}
|
||||
attr_float4.tag_modified();
|
||||
}
|
||||
attr_float4_offset += size;
|
||||
}
|
||||
else {
|
||||
float3 *data = mattr->data_float3();
|
||||
offset = attr_float3_offset;
|
||||
|
||||
assert(attr_float3.size() >= offset + size);
|
||||
if (mattr->modified) {
|
||||
for (size_t k = 0; k < size; k++) {
|
||||
attr_float3[offset + k] = data[k];
|
||||
}
|
||||
attr_float3.tag_modified();
|
||||
}
|
||||
attr_float3_offset += size;
|
||||
}
|
||||
|
||||
/* mesh vertex/curve index is global, not per object, so we sneak
|
||||
* a correction for that in here */
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
if (mesh->subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK &&
|
||||
desc.flags & ATTR_SUBDIVIDED) {
|
||||
/* Indices for subdivided attributes are retrieved
|
||||
* from patch table so no need for correction here. */
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_VERTEX)
|
||||
offset -= mesh->vert_offset;
|
||||
else if (element == ATTR_ELEMENT_VERTEX_MOTION)
|
||||
offset -= mesh->vert_offset;
|
||||
else if (element == ATTR_ELEMENT_FACE) {
|
||||
if (prim == ATTR_PRIM_GEOMETRY)
|
||||
offset -= mesh->prim_offset;
|
||||
else
|
||||
offset -= mesh->face_offset;
|
||||
}
|
||||
else if (element == ATTR_ELEMENT_CORNER || element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
if (prim == ATTR_PRIM_GEOMETRY)
|
||||
offset -= 3 * mesh->prim_offset;
|
||||
else
|
||||
offset -= mesh->corner_offset;
|
||||
}
|
||||
}
|
||||
else if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
if (element == ATTR_ELEMENT_CURVE)
|
||||
offset -= hair->prim_offset;
|
||||
else if (element == ATTR_ELEMENT_CURVE_KEY)
|
||||
offset -= hair->curve_key_offset;
|
||||
else if (element == ATTR_ELEMENT_CURVE_KEY_MOTION)
|
||||
offset -= hair->curve_key_offset;
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
if (element == ATTR_ELEMENT_VERTEX)
|
||||
offset -= geom->prim_offset;
|
||||
else if (element == ATTR_ELEMENT_VERTEX_MOTION)
|
||||
offset -= geom->prim_offset;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* attribute not found */
|
||||
desc.element = ATTR_ELEMENT_NONE;
|
||||
desc.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void update_attribute_element_size(Geometry *geom,
|
||||
Attribute *mattr,
|
||||
AttributePrimitive prim,
|
||||
size_t *attr_float_size,
|
||||
size_t *attr_float2_size,
|
||||
size_t *attr_float3_size,
|
||||
size_t *attr_float4_size,
|
||||
size_t *attr_uchar4_size)
|
||||
{
|
||||
if (mattr) {
|
||||
size_t size = mattr->element_size(geom, prim);
|
||||
|
||||
if (mattr->element == ATTR_ELEMENT_VOXEL) {
|
||||
/* pass */
|
||||
}
|
||||
else if (mattr->element == ATTR_ELEMENT_CORNER_BYTE) {
|
||||
*attr_uchar4_size += size;
|
||||
}
|
||||
else if (mattr->type == TypeDesc::TypeFloat) {
|
||||
*attr_float_size += size;
|
||||
}
|
||||
else if (mattr->type == TypeFloat2) {
|
||||
*attr_float2_size += size;
|
||||
}
|
||||
else if (mattr->type == TypeDesc::TypeMatrix) {
|
||||
*attr_float4_size += size * 4;
|
||||
}
|
||||
else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) {
|
||||
*attr_float4_size += size;
|
||||
}
|
||||
else {
|
||||
*attr_float3_size += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryManager::device_update_attributes(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
progress.set_status("Updating Mesh", "Computing attributes");
|
||||
|
||||
/* gather per mesh requested attributes. as meshes may have multiple
|
||||
* shaders assigned, this merges the requested attributes that have
|
||||
* been set per shader by the shader manager */
|
||||
vector<AttributeRequestSet> geom_attributes(scene->geometry.size());
|
||||
|
||||
for (size_t i = 0; i < scene->geometry.size(); i++) {
|
||||
Geometry *geom = scene->geometry[i];
|
||||
|
||||
geom->index = i;
|
||||
scene->need_global_attributes(geom_attributes[i]);
|
||||
|
||||
foreach (Node *node, geom->get_used_shaders()) {
|
||||
Shader *shader = static_cast<Shader *>(node);
|
||||
geom_attributes[i].add(shader->attributes);
|
||||
}
|
||||
|
||||
if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) {
|
||||
geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY);
|
||||
}
|
||||
}
|
||||
|
||||
/* convert object attributes to use the same data structures as geometry ones */
|
||||
vector<AttributeRequestSet> object_attributes(scene->objects.size());
|
||||
vector<AttributeSet> object_attribute_values;
|
||||
|
||||
object_attribute_values.reserve(scene->objects.size());
|
||||
|
||||
for (size_t i = 0; i < scene->objects.size(); i++) {
|
||||
Object *object = scene->objects[i];
|
||||
Geometry *geom = object->geometry;
|
||||
size_t geom_idx = geom->index;
|
||||
|
||||
assert(geom_idx < scene->geometry.size() && scene->geometry[geom_idx] == geom);
|
||||
|
||||
object_attribute_values.push_back(AttributeSet(geom, ATTR_PRIM_GEOMETRY));
|
||||
|
||||
AttributeRequestSet &geom_requests = geom_attributes[geom_idx];
|
||||
AttributeRequestSet &attributes = object_attributes[i];
|
||||
AttributeSet &values = object_attribute_values[i];
|
||||
|
||||
for (size_t j = 0; j < object->attributes.size(); j++) {
|
||||
ParamValue ¶m = object->attributes[j];
|
||||
|
||||
/* add attributes that are requested and not already handled by the mesh */
|
||||
if (geom_requests.find(param.name()) && !geom->attributes.find(param.name())) {
|
||||
attributes.add(param.name());
|
||||
|
||||
Attribute *attr = values.add(param.name(), param.type(), ATTR_ELEMENT_OBJECT);
|
||||
assert(param.datasize() == attr->buffer.size());
|
||||
memcpy(attr->buffer.data(), param.data(), param.datasize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* mesh attribute are stored in a single array per data type. here we fill
|
||||
* those arrays, and set the offset and element type to create attribute
|
||||
* maps next */
|
||||
|
||||
/* Pre-allocate attributes to avoid arrays re-allocation which would
|
||||
* take 2x of overall attribute memory usage.
|
||||
*/
|
||||
size_t attr_float_size = 0;
|
||||
size_t attr_float2_size = 0;
|
||||
size_t attr_float3_size = 0;
|
||||
size_t attr_float4_size = 0;
|
||||
size_t attr_uchar4_size = 0;
|
||||
|
||||
for (size_t i = 0; i < scene->geometry.size(); i++) {
|
||||
Geometry *geom = scene->geometry[i];
|
||||
AttributeRequestSet &attributes = geom_attributes[i];
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
update_attribute_element_size(geom,
|
||||
attr,
|
||||
ATTR_PRIM_GEOMETRY,
|
||||
&attr_float_size,
|
||||
&attr_float2_size,
|
||||
&attr_float3_size,
|
||||
&attr_float4_size,
|
||||
&attr_uchar4_size);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
update_attribute_element_size(mesh,
|
||||
subd_attr,
|
||||
ATTR_PRIM_SUBD,
|
||||
&attr_float_size,
|
||||
&attr_float2_size,
|
||||
&attr_float3_size,
|
||||
&attr_float4_size,
|
||||
&attr_uchar4_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scene->objects.size(); i++) {
|
||||
Object *object = scene->objects[i];
|
||||
|
||||
foreach (Attribute &attr, object_attribute_values[i].attributes) {
|
||||
update_attribute_element_size(object->geometry,
|
||||
&attr,
|
||||
ATTR_PRIM_GEOMETRY,
|
||||
&attr_float_size,
|
||||
&attr_float2_size,
|
||||
&attr_float3_size,
|
||||
&attr_float4_size,
|
||||
&attr_uchar4_size);
|
||||
}
|
||||
}
|
||||
|
||||
dscene->attributes_float.alloc(attr_float_size);
|
||||
dscene->attributes_float2.alloc(attr_float2_size);
|
||||
dscene->attributes_float3.alloc(attr_float3_size);
|
||||
dscene->attributes_float4.alloc(attr_float4_size);
|
||||
dscene->attributes_uchar4.alloc(attr_uchar4_size);
|
||||
|
||||
/* The order of those flags needs to match that of AttrKernelDataType. */
|
||||
const bool attributes_need_realloc[AttrKernelDataType::NUM] = {
|
||||
dscene->attributes_float.need_realloc(),
|
||||
dscene->attributes_float2.need_realloc(),
|
||||
dscene->attributes_float3.need_realloc(),
|
||||
dscene->attributes_float4.need_realloc(),
|
||||
dscene->attributes_uchar4.need_realloc(),
|
||||
};
|
||||
|
||||
size_t attr_float_offset = 0;
|
||||
size_t attr_float2_offset = 0;
|
||||
size_t attr_float3_offset = 0;
|
||||
size_t attr_float4_offset = 0;
|
||||
size_t attr_uchar4_offset = 0;
|
||||
|
||||
/* Fill in attributes. */
|
||||
for (size_t i = 0; i < scene->geometry.size(); i++) {
|
||||
Geometry *geom = scene->geometry[i];
|
||||
AttributeRequestSet &attributes = geom_attributes[i];
|
||||
|
||||
/* todo: we now store std and name attributes from requests even if
|
||||
* they actually refer to the same mesh attributes, optimize */
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = geom->attributes.find(req);
|
||||
|
||||
if (attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
|
||||
}
|
||||
|
||||
update_attribute_element_offset(geom,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
dscene->attributes_float2,
|
||||
attr_float2_offset,
|
||||
dscene->attributes_float3,
|
||||
attr_float3_offset,
|
||||
dscene->attributes_float4,
|
||||
attr_float4_offset,
|
||||
dscene->attributes_uchar4,
|
||||
attr_uchar4_offset,
|
||||
attr,
|
||||
ATTR_PRIM_GEOMETRY,
|
||||
req.type,
|
||||
req.desc);
|
||||
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
Attribute *subd_attr = mesh->subd_attributes.find(req);
|
||||
|
||||
if (subd_attr) {
|
||||
/* force a copy if we need to reallocate all the data */
|
||||
subd_attr->modified |= attributes_need_realloc[Attribute::kernel_type(*subd_attr)];
|
||||
}
|
||||
|
||||
update_attribute_element_offset(mesh,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
dscene->attributes_float2,
|
||||
attr_float2_offset,
|
||||
dscene->attributes_float3,
|
||||
attr_float3_offset,
|
||||
dscene->attributes_float4,
|
||||
attr_float4_offset,
|
||||
dscene->attributes_uchar4,
|
||||
attr_uchar4_offset,
|
||||
subd_attr,
|
||||
ATTR_PRIM_SUBD,
|
||||
req.subd_type,
|
||||
req.subd_desc);
|
||||
}
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < scene->objects.size(); i++) {
|
||||
Object *object = scene->objects[i];
|
||||
AttributeRequestSet &attributes = object_attributes[i];
|
||||
AttributeSet &values = object_attribute_values[i];
|
||||
|
||||
foreach (AttributeRequest &req, attributes.requests) {
|
||||
Attribute *attr = values.find(req);
|
||||
|
||||
if (attr) {
|
||||
attr->modified |= attributes_need_realloc[Attribute::kernel_type(*attr)];
|
||||
}
|
||||
|
||||
update_attribute_element_offset(object->geometry,
|
||||
dscene->attributes_float,
|
||||
attr_float_offset,
|
||||
dscene->attributes_float2,
|
||||
attr_float2_offset,
|
||||
dscene->attributes_float3,
|
||||
attr_float3_offset,
|
||||
dscene->attributes_float4,
|
||||
attr_float4_offset,
|
||||
dscene->attributes_uchar4,
|
||||
attr_uchar4_offset,
|
||||
attr,
|
||||
ATTR_PRIM_GEOMETRY,
|
||||
req.type,
|
||||
req.desc);
|
||||
|
||||
/* object attributes don't care about subdivision */
|
||||
req.subd_type = req.type;
|
||||
req.subd_desc = req.desc;
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* create attribute lookup maps */
|
||||
if (scene->shader_manager->use_osl())
|
||||
update_osl_globals(device, scene);
|
||||
|
||||
update_svm_attributes(device, dscene, scene, geom_attributes, object_attributes);
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
/* copy to device */
|
||||
progress.set_status("Updating Mesh", "Copying Attributes to device");
|
||||
|
||||
dscene->attributes_float.copy_to_device_if_modified();
|
||||
dscene->attributes_float2.copy_to_device_if_modified();
|
||||
dscene->attributes_float3.copy_to_device_if_modified();
|
||||
dscene->attributes_float4.copy_to_device_if_modified();
|
||||
dscene->attributes_uchar4.copy_to_device_if_modified();
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
|
||||
/* After mesh attributes and patch tables have been copied to device memory,
|
||||
* we need to update offsets in the objects. */
|
||||
scene->object_manager->device_update_geom_offsets(device, dscene, scene);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -0,0 +1,196 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "bvh/bvh.h"
|
||||
#include "bvh/bvh2.h"
|
||||
|
||||
#include "device/device.h"
|
||||
|
||||
#include "scene/attribute.h"
|
||||
#include "scene/camera.h"
|
||||
#include "scene/geometry.h"
|
||||
#include "scene/hair.h"
|
||||
#include "scene/light.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
#include "scene/stats.h"
|
||||
#include "scene/volume.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#include "kernel/osl/globals.h"
|
||||
|
||||
#include "util/foreach.h"
|
||||
#include "util/log.h"
|
||||
#include "util/progress.h"
|
||||
#include "util/task.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
void Geometry::compute_bvh(Device *device,
|
||||
DeviceScene *dscene,
|
||||
SceneParams *params,
|
||||
Progress *progress,
|
||||
size_t n,
|
||||
size_t total)
|
||||
{
|
||||
if (progress->get_cancel())
|
||||
return;
|
||||
|
||||
compute_bounds();
|
||||
|
||||
const BVHLayout bvh_layout = BVHParams::best_bvh_layout(
|
||||
params->bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features));
|
||||
if (need_build_bvh(bvh_layout)) {
|
||||
string msg = "Updating Geometry BVH ";
|
||||
if (name.empty())
|
||||
msg += string_printf("%u/%u", (uint)(n + 1), (uint)total);
|
||||
else
|
||||
msg += string_printf("%s %u/%u", name.c_str(), (uint)(n + 1), (uint)total);
|
||||
|
||||
Object object;
|
||||
|
||||
/* Ensure all visibility bits are set at the geometry level BVH. In
|
||||
* the object level BVH is where actual visibility is tested. */
|
||||
object.set_is_shadow_catcher(true);
|
||||
object.set_visibility(~0);
|
||||
|
||||
object.set_geometry(this);
|
||||
|
||||
vector<Geometry *> geometry;
|
||||
geometry.push_back(this);
|
||||
vector<Object *> objects;
|
||||
objects.push_back(&object);
|
||||
|
||||
if (bvh && !need_update_rebuild) {
|
||||
progress->set_status(msg, "Refitting BVH");
|
||||
|
||||
bvh->replace_geometry(geometry, objects);
|
||||
|
||||
device->build_bvh(bvh, *progress, true);
|
||||
}
|
||||
else {
|
||||
progress->set_status(msg, "Building BVH");
|
||||
|
||||
BVHParams bparams;
|
||||
bparams.use_spatial_split = params->use_bvh_spatial_split;
|
||||
bparams.use_compact_structure = params->use_bvh_compact_structure;
|
||||
bparams.bvh_layout = bvh_layout;
|
||||
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
|
||||
params->use_bvh_unaligned_nodes;
|
||||
bparams.num_motion_triangle_steps = params->num_bvh_time_steps;
|
||||
bparams.num_motion_curve_steps = params->num_bvh_time_steps;
|
||||
bparams.num_motion_point_steps = params->num_bvh_time_steps;
|
||||
bparams.bvh_type = params->bvh_type;
|
||||
bparams.curve_subdivisions = params->curve_subdivisions();
|
||||
|
||||
delete bvh;
|
||||
bvh = BVH::create(bparams, geometry, objects, device);
|
||||
MEM_GUARDED_CALL(progress, device->build_bvh, bvh, *progress, false);
|
||||
}
|
||||
}
|
||||
|
||||
need_update_rebuild = false;
|
||||
need_update_bvh_for_offset = false;
|
||||
}
|
||||
|
||||
void GeometryManager::device_update_bvh(Device *device,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
/* bvh build */
|
||||
progress.set_status("Updating Scene BVH", "Building");
|
||||
|
||||
BVHParams bparams;
|
||||
bparams.top_level = true;
|
||||
bparams.bvh_layout = BVHParams::best_bvh_layout(
|
||||
scene->params.bvh_layout, device->get_bvh_layout_mask(dscene->data.kernel_features));
|
||||
bparams.use_spatial_split = scene->params.use_bvh_spatial_split;
|
||||
bparams.use_unaligned_nodes = dscene->data.bvh.have_curves &&
|
||||
scene->params.use_bvh_unaligned_nodes;
|
||||
bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.num_motion_point_steps = scene->params.num_bvh_time_steps;
|
||||
bparams.bvh_type = scene->params.bvh_type;
|
||||
bparams.curve_subdivisions = scene->params.curve_subdivisions();
|
||||
|
||||
VLOG_INFO << "Using " << bvh_layout_name(bparams.bvh_layout) << " layout.";
|
||||
|
||||
const bool can_refit = scene->bvh != nullptr &&
|
||||
(bparams.bvh_layout == BVHLayout::BVH_LAYOUT_OPTIX ||
|
||||
bparams.bvh_layout == BVHLayout::BVH_LAYOUT_METAL);
|
||||
|
||||
BVH *bvh = scene->bvh;
|
||||
if (!scene->bvh) {
|
||||
bvh = scene->bvh = BVH::create(bparams, scene->geometry, scene->objects, device);
|
||||
}
|
||||
|
||||
device->build_bvh(bvh, progress, can_refit);
|
||||
|
||||
if (progress.get_cancel()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool has_bvh2_layout = (bparams.bvh_layout == BVH_LAYOUT_BVH2);
|
||||
|
||||
PackedBVH pack;
|
||||
if (has_bvh2_layout) {
|
||||
pack = std::move(static_cast<BVH2 *>(bvh)->pack);
|
||||
}
|
||||
else {
|
||||
pack.root_index = -1;
|
||||
}
|
||||
|
||||
/* copy to device */
|
||||
progress.set_status("Updating Scene BVH", "Copying BVH to device");
|
||||
|
||||
/* When using BVH2, we always have to copy/update the data as its layout is dependent on the
|
||||
* BVH's leaf nodes which may be different when the objects or vertices move. */
|
||||
|
||||
if (pack.nodes.size()) {
|
||||
dscene->bvh_nodes.steal_data(pack.nodes);
|
||||
dscene->bvh_nodes.copy_to_device();
|
||||
}
|
||||
if (pack.leaf_nodes.size()) {
|
||||
dscene->bvh_leaf_nodes.steal_data(pack.leaf_nodes);
|
||||
dscene->bvh_leaf_nodes.copy_to_device();
|
||||
}
|
||||
if (pack.object_node.size()) {
|
||||
dscene->object_node.steal_data(pack.object_node);
|
||||
dscene->object_node.copy_to_device();
|
||||
}
|
||||
if (pack.prim_type.size()) {
|
||||
dscene->prim_type.steal_data(pack.prim_type);
|
||||
dscene->prim_type.copy_to_device();
|
||||
}
|
||||
if (pack.prim_visibility.size()) {
|
||||
dscene->prim_visibility.steal_data(pack.prim_visibility);
|
||||
dscene->prim_visibility.copy_to_device();
|
||||
}
|
||||
if (pack.prim_index.size()) {
|
||||
dscene->prim_index.steal_data(pack.prim_index);
|
||||
dscene->prim_index.copy_to_device();
|
||||
}
|
||||
if (pack.prim_object.size()) {
|
||||
dscene->prim_object.steal_data(pack.prim_object);
|
||||
dscene->prim_object.copy_to_device();
|
||||
}
|
||||
if (pack.prim_time.size()) {
|
||||
dscene->prim_time.steal_data(pack.prim_time);
|
||||
dscene->prim_time.copy_to_device();
|
||||
}
|
||||
|
||||
dscene->data.bvh.root = pack.root_index;
|
||||
dscene->data.bvh.use_bvh_steps = (scene->params.num_bvh_time_steps != 0);
|
||||
dscene->data.bvh.curve_subdivisions = scene->params.curve_subdivisions();
|
||||
/* The scene handle is set in 'CPUDevice::const_copy_to' and 'OptiXDevice::const_copy_to' */
|
||||
dscene->data.device_bvh = 0;
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -0,0 +1,223 @@
|
|||
/* SPDX-License-Identifier: Apache-2.0
|
||||
* Copyright 2011-2022 Blender Foundation */
|
||||
|
||||
#include "bvh/bvh.h"
|
||||
#include "bvh/bvh2.h"
|
||||
|
||||
#include "device/device.h"
|
||||
|
||||
#include "scene/attribute.h"
|
||||
#include "scene/camera.h"
|
||||
#include "scene/geometry.h"
|
||||
#include "scene/hair.h"
|
||||
#include "scene/light.h"
|
||||
#include "scene/mesh.h"
|
||||
#include "scene/object.h"
|
||||
#include "scene/osl.h"
|
||||
#include "scene/pointcloud.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/shader.h"
|
||||
#include "scene/shader_nodes.h"
|
||||
#include "scene/stats.h"
|
||||
#include "scene/volume.h"
|
||||
|
||||
#include "subd/patch_table.h"
|
||||
#include "subd/split.h"
|
||||
|
||||
#ifdef WITH_OSL
|
||||
# include "kernel/osl/globals.h"
|
||||
#endif
|
||||
|
||||
#include "util/foreach.h"
|
||||
#include "util/log.h"
|
||||
#include "util/progress.h"
|
||||
#include "util/task.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
void GeometryManager::device_update_mesh(Device *,
|
||||
DeviceScene *dscene,
|
||||
Scene *scene,
|
||||
Progress &progress)
|
||||
{
|
||||
/* Count. */
|
||||
size_t vert_size = 0;
|
||||
size_t tri_size = 0;
|
||||
|
||||
size_t curve_key_size = 0;
|
||||
size_t curve_size = 0;
|
||||
size_t curve_segment_size = 0;
|
||||
|
||||
size_t point_size = 0;
|
||||
|
||||
size_t patch_size = 0;
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
||||
vert_size += mesh->verts.size();
|
||||
tri_size += mesh->num_triangles();
|
||||
|
||||
if (mesh->get_num_subd_faces()) {
|
||||
Mesh::SubdFace last = mesh->get_subd_face(mesh->get_num_subd_faces() - 1);
|
||||
patch_size += (last.ptex_offset + last.num_ptex_faces()) * 8;
|
||||
|
||||
/* patch tables are stored in same array so include them in patch_size */
|
||||
if (mesh->patch_table) {
|
||||
mesh->patch_table_offset = patch_size;
|
||||
patch_size += mesh->patch_table->total_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
|
||||
curve_key_size += hair->get_curve_keys().size();
|
||||
curve_size += hair->num_curves();
|
||||
curve_segment_size += hair->num_segments();
|
||||
}
|
||||
else if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
point_size += pointcloud->num_points();
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in all the arrays. */
|
||||
if (tri_size != 0) {
|
||||
/* normals */
|
||||
progress.set_status("Updating Mesh", "Computing normals");
|
||||
|
||||
packed_float3 *tri_verts = dscene->tri_verts.alloc(vert_size);
|
||||
uint *tri_shader = dscene->tri_shader.alloc(tri_size);
|
||||
packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size);
|
||||
packed_uint3 *tri_vindex = dscene->tri_vindex.alloc(tri_size);
|
||||
uint *tri_patch = dscene->tri_patch.alloc(tri_size);
|
||||
float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size);
|
||||
|
||||
const bool copy_all_data = dscene->tri_shader.need_realloc() ||
|
||||
dscene->tri_vindex.need_realloc() ||
|
||||
dscene->tri_vnormal.need_realloc() ||
|
||||
dscene->tri_patch.need_realloc() ||
|
||||
dscene->tri_patch_uv.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
|
||||
if (mesh->shader_is_modified() || mesh->smooth_is_modified() ||
|
||||
mesh->triangles_is_modified() || copy_all_data) {
|
||||
mesh->pack_shaders(scene, &tri_shader[mesh->prim_offset]);
|
||||
}
|
||||
|
||||
if (mesh->verts_is_modified() || copy_all_data) {
|
||||
mesh->pack_normals(&vnormal[mesh->vert_offset]);
|
||||
}
|
||||
|
||||
if (mesh->verts_is_modified() || mesh->triangles_is_modified() ||
|
||||
mesh->vert_patch_uv_is_modified() || copy_all_data) {
|
||||
mesh->pack_verts(&tri_verts[mesh->vert_offset],
|
||||
&tri_vindex[mesh->prim_offset],
|
||||
&tri_patch[mesh->prim_offset],
|
||||
&tri_patch_uv[mesh->vert_offset]);
|
||||
}
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* vertex coordinates */
|
||||
progress.set_status("Updating Mesh", "Copying Mesh to device");
|
||||
|
||||
dscene->tri_verts.copy_to_device_if_modified();
|
||||
dscene->tri_shader.copy_to_device_if_modified();
|
||||
dscene->tri_vnormal.copy_to_device_if_modified();
|
||||
dscene->tri_vindex.copy_to_device_if_modified();
|
||||
dscene->tri_patch.copy_to_device_if_modified();
|
||||
dscene->tri_patch_uv.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (curve_segment_size != 0) {
|
||||
progress.set_status("Updating Mesh", "Copying Curves to device");
|
||||
|
||||
float4 *curve_keys = dscene->curve_keys.alloc(curve_key_size);
|
||||
KernelCurve *curves = dscene->curves.alloc(curve_size);
|
||||
KernelCurveSegment *curve_segments = dscene->curve_segments.alloc(curve_segment_size);
|
||||
|
||||
const bool copy_all_data = dscene->curve_keys.need_realloc() ||
|
||||
dscene->curves.need_realloc() ||
|
||||
dscene->curve_segments.need_realloc();
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_hair()) {
|
||||
Hair *hair = static_cast<Hair *>(geom);
|
||||
|
||||
bool curve_keys_co_modified = hair->curve_radius_is_modified() ||
|
||||
hair->curve_keys_is_modified();
|
||||
bool curve_data_modified = hair->curve_shader_is_modified() ||
|
||||
hair->curve_first_key_is_modified();
|
||||
|
||||
if (!curve_keys_co_modified && !curve_data_modified && !copy_all_data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hair->pack_curves(scene,
|
||||
&curve_keys[hair->curve_key_offset],
|
||||
&curves[hair->prim_offset],
|
||||
&curve_segments[hair->curve_segment_offset]);
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dscene->curve_keys.copy_to_device_if_modified();
|
||||
dscene->curves.copy_to_device_if_modified();
|
||||
dscene->curve_segments.copy_to_device_if_modified();
|
||||
}
|
||||
|
||||
if (point_size != 0) {
|
||||
progress.set_status("Updating Mesh", "Copying Point clouds to device");
|
||||
|
||||
float4 *points = dscene->points.alloc(point_size);
|
||||
uint *points_shader = dscene->points_shader.alloc(point_size);
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_pointcloud()) {
|
||||
PointCloud *pointcloud = static_cast<PointCloud *>(geom);
|
||||
pointcloud->pack(
|
||||
scene, &points[pointcloud->prim_offset], &points_shader[pointcloud->prim_offset]);
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dscene->points.copy_to_device();
|
||||
dscene->points_shader.copy_to_device();
|
||||
}
|
||||
|
||||
if (patch_size != 0 && dscene->patches.need_realloc()) {
|
||||
progress.set_status("Updating Mesh", "Copying Patches to device");
|
||||
|
||||
uint *patch_data = dscene->patches.alloc(patch_size);
|
||||
|
||||
foreach (Geometry *geom, scene->geometry) {
|
||||
if (geom->is_mesh()) {
|
||||
Mesh *mesh = static_cast<Mesh *>(geom);
|
||||
mesh->pack_patches(&patch_data[mesh->patch_offset]);
|
||||
|
||||
if (mesh->patch_table) {
|
||||
mesh->patch_table->copy_adjusting_offsets(&patch_data[mesh->patch_table_offset],
|
||||
mesh->patch_table_offset);
|
||||
}
|
||||
|
||||
if (progress.get_cancel())
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dscene->patches.copy_to_device();
|
||||
}
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
|
@ -24,6 +24,7 @@
|
|||
#include "scene/svm.h"
|
||||
#include "scene/tables.h"
|
||||
#include "scene/volume.h"
|
||||
#include "scene/devicescene.h"
|
||||
#include "session/session.h"
|
||||
|
||||
#include "util/foreach.h"
|
||||
|
@ -33,59 +34,7 @@
|
|||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
DeviceScene::DeviceScene(Device *device)
|
||||
: bvh_nodes(device, "bvh_nodes", MEM_GLOBAL),
|
||||
bvh_leaf_nodes(device, "bvh_leaf_nodes", MEM_GLOBAL),
|
||||
object_node(device, "object_node", MEM_GLOBAL),
|
||||
prim_type(device, "prim_type", MEM_GLOBAL),
|
||||
prim_visibility(device, "prim_visibility", MEM_GLOBAL),
|
||||
prim_index(device, "prim_index", MEM_GLOBAL),
|
||||
prim_object(device, "prim_object", MEM_GLOBAL),
|
||||
prim_time(device, "prim_time", MEM_GLOBAL),
|
||||
tri_verts(device, "tri_verts", MEM_GLOBAL),
|
||||
tri_shader(device, "tri_shader", MEM_GLOBAL),
|
||||
tri_vnormal(device, "tri_vnormal", MEM_GLOBAL),
|
||||
tri_vindex(device, "tri_vindex", MEM_GLOBAL),
|
||||
tri_patch(device, "tri_patch", MEM_GLOBAL),
|
||||
tri_patch_uv(device, "tri_patch_uv", MEM_GLOBAL),
|
||||
curves(device, "curves", MEM_GLOBAL),
|
||||
curve_keys(device, "curve_keys", MEM_GLOBAL),
|
||||
curve_segments(device, "curve_segments", MEM_GLOBAL),
|
||||
patches(device, "patches", MEM_GLOBAL),
|
||||
points(device, "points", MEM_GLOBAL),
|
||||
points_shader(device, "points_shader", MEM_GLOBAL),
|
||||
objects(device, "objects", MEM_GLOBAL),
|
||||
object_motion_pass(device, "object_motion_pass", MEM_GLOBAL),
|
||||
object_motion(device, "object_motion", MEM_GLOBAL),
|
||||
object_flag(device, "object_flag", MEM_GLOBAL),
|
||||
object_volume_step(device, "object_volume_step", MEM_GLOBAL),
|
||||
object_prim_offset(device, "object_prim_offset", MEM_GLOBAL),
|
||||
camera_motion(device, "camera_motion", MEM_GLOBAL),
|
||||
attributes_map(device, "attributes_map", MEM_GLOBAL),
|
||||
attributes_float(device, "attributes_float", MEM_GLOBAL),
|
||||
attributes_float2(device, "attributes_float2", MEM_GLOBAL),
|
||||
attributes_float3(device, "attributes_float3", MEM_GLOBAL),
|
||||
attributes_float4(device, "attributes_float4", MEM_GLOBAL),
|
||||
attributes_uchar4(device, "attributes_uchar4", MEM_GLOBAL),
|
||||
light_distribution(device, "light_distribution", MEM_GLOBAL),
|
||||
lights(device, "lights", MEM_GLOBAL),
|
||||
light_background_marginal_cdf(device, "light_background_marginal_cdf", MEM_GLOBAL),
|
||||
light_background_conditional_cdf(device, "light_background_conditional_cdf", MEM_GLOBAL),
|
||||
light_tree_nodes(device, "light_tree_nodes", MEM_GLOBAL),
|
||||
light_tree_emitters(device, "light_tree_emitters", MEM_GLOBAL),
|
||||
light_to_tree(device, "light_to_tree", MEM_GLOBAL),
|
||||
object_to_tree(device, "object_to_tree", MEM_GLOBAL),
|
||||
object_lookup_offset(device, "object_lookup_offset", MEM_GLOBAL),
|
||||
triangle_to_tree(device, "triangle_to_tree", MEM_GLOBAL),
|
||||
particles(device, "particles", MEM_GLOBAL),
|
||||
svm_nodes(device, "svm_nodes", MEM_GLOBAL),
|
||||
shaders(device, "shaders", MEM_GLOBAL),
|
||||
lookup_table(device, "lookup_table", MEM_GLOBAL),
|
||||
sample_pattern_lut(device, "sample_pattern_lut", MEM_GLOBAL),
|
||||
ies_lights(device, "ies", MEM_GLOBAL)
|
||||
{
|
||||
memset((void *)&data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
|
||||
Scene::Scene(const SceneParams ¶ms_, Device *device)
|
||||
: name("Scene"),
|
||||
|
|
|
@ -6,20 +6,16 @@
|
|||
|
||||
#include "bvh/params.h"
|
||||
|
||||
#include "scene/devicescene.h"
|
||||
#include "scene/film.h"
|
||||
#include "scene/image.h"
|
||||
#include "scene/shader.h"
|
||||
|
||||
#include "device/device.h"
|
||||
#include "device/memory.h"
|
||||
|
||||
#include "util/param.h"
|
||||
#include "util/string.h"
|
||||
#include "util/system.h"
|
||||
#include "util/texture.h"
|
||||
#include "util/thread.h"
|
||||
#include "util/types.h"
|
||||
#include "util/vector.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -54,92 +50,6 @@ class RenderStats;
|
|||
class SceneUpdateStats;
|
||||
class Volume;
|
||||
|
||||
/* Scene Device Data */
|
||||
|
||||
class DeviceScene {
|
||||
public:
|
||||
/* BVH */
|
||||
device_vector<int4> bvh_nodes;
|
||||
device_vector<int4> bvh_leaf_nodes;
|
||||
device_vector<int> object_node;
|
||||
device_vector<int> prim_type;
|
||||
device_vector<uint> prim_visibility;
|
||||
device_vector<int> prim_index;
|
||||
device_vector<int> prim_object;
|
||||
device_vector<float2> prim_time;
|
||||
|
||||
/* mesh */
|
||||
device_vector<packed_float3> tri_verts;
|
||||
device_vector<uint> tri_shader;
|
||||
device_vector<packed_float3> tri_vnormal;
|
||||
device_vector<packed_uint3> tri_vindex;
|
||||
device_vector<uint> tri_patch;
|
||||
device_vector<float2> tri_patch_uv;
|
||||
|
||||
device_vector<KernelCurve> curves;
|
||||
device_vector<float4> curve_keys;
|
||||
device_vector<KernelCurveSegment> curve_segments;
|
||||
|
||||
device_vector<uint> patches;
|
||||
|
||||
/* point-cloud */
|
||||
device_vector<float4> points;
|
||||
device_vector<uint> points_shader;
|
||||
|
||||
/* objects */
|
||||
device_vector<KernelObject> objects;
|
||||
device_vector<Transform> object_motion_pass;
|
||||
device_vector<DecomposedTransform> object_motion;
|
||||
device_vector<uint> object_flag;
|
||||
device_vector<float> object_volume_step;
|
||||
device_vector<uint> object_prim_offset;
|
||||
|
||||
/* cameras */
|
||||
device_vector<DecomposedTransform> camera_motion;
|
||||
|
||||
/* attributes */
|
||||
device_vector<AttributeMap> attributes_map;
|
||||
device_vector<float> attributes_float;
|
||||
device_vector<float2> attributes_float2;
|
||||
device_vector<packed_float3> attributes_float3;
|
||||
device_vector<float4> attributes_float4;
|
||||
device_vector<uchar4> attributes_uchar4;
|
||||
|
||||
/* lights */
|
||||
device_vector<KernelLightDistribution> light_distribution;
|
||||
device_vector<KernelLight> lights;
|
||||
device_vector<float2> light_background_marginal_cdf;
|
||||
device_vector<float2> light_background_conditional_cdf;
|
||||
|
||||
/* light tree */
|
||||
device_vector<KernelLightTreeNode> light_tree_nodes;
|
||||
device_vector<KernelLightTreeEmitter> light_tree_emitters;
|
||||
device_vector<uint> light_to_tree;
|
||||
device_vector<uint> object_to_tree;
|
||||
device_vector<uint> object_lookup_offset;
|
||||
device_vector<uint> triangle_to_tree;
|
||||
|
||||
/* particles */
|
||||
device_vector<KernelParticle> particles;
|
||||
|
||||
/* shaders */
|
||||
device_vector<int4> svm_nodes;
|
||||
device_vector<KernelShader> shaders;
|
||||
|
||||
/* lookup tables */
|
||||
device_vector<float> lookup_table;
|
||||
|
||||
/* integrator */
|
||||
device_vector<float> sample_pattern_lut;
|
||||
|
||||
/* IES lights */
|
||||
device_vector<float> ies_lights;
|
||||
|
||||
KernelData data;
|
||||
|
||||
DeviceScene(Device *device);
|
||||
};
|
||||
|
||||
/* Scene Parameters */
|
||||
|
||||
class SceneParams {
|
||||
|
|
|
@ -72,7 +72,7 @@ class GHOST_ISystemPaths {
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
virtual void addToSystemRecentFiles(const char *filename) const = 0;
|
||||
virtual void addToSystemRecentFiles(const char *filepath) const = 0;
|
||||
|
||||
private:
|
||||
/** The one and only system paths. */
|
||||
|
|
|
@ -61,7 +61,7 @@ extern const char *GHOST_getBinaryDir(void);
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
extern void GHOST_addToSystemRecentFiles(const char *filename);
|
||||
extern void GHOST_addToSystemRecentFiles(const char *filepath);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include "GHOST_Context.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
# include <epoxy/wgl.h>
|
||||
# include <tchar.h>
|
||||
#
|
||||
|
@ -18,6 +21,8 @@
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
#include "GHOST_IContext.hh"
|
||||
#include "GHOST_Types.h"
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include <cstdlib> // for NULL
|
||||
|
||||
class GHOST_Context : public GHOST_IContext {
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <Metal/Metal.h>
|
||||
#include <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
|
|
|
@ -57,4 +57,4 @@ class GHOST_IXrGraphicsBinding {
|
|||
};
|
||||
|
||||
std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
|
||||
GHOST_TXrGraphicsBinding type, GHOST_Context &ghost_ctx);
|
||||
GHOST_TXrGraphicsBinding type, GHOST_Context &context);
|
||||
|
|
|
@ -47,5 +47,5 @@ class GHOST_SystemPaths : public GHOST_ISystemPaths {
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
virtual void addToSystemRecentFiles(const char *filename) const = 0;
|
||||
virtual void addToSystemRecentFiles(const char *filepath) const = 0;
|
||||
};
|
||||
|
|
|
@ -54,5 +54,5 @@ class GHOST_SystemPathsCocoa : public GHOST_SystemPaths {
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
void addToSystemRecentFiles(const char *filename) const;
|
||||
void addToSystemRecentFiles(const char *filepath) const;
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2010 Blender Foundation */
|
||||
|
||||
#import <AppKit/NSDocumentController.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include "GHOST_Debug.hh"
|
||||
|
@ -112,7 +113,10 @@ const char *GHOST_SystemPathsCocoa::getBinaryDir() const
|
|||
return tempPath;
|
||||
}
|
||||
|
||||
void GHOST_SystemPathsCocoa::addToSystemRecentFiles(const char *filename) const
|
||||
void GHOST_SystemPathsCocoa::addToSystemRecentFiles(const char *filepath) const
|
||||
{
|
||||
/* TODO: implement for macOS */
|
||||
@autoreleasepool {
|
||||
NSURL *const file_url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:filepath]];
|
||||
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:file_url];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,5 +52,5 @@ class GHOST_SystemPathsUnix : public GHOST_SystemPaths {
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
void addToSystemRecentFiles(const char *filename) const;
|
||||
void addToSystemRecentFiles(const char *filepath) const;
|
||||
};
|
||||
|
|
|
@ -117,10 +117,10 @@ const char *GHOST_SystemPathsWin32::getBinaryDir() const
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void GHOST_SystemPathsWin32::addToSystemRecentFiles(const char *filename) const
|
||||
void GHOST_SystemPathsWin32::addToSystemRecentFiles(const char *filepath) const
|
||||
{
|
||||
/* SHARD_PATH resolves to SHARD_PATHA for non-UNICODE build */
|
||||
UTF16_ENCODE(filename);
|
||||
SHAddToRecentDocs(SHARD_PATHW, filename_16);
|
||||
UTF16_UN_ENCODE(filename);
|
||||
UTF16_ENCODE(filepath);
|
||||
SHAddToRecentDocs(SHARD_PATHW, filepath_16);
|
||||
UTF16_UN_ENCODE(filepath);
|
||||
}
|
||||
|
|
|
@ -61,5 +61,5 @@ class GHOST_SystemPathsWin32 : public GHOST_SystemPaths {
|
|||
/**
|
||||
* Add the file to the operating system most recently used files
|
||||
*/
|
||||
void addToSystemRecentFiles(const char *filename) const;
|
||||
void addToSystemRecentFiles(const char *filepath) const;
|
||||
};
|
||||
|
|
|
@ -5586,8 +5586,6 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
|
|||
# endif
|
||||
display_destroy_and_free_all();
|
||||
throw std::runtime_error("Wayland: unable to find libdecor!");
|
||||
|
||||
use_libdecor = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -5610,7 +5608,7 @@ GHOST_SystemWayland::GHOST_SystemWayland(bool background)
|
|||
(void)background;
|
||||
#endif
|
||||
{
|
||||
GWL_XDG_Decor_System &decor = *display_->xdg_decor;
|
||||
const GWL_XDG_Decor_System &decor = *display_->xdg_decor;
|
||||
if (!decor.shell) {
|
||||
display_destroy_and_free_all();
|
||||
throw std::runtime_error("Wayland: unable to access xdg_shell!");
|
||||
|
@ -6071,10 +6069,8 @@ static GHOST_TSuccess getCursorPositionClientRelative_impl(
|
|||
/* As the cursor is restored at the warped location,
|
||||
* apply warping when requesting the cursor location. */
|
||||
GHOST_Rect wrap_bounds{};
|
||||
if (win->getCursorGrabModeIsWarp()) {
|
||||
if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) {
|
||||
win->getClientBounds(wrap_bounds);
|
||||
}
|
||||
if (win->getCursorGrabBounds(wrap_bounds) == GHOST_kFailure) {
|
||||
win->getClientBounds(wrap_bounds);
|
||||
}
|
||||
int xy_wrap[2] = {
|
||||
seat_state_pointer->xy[0],
|
||||
|
@ -6680,10 +6676,9 @@ GHOST_TSuccess GHOST_SystemWayland::cursor_shape_custom_set(uint8_t *bitmap,
|
|||
static constexpr uint32_t transparent = 0x00000000;
|
||||
|
||||
uint8_t datab = 0, maskb = 0;
|
||||
uint32_t *pixel;
|
||||
|
||||
for (int y = 0; y < sizey; ++y) {
|
||||
pixel = &static_cast<uint32_t *>(cursor->custom_data)[y * sizex];
|
||||
uint32_t *pixel = &static_cast<uint32_t *>(cursor->custom_data)[y * sizex];
|
||||
for (int x = 0; x < sizex; ++x) {
|
||||
if ((x % 8) == 0) {
|
||||
datab = *bitmap++;
|
||||
|
|
|
@ -37,15 +37,15 @@ bool ghost_wl_output_own(const struct wl_output *wl_output);
|
|||
void ghost_wl_output_tag(struct wl_output *wl_output);
|
||||
struct GWL_Output *ghost_wl_output_user_data(struct wl_output *wl_output);
|
||||
|
||||
bool ghost_wl_surface_own(const struct wl_surface *surface);
|
||||
void ghost_wl_surface_tag(struct wl_surface *surface);
|
||||
GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *surface);
|
||||
bool ghost_wl_surface_own(const struct wl_surface *wl_surface);
|
||||
void ghost_wl_surface_tag(struct wl_surface *wl_surface);
|
||||
GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface);
|
||||
|
||||
bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *surface);
|
||||
void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *surface);
|
||||
bool ghost_wl_surface_own_cursor_pointer(const struct wl_surface *wl_surface);
|
||||
void ghost_wl_surface_tag_cursor_pointer(struct wl_surface *wl_surface);
|
||||
|
||||
bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *surface);
|
||||
void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *surface);
|
||||
bool ghost_wl_surface_own_cursor_tablet(const struct wl_surface *wl_surface);
|
||||
void ghost_wl_surface_tag_cursor_tablet(struct wl_surface *wl_surface);
|
||||
|
||||
/* Scaling to: translates from WAYLAND into GHOST (viewport local) coordinates.
|
||||
* Scaling from: performs the reverse translation.
|
||||
|
|
|
@ -85,7 +85,7 @@ static uchar bit_is_on(const uchar *ptr, int bit)
|
|||
|
||||
static GHOST_TKey ghost_key_from_keysym(const KeySym key);
|
||||
static GHOST_TKey ghost_key_from_keycode(const XkbDescPtr xkb_descr, const KeyCode keycode);
|
||||
static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key,
|
||||
static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym,
|
||||
const XkbDescPtr xkb_descr,
|
||||
const KeyCode keycode);
|
||||
|
||||
|
@ -99,7 +99,12 @@ static bool use_xwayland_hack = false;
|
|||
|
||||
using namespace std;
|
||||
|
||||
GHOST_SystemX11::GHOST_SystemX11() : GHOST_System(), m_xkb_descr(nullptr), m_start_time(0)
|
||||
GHOST_SystemX11::GHOST_SystemX11()
|
||||
: GHOST_System(),
|
||||
m_xkb_descr(nullptr),
|
||||
m_start_time(0),
|
||||
m_keyboard_vector{0},
|
||||
m_keycode_last_repeat_key(uint(-1))
|
||||
{
|
||||
XInitThreads();
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
|
@ -897,7 +902,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
|||
#endif /* WITH_X11_XINPUT */
|
||||
switch (xe->type) {
|
||||
case Expose: {
|
||||
XExposeEvent &xee = xe->xexpose;
|
||||
const XExposeEvent &xee = xe->xexpose;
|
||||
|
||||
if (xee.count == 0) {
|
||||
/* Only generate a single expose event
|
||||
|
@ -909,7 +914,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
|||
}
|
||||
|
||||
case MotionNotify: {
|
||||
XMotionEvent &xme = xe->xmotion;
|
||||
const XMotionEvent &xme = xe->xmotion;
|
||||
|
||||
bool is_tablet = window->GetTabletData().Active != GHOST_kTabletModeNone;
|
||||
|
||||
|
@ -1235,7 +1240,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
|||
|
||||
case ButtonPress:
|
||||
case ButtonRelease: {
|
||||
XButtonEvent &xbe = xe->xbutton;
|
||||
const XButtonEvent &xbe = xe->xbutton;
|
||||
GHOST_TButton gbmask = GHOST_kButtonMaskLeft;
|
||||
GHOST_TEventType type = (xbe.type == ButtonPress) ? GHOST_kEventButtonDown :
|
||||
GHOST_kEventButtonUp;
|
||||
|
@ -1290,14 +1295,14 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
|||
|
||||
/* change of size, border, layer etc. */
|
||||
case ConfigureNotify: {
|
||||
// XConfigureEvent & xce = xe->xconfigure;
|
||||
// const XConfigureEvent & xce = xe->xconfigure;
|
||||
g_event = new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window);
|
||||
break;
|
||||
}
|
||||
|
||||
case FocusIn:
|
||||
case FocusOut: {
|
||||
XFocusChangeEvent &xfe = xe->xfocus;
|
||||
const XFocusChangeEvent &xfe = xe->xfocus;
|
||||
|
||||
/* TODO: make sure this is the correct place for activate/deactivate */
|
||||
// printf("X: focus %s for window %d\n",
|
||||
|
@ -1385,7 +1390,7 @@ void GHOST_SystemX11::processEvent(XEvent *xe)
|
|||
* (really crossing between windows) since some window-managers
|
||||
* also send grab/un-grab crossings for mouse-wheel events.
|
||||
*/
|
||||
XCrossingEvent &xce = xe->xcrossing;
|
||||
const XCrossingEvent &xce = xe->xcrossing;
|
||||
if (xce.mode == NotifyNormal) {
|
||||
g_event = new GHOST_EventCursor(getMilliSeconds(),
|
||||
GHOST_kEventCursorMove,
|
||||
|
@ -1776,11 +1781,11 @@ bool GHOST_SystemX11::generateWindowExposeEvents()
|
|||
return anyProcessed;
|
||||
}
|
||||
|
||||
static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym keysym,
|
||||
static GHOST_TKey ghost_key_from_keysym_or_keycode(const KeySym key_sym,
|
||||
XkbDescPtr xkb_descr,
|
||||
const KeyCode keycode)
|
||||
{
|
||||
GHOST_TKey type = ghost_key_from_keysym(keysym);
|
||||
GHOST_TKey type = ghost_key_from_keysym(key_sym);
|
||||
if (type == GHOST_kKeyUnknown) {
|
||||
if (xkb_descr) {
|
||||
type = ghost_key_from_keycode(xkb_descr, keycode);
|
||||
|
@ -2376,7 +2381,7 @@ class DialogData {
|
|||
}
|
||||
|
||||
/* Is the mouse inside the given button */
|
||||
bool isInsideButton(XEvent &e, uint button_num)
|
||||
bool isInsideButton(const XEvent &e, uint button_num)
|
||||
{
|
||||
return (
|
||||
(e.xmotion.y > int(height - padding_y - button_height)) &&
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#endif
|
||||
|
||||
/* generic error handlers */
|
||||
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
|
||||
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *event);
|
||||
int GHOST_X11_ApplicationIOErrorHandler(Display *display);
|
||||
|
||||
#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \
|
||||
|
|
|
@ -21,22 +21,21 @@ GHOST_Window::GHOST_Window(uint32_t width,
|
|||
const bool wantStereoVisual,
|
||||
const bool /*exclusive*/)
|
||||
: m_drawingContextType(GHOST_kDrawingContextTypeNone),
|
||||
m_userData(nullptr),
|
||||
m_cursorVisible(true),
|
||||
m_cursorGrab(GHOST_kGrabDisable),
|
||||
m_cursorGrabAxis(GHOST_kAxisNone),
|
||||
m_cursorGrabInitPos{0, 0},
|
||||
m_cursorGrabAccumPos{0, 0},
|
||||
m_cursorShape(GHOST_kStandardCursorDefault),
|
||||
m_progressBarVisible(false),
|
||||
m_canAcceptDragOperation(false),
|
||||
m_isUnsavedChanges(false),
|
||||
m_wantStereoVisual(wantStereoVisual),
|
||||
m_nativePixelSize(1.0f),
|
||||
m_context(new GHOST_ContextNone(false))
|
||||
|
||||
{
|
||||
m_isUnsavedChanges = false;
|
||||
m_canAcceptDragOperation = false;
|
||||
|
||||
m_progressBarVisible = false;
|
||||
|
||||
m_cursorGrabAccumPos[0] = 0;
|
||||
m_cursorGrabAccumPos[1] = 0;
|
||||
|
||||
m_nativePixelSize = 1.0f;
|
||||
|
||||
m_fullScreen = state == GHOST_kWindowStateFullScreen;
|
||||
if (m_fullScreen) {
|
||||
|
|
|
@ -155,7 +155,7 @@ class GHOST_Window : public GHOST_IWindow {
|
|||
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override;
|
||||
|
||||
void getCursorGrabState(GHOST_TGrabCursorMode &mode,
|
||||
GHOST_TAxisFlag &axis_flag,
|
||||
GHOST_TAxisFlag &wrap_axis,
|
||||
GHOST_Rect &bounds,
|
||||
bool &use_software_cursor) override;
|
||||
/**
|
||||
|
|
|
@ -89,11 +89,13 @@ class GHOST_XrAction {
|
|||
const XrTime &predicted_display_time);
|
||||
void applyHapticFeedback(XrSession session,
|
||||
const char *action_name,
|
||||
const char *subaction_path,
|
||||
const char *subaction_path_str,
|
||||
const int64_t &duration,
|
||||
const float &frequency,
|
||||
const float &litude);
|
||||
void stopHapticFeedback(XrSession session, const char *action_name, const char *subaction_path);
|
||||
void stopHapticFeedback(XrSession session,
|
||||
const char *action_name,
|
||||
const char *subaction_path_str);
|
||||
|
||||
void *getCustomdata();
|
||||
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -204,6 +204,9 @@ _km_hierarchy = [
|
|||
('Grease Pencil Stroke Sculpt (Clone)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Weight Mode', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Weight (Draw)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Weight (Blur)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Weight (Average)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Weight (Smear)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Vertex Mode', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Vertex (Draw)', 'EMPTY', 'WINDOW', []),
|
||||
('Grease Pencil Stroke Vertex (Blur)', 'EMPTY', 'WINDOW', []),
|
||||
|
|
|
@ -4178,6 +4178,9 @@ def km_grease_pencil_stroke_weight_mode(params):
|
|||
# Brush size
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
|
||||
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}),
|
||||
# Brush weight
|
||||
("wm.radial_control", {"type": 'F', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.weight')]}),
|
||||
# Increase/Decrease brush size
|
||||
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
|
||||
{"properties": [("scalar", 0.9)]}),
|
||||
|
@ -4197,6 +4200,10 @@ def km_grease_pencil_stroke_weight_mode(params):
|
|||
op_menu("VIEW3D_MT_gpencil_animation", {"type": 'I', "value": 'PRESS'}),
|
||||
# Context menu
|
||||
*_template_items_context_panel("VIEW3D_PT_gpencil_weight_context_menu", params.context_menu_event),
|
||||
# Toggle Add/Subtract for weight draw tool
|
||||
("gpencil.weight_toggle_direction", {"type": 'D', "value": 'PRESS'}, None),
|
||||
# Weight sample
|
||||
("gpencil.weight_sample", {"type": params.action_mouse, "value": 'PRESS', "ctrl": True}, None),
|
||||
])
|
||||
|
||||
if params.select_mouse == 'LEFTMOUSE':
|
||||
|
@ -4220,6 +4227,59 @@ def km_grease_pencil_stroke_weight_draw(_params):
|
|||
# Draw
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_blur(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Blur)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
# Blur
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_average(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Average)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
# Average
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_smear(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Smear)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
# Smear
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
@ -8115,6 +8175,9 @@ def generate_keymaps(params=None):
|
|||
km_grease_pencil_stroke_sculpt_clone(params),
|
||||
km_grease_pencil_stroke_weight_mode(params),
|
||||
km_grease_pencil_stroke_weight_draw(params),
|
||||
km_grease_pencil_stroke_weight_blur(params),
|
||||
km_grease_pencil_stroke_weight_average(params),
|
||||
km_grease_pencil_stroke_weight_smear(params),
|
||||
km_grease_pencil_stroke_vertex_mode(params),
|
||||
km_grease_pencil_stroke_vertex_draw(params),
|
||||
km_grease_pencil_stroke_vertex_blur(params),
|
||||
|
|
|
@ -2777,6 +2777,56 @@ def km_grease_pencil_stroke_weight_draw(_params):
|
|||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_blur(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Blur)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_average(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Average)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
])
|
||||
|
||||
return keymap
|
||||
|
||||
|
||||
def km_grease_pencil_stroke_weight_smear(_params):
|
||||
items = []
|
||||
keymap = (
|
||||
"Grease Pencil Stroke Weight (Smear)",
|
||||
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
|
||||
{"items": items},
|
||||
)
|
||||
|
||||
items.extend([
|
||||
("gpencil.weight_paint", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("wait_for_input", False)]}),
|
||||
|
@ -4195,6 +4245,9 @@ def generate_keymaps_impl(params=None):
|
|||
km_grease_pencil_stroke_sculpt_clone(params),
|
||||
km_grease_pencil_stroke_weight_mode(params),
|
||||
km_grease_pencil_stroke_weight_draw(params),
|
||||
km_grease_pencil_stroke_weight_blur(params),
|
||||
km_grease_pencil_stroke_weight_average(params),
|
||||
km_grease_pencil_stroke_weight_smear(params),
|
||||
km_grease_pencil_stroke_vertex_mode(params),
|
||||
km_grease_pencil_stroke_vertex_draw(params),
|
||||
km_grease_pencil_stroke_vertex_blur(params),
|
||||
|
|
|
@ -371,10 +371,18 @@ class DATA_PT_font(CurveButtonsPanelText, Panel):
|
|||
row.prop(char, "use_small_caps", toggle=True)
|
||||
else:
|
||||
row = layout.row(align=True)
|
||||
row.operator("font.style_toggle", text="Bold", icon='BOLD' , depress = text.is_select_bold).style = 'BOLD'
|
||||
row.operator("font.style_toggle", text="Italic", icon='ITALIC' , depress = text.is_select_italic).style = 'ITALIC'
|
||||
row.operator("font.style_toggle", text="Underline", icon='UNDERLINE' , depress = text.is_select_underline).style = 'UNDERLINE'
|
||||
row.operator("font.style_toggle", text="Small Caps", icon='SMALL_CAPS' , depress = text.is_select_smallcaps).style = 'SMALL_CAPS'
|
||||
row.operator(
|
||||
"font.style_toggle", text="Bold", icon='BOLD', depress=text.is_select_bold,
|
||||
).style = 'BOLD'
|
||||
row.operator(
|
||||
"font.style_toggle", text="Italic", icon='ITALIC', depress=text.is_select_italic,
|
||||
).style = 'ITALIC'
|
||||
row.operator(
|
||||
"font.style_toggle", text="Underline", icon='UNDERLINE', depress=text.is_select_underline,
|
||||
).style = 'UNDERLINE'
|
||||
row.operator(
|
||||
"font.style_toggle", text="Small Caps", icon='SMALL_CAPS', depress=text.is_select_smallcaps,
|
||||
).style = 'SMALL_CAPS'
|
||||
|
||||
|
||||
class DATA_PT_font_transform(CurveButtonsPanelText, Panel):
|
||||
|
|
|
@ -1415,7 +1415,11 @@ def brush_basic_gpencil_weight_settings(layout, _context, brush, *, compact=Fals
|
|||
row.prop(brush, "strength", slider=True)
|
||||
row.prop(brush, "use_pressure_strength", text="")
|
||||
|
||||
layout.prop(brush, "weight", slider=True)
|
||||
if brush.gpencil_weight_tool in {'WEIGHT'}:
|
||||
layout.prop(brush, "weight", slider=True)
|
||||
|
||||
gp_settings = brush.gpencil_settings
|
||||
layout.prop(gp_settings, "direction", expand=True, text="" if compact else "Direction")
|
||||
|
||||
|
||||
def brush_basic_gpencil_vertex_settings(layout, _context, brush, *, compact=False):
|
||||
|
|
|
@ -903,7 +903,10 @@ class NodeTreeInterfacePanel(Panel):
|
|||
props = property_row.operator_menu_enum(
|
||||
"node.tree_socket_change_subtype",
|
||||
"socket_subtype",
|
||||
text=active_socket.bl_subtype_label if active_socket.bl_subtype_label else active_socket.bl_idname
|
||||
text=(
|
||||
active_socket.bl_subtype_label if active_socket.bl_subtype_label else
|
||||
active_socket.bl_idname
|
||||
),
|
||||
)
|
||||
|
||||
layout.use_property_split = True
|
||||
|
|
|
@ -68,6 +68,7 @@ def generate_from_enum_ex(
|
|||
dict(
|
||||
idname=idname_prefix + name,
|
||||
label=name,
|
||||
description=enum.description,
|
||||
icon=icon,
|
||||
cursor=cursor,
|
||||
data_block=idname,
|
||||
|
|
|
@ -8,6 +8,7 @@ from bpy.types import (
|
|||
from bl_ui.properties_paint_common import (
|
||||
UnifiedPaintPanel,
|
||||
brush_basic_texpaint_settings,
|
||||
brush_basic_gpencil_weight_settings,
|
||||
)
|
||||
from bl_ui.properties_grease_pencil_common import (
|
||||
AnnotationDataPanel,
|
||||
|
@ -414,11 +415,13 @@ class _draw_tool_settings_context_mode:
|
|||
paint = context.tool_settings.gpencil_weight_paint
|
||||
brush = paint.brush
|
||||
|
||||
from bl_ui.properties_paint_common import (
|
||||
brush_basic_gpencil_weight_settings,
|
||||
)
|
||||
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
|
||||
|
||||
brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
|
||||
|
||||
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_options", text="Options")
|
||||
layout.popover("VIEW3D_PT_tools_grease_pencil_brush_weight_falloff", text="Falloff")
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
|
@ -7662,12 +7665,10 @@ class VIEW3D_PT_gpencil_weight_context_menu(Panel):
|
|||
tool_settings = context.tool_settings
|
||||
settings = tool_settings.gpencil_weight_paint
|
||||
brush = settings.brush
|
||||
|
||||
layout = self.layout
|
||||
|
||||
layout.prop(brush, "size", slider=True)
|
||||
layout.prop(brush, "strength")
|
||||
layout.prop(brush, "weight")
|
||||
# Weight settings
|
||||
brush_basic_gpencil_weight_settings(layout, context, brush)
|
||||
|
||||
# Layers
|
||||
draw_gpencil_layer_active(context, layout)
|
||||
|
|
|
@ -2021,6 +2021,9 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr
|
|||
bl_label = "Brush Settings"
|
||||
|
||||
def draw(self, context):
|
||||
if self.is_popover:
|
||||
return
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
|
@ -2029,15 +2032,15 @@ class VIEW3D_PT_tools_grease_pencil_weight_paint_settings(Panel, View3DPanel, Gr
|
|||
settings = tool_settings.gpencil_weight_paint
|
||||
brush = settings.brush
|
||||
|
||||
if not self.is_popover:
|
||||
from bl_ui.properties_paint_common import (
|
||||
brush_basic_gpencil_weight_settings,
|
||||
)
|
||||
brush_basic_gpencil_weight_settings(layout, context, brush)
|
||||
from bl_ui.properties_paint_common import (
|
||||
brush_basic_gpencil_weight_settings,
|
||||
)
|
||||
brush_basic_gpencil_weight_settings(layout, context, brush)
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFalloff, Panel, View3DPaintPanel):
|
||||
bl_context = ".greasepencil_weight"
|
||||
bl_parent_id = 'VIEW3D_PT_tools_grease_pencil_weight_paint_settings'
|
||||
bl_label = "Falloff"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
|
@ -2049,6 +2052,20 @@ class VIEW3D_PT_tools_grease_pencil_brush_weight_falloff(GreasePencilBrushFallof
|
|||
return (brush and brush.curve)
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_grease_pencil_weight_options(Panel, View3DPanel, GreasePencilWeightPanel):
|
||||
bl_label = "Options"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.use_property_decorate = False
|
||||
tool_settings = context.scene.tool_settings
|
||||
|
||||
col = layout.column()
|
||||
col.prop(tool_settings, "use_auto_normalize", text="Auto Normalize")
|
||||
|
||||
|
||||
# Grease Pencil vertex painting tools
|
||||
class GreasePencilVertexPanel:
|
||||
bl_context = ".greasepencil_vertex"
|
||||
|
@ -2425,6 +2442,7 @@ classes = (
|
|||
VIEW3D_PT_tools_grease_pencil_sculpt_appearance,
|
||||
VIEW3D_PT_tools_grease_pencil_weight_paint_select,
|
||||
VIEW3D_PT_tools_grease_pencil_weight_paint_settings,
|
||||
VIEW3D_PT_tools_grease_pencil_weight_options,
|
||||
VIEW3D_PT_tools_grease_pencil_weight_appearance,
|
||||
VIEW3D_PT_tools_grease_pencil_vertex_paint_select,
|
||||
VIEW3D_PT_tools_grease_pencil_vertex_paint_settings,
|
||||
|
|
|
@ -260,6 +260,7 @@ void AssetCatalogService::update_catalog_path(const CatalogID catalog_id,
|
|||
}
|
||||
cat->path = new_path;
|
||||
cat->simple_name_refresh();
|
||||
this->tag_has_unsaved_changes(cat);
|
||||
|
||||
/* TODO(Sybren): go over all assets that are assigned to this catalog, defined in the current
|
||||
* blend file, and update the catalog simple name stored there. */
|
||||
|
|
|
@ -55,7 +55,7 @@ struct BasisCache {
|
|||
class CurvesGeometryRuntime {
|
||||
public:
|
||||
/** Implicit sharing user count for #CurvesGeometry::curve_offsets. */
|
||||
ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
|
||||
const ImplicitSharingInfo *curve_offsets_sharing_info = nullptr;
|
||||
|
||||
/**
|
||||
* The cached number of curves with each type. Unlike other caches here, this is not computed
|
||||
|
|
|
@ -98,7 +98,7 @@ struct MeshRuntime {
|
|||
std::mutex render_mutex;
|
||||
|
||||
/** Implicit sharing user count for #Mesh::poly_offset_indices. */
|
||||
ImplicitSharingInfoHandle *poly_offsets_sharing_info;
|
||||
const ImplicitSharingInfoHandle *poly_offsets_sharing_info;
|
||||
|
||||
/**
|
||||
* A cache of bounds shared between data-blocks with unchanged positions. When changing positions
|
||||
|
|
|
@ -569,6 +569,27 @@ static Mesh *modifier_modify_mesh_and_geometry_set(ModifierData *md,
|
|||
return mesh_output;
|
||||
}
|
||||
|
||||
static void set_rest_position(Mesh &mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
const AttributeReader positions = attributes.lookup<float3>("position");
|
||||
attributes.remove("rest_position");
|
||||
if (positions) {
|
||||
if (positions.sharing_info && positions.varray.is_span()) {
|
||||
attributes.add<float3>("rest_position",
|
||||
ATTR_DOMAIN_POINT,
|
||||
AttributeInitShared(positions.varray.get_internal_span().data(),
|
||||
*positions.sharing_info));
|
||||
}
|
||||
else {
|
||||
attributes.add<float3>(
|
||||
"rest_position", ATTR_DOMAIN_POINT, AttributeInitVArray(positions.varray));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
|
||||
const Scene *scene,
|
||||
Object *ob,
|
||||
|
@ -657,20 +678,7 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
|
|||
mesh_final = BKE_mesh_copy_for_eval(mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
}
|
||||
MutableAttributeAccessor attributes = mesh_final->attributes_for_write();
|
||||
const AttributeReader positions = attributes.lookup<float3>("position");
|
||||
if (positions) {
|
||||
if (positions.sharing_info && positions.varray.is_span()) {
|
||||
attributes.add<float3>("rest_position",
|
||||
ATTR_DOMAIN_POINT,
|
||||
AttributeInitShared(positions.varray.get_internal_span().data(),
|
||||
*positions.sharing_info));
|
||||
}
|
||||
else {
|
||||
attributes.add<float3>(
|
||||
"rest_position", ATTR_DOMAIN_POINT, AttributeInitVArray(positions.varray));
|
||||
}
|
||||
}
|
||||
set_rest_position(*mesh_final);
|
||||
}
|
||||
|
||||
/* Apply all leading deform modifiers. */
|
||||
|
@ -1194,6 +1202,14 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
|
|||
/* Clear errors before evaluation. */
|
||||
BKE_modifiers_clear_errors(ob);
|
||||
|
||||
if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
|
||||
if (mesh_final == nullptr) {
|
||||
mesh_final = BKE_mesh_from_bmesh_for_eval_nomain(em_input->bm, nullptr, mesh_input);
|
||||
ASSERT_IS_VALID_MESH(mesh_final);
|
||||
}
|
||||
set_rest_position(*mesh_final);
|
||||
}
|
||||
|
||||
for (int i = 0; md; i++, md = md->next, md_datamask = md_datamask->next) {
|
||||
const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md->type);
|
||||
|
||||
|
|
|
@ -1276,14 +1276,57 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type)
|
|||
|
||||
break;
|
||||
}
|
||||
case GP_BRUSH_PRESET_DRAW_WEIGHT: {
|
||||
case GP_BRUSH_PRESET_WEIGHT_DRAW: {
|
||||
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_GPBRUSH_WEIGHT;
|
||||
brush->gpencil_weight_tool = GPWEIGHT_TOOL_DRAW;
|
||||
|
||||
brush->size = 25.0f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
|
||||
|
||||
brush->gpencil_settings->draw_strength = 0.8f;
|
||||
brush->alpha = 0.3f;
|
||||
brush->gpencil_settings->draw_strength = 0.3f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE;
|
||||
brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION;
|
||||
|
||||
break;
|
||||
}
|
||||
case GP_BRUSH_PRESET_WEIGHT_BLUR: {
|
||||
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR;
|
||||
brush->gpencil_weight_tool = GPWEIGHT_TOOL_BLUR;
|
||||
|
||||
brush->size = 50.0f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
|
||||
|
||||
brush->alpha = 0.3f;
|
||||
brush->gpencil_settings->draw_strength = 0.3f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE;
|
||||
brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION;
|
||||
|
||||
break;
|
||||
}
|
||||
case GP_BRUSH_PRESET_WEIGHT_AVERAGE: {
|
||||
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR;
|
||||
brush->gpencil_weight_tool = GPWEIGHT_TOOL_AVERAGE;
|
||||
|
||||
brush->size = 50.0f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
|
||||
|
||||
brush->alpha = 0.3f;
|
||||
brush->gpencil_settings->draw_strength = 0.3f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE;
|
||||
brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION;
|
||||
|
||||
break;
|
||||
}
|
||||
case GP_BRUSH_PRESET_WEIGHT_SMEAR: {
|
||||
brush->gpencil_settings->icon_id = GP_BRUSH_ICON_VERTEX_BLUR;
|
||||
brush->gpencil_weight_tool = GPWEIGHT_TOOL_SMEAR;
|
||||
|
||||
brush->size = 50.0f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE;
|
||||
|
||||
brush->alpha = 0.3f;
|
||||
brush->gpencil_settings->draw_strength = 0.3f;
|
||||
brush->gpencil_settings->flag |= GP_BRUSH_USE_STRENGTH_PRESSURE;
|
||||
brush->gpencil_settings->sculpt_mode_flag |= GP_SCULPT_FLAGMODE_APPLY_POSITION;
|
||||
|
||||
|
@ -1569,13 +1612,32 @@ void BKE_brush_gpencil_weight_presets(Main *bmain, ToolSettings *ts, const bool
|
|||
Paint *weightpaint = &ts->gp_weightpaint->paint;
|
||||
Brush *brush_prev = weightpaint->brush;
|
||||
Brush *brush, *deft_weight;
|
||||
/* Vertex Draw brush. */
|
||||
brush = gpencil_brush_ensure(bmain, ts, "Draw Weight", OB_MODE_WEIGHT_GPENCIL, &r_new);
|
||||
|
||||
/* Weight Draw brush. */
|
||||
brush = gpencil_brush_ensure(bmain, ts, "Weight Draw", OB_MODE_WEIGHT_GPENCIL, &r_new);
|
||||
if ((reset) || (r_new)) {
|
||||
BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_DRAW_WEIGHT);
|
||||
BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_DRAW);
|
||||
}
|
||||
deft_weight = brush; /* save default brush. */
|
||||
|
||||
/* Weight Blur brush. */
|
||||
brush = gpencil_brush_ensure(bmain, ts, "Weight Blur", OB_MODE_WEIGHT_GPENCIL, &r_new);
|
||||
if ((reset) || (r_new)) {
|
||||
BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_BLUR);
|
||||
}
|
||||
|
||||
/* Weight Average brush. */
|
||||
brush = gpencil_brush_ensure(bmain, ts, "Weight Average", OB_MODE_WEIGHT_GPENCIL, &r_new);
|
||||
if ((reset) || (r_new)) {
|
||||
BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_AVERAGE);
|
||||
}
|
||||
|
||||
/* Weight Smear brush. */
|
||||
brush = gpencil_brush_ensure(bmain, ts, "Weight Smear", OB_MODE_WEIGHT_GPENCIL, &r_new);
|
||||
if ((reset) || (r_new)) {
|
||||
BKE_gpencil_brush_preset_set(bmain, brush, GP_BRUSH_PRESET_WEIGHT_SMEAR);
|
||||
}
|
||||
|
||||
/* Set default brush. */
|
||||
if (reset || brush_prev == nullptr) {
|
||||
BKE_paint_brush_set(weightpaint, deft_weight);
|
||||
|
|
|
@ -2383,9 +2383,9 @@ class CustomDataLayerImplicitSharing : public ImplicitSharingInfo {
|
|||
};
|
||||
|
||||
/** Create a #ImplicitSharingInfo that takes ownership of the data. */
|
||||
static ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
|
||||
const void *data,
|
||||
const int totelem)
|
||||
static const ImplicitSharingInfo *make_implicit_sharing_info_for_layer(const eCustomDataType type,
|
||||
const void *data,
|
||||
const int totelem)
|
||||
{
|
||||
return MEM_new<CustomDataLayerImplicitSharing>(__func__, data, totelem, type);
|
||||
}
|
||||
|
|
|
@ -431,7 +431,9 @@ CDataFileLayer *cdf_layer_add(CDataFile *cdf, int type, const char *name, size_t
|
|||
|
||||
/* expand array */
|
||||
newlayer = MEM_calloc_arrayN((cdf->totlayer + 1), sizeof(CDataFileLayer), "CDataFileLayer");
|
||||
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
|
||||
if (cdf->totlayer > 0) {
|
||||
memcpy(newlayer, cdf->layer, sizeof(CDataFileLayer) * cdf->totlayer);
|
||||
}
|
||||
cdf->layer = newlayer;
|
||||
|
||||
cdf->totlayer++;
|
||||
|
|
|
@ -63,20 +63,10 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span<int> corner_vert
|
|||
MLoopTri *mlt_a = mlt++;
|
||||
create_tri(0, 2, 3);
|
||||
MLoopTri *mlt_b = mlt;
|
||||
|
||||
if (UNLIKELY(face_normal ? is_quad_flip_v3_first_third_fast_with_normal(
|
||||
/* Simpler calculation (using the normal). */
|
||||
positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]],
|
||||
normal_precalc) :
|
||||
is_quad_flip_v3_first_third_fast(
|
||||
/* Expensive calculation (no normal). */
|
||||
positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]]))) {
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast(positions[corner_verts[mlt_a->tri[0]]],
|
||||
positions[corner_verts[mlt_a->tri[1]]],
|
||||
positions[corner_verts[mlt_a->tri[2]]],
|
||||
positions[corner_verts[mlt_b->tri[2]]]))) {
|
||||
/* Flip out of degenerate 0-2 state. */
|
||||
mlt_a->tri[2] = mlt_b->tri[2];
|
||||
mlt_b->tri[0] = mlt_a->tri[1];
|
||||
|
|
|
@ -66,6 +66,11 @@ class BitArrayVector {
|
|||
return aligned_group_size_ == 0 ? 0 : data_.size() / aligned_group_size_;
|
||||
}
|
||||
|
||||
int64_t group_size() const
|
||||
{
|
||||
return group_size_;
|
||||
}
|
||||
|
||||
IndexRange index_range() const
|
||||
{
|
||||
return IndexRange{this->size()};
|
||||
|
|
|
@ -326,6 +326,21 @@ class MutableBoundedBitSpan : public MutableBitSpan {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This is overloaded in BLI_bit_vector.hh. The purpose is to make passing #BitVector into bit span
|
||||
* operations more simpler and efficient (interpreting it as `BoundedBitSpan` instead of just
|
||||
* `BitSpan`).
|
||||
*/
|
||||
template<typename T> inline T to_best_bit_span(const T &data)
|
||||
{
|
||||
static_assert(is_same_any_v<std::decay_t<T>,
|
||||
BitSpan,
|
||||
MutableBitSpan,
|
||||
BoundedBitSpan,
|
||||
MutableBoundedBitSpan>);
|
||||
return data;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
constexpr bool all_bounded_spans =
|
||||
(is_same_any_v<std::decay_t<Args>, BoundedBitSpan, MutableBoundedBitSpan> && ...);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
namespace blender::bits {
|
||||
|
||||
namespace detail {
|
||||
/**
|
||||
* Evaluates the expression on one or more bit spans and stores the result in the first.
|
||||
*
|
||||
|
@ -92,7 +93,7 @@ inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const Bi
|
|||
/* Fallback or arbitrary bit spans. This could be implemented more efficiently but adds more
|
||||
* complexity and is not necessary yet. */
|
||||
for (const int64_t i : IndexRange(size)) {
|
||||
const BitInt result = fn(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
|
||||
const BitInt result = expr(BitInt(first_arg[i].test()), BitInt(args[i].test())...);
|
||||
if (result != 0) {
|
||||
return true;
|
||||
}
|
||||
|
@ -137,7 +138,7 @@ inline void foreach_1_index_expr(ExprFn &&expr,
|
|||
if (const int64_t final_bits = first_arg.final_bits_num()) {
|
||||
BitInt tmp = expr(first_data[full_ints_num] >> first_arg.offset(),
|
||||
(*args.data()[full_ints_num] >> args.offset())...) &
|
||||
mask_first_n_bits(size);
|
||||
mask_first_n_bits(final_bits);
|
||||
const int64_t offset = full_ints_num << BitToIntIndexShift;
|
||||
while (tmp != 0) {
|
||||
const int index = bitscan_forward_uint64(tmp);
|
||||
|
@ -158,6 +159,32 @@ inline void foreach_1_index_expr(ExprFn &&expr,
|
|||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
|
||||
inline void mix_into_first_expr(ExprFn &&expr,
|
||||
const FirstBitSpanT &first_arg,
|
||||
const BitSpanT &...args)
|
||||
{
|
||||
detail::mix_into_first_expr(expr, to_best_bit_span(first_arg), to_best_bit_span(args)...);
|
||||
}
|
||||
|
||||
template<typename ExprFn, typename FirstBitSpanT, typename... BitSpanT>
|
||||
inline bool any_set_expr(ExprFn &&expr, const FirstBitSpanT &first_arg, const BitSpanT &...args)
|
||||
{
|
||||
return detail::any_set_expr(expr, to_best_bit_span(first_arg), to_best_bit_span(args)...);
|
||||
}
|
||||
|
||||
template<typename ExprFn, typename HandleFn, typename FirstBitSpanT, typename... BitSpanT>
|
||||
inline void foreach_1_index_expr(ExprFn &&expr,
|
||||
HandleFn &&handle,
|
||||
const FirstBitSpanT &first_arg,
|
||||
const BitSpanT &...args)
|
||||
{
|
||||
detail::foreach_1_index_expr(
|
||||
expr, handle, to_best_bit_span(first_arg), to_best_bit_span(args)...);
|
||||
}
|
||||
|
||||
template<typename FirstBitSpanT, typename... BitSpanT>
|
||||
inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
|
||||
{
|
||||
|
|
|
@ -170,12 +170,12 @@ class BitVector {
|
|||
return move_assign_container(*this, std::move(other));
|
||||
}
|
||||
|
||||
operator BitSpan() const
|
||||
operator BoundedBitSpan() const
|
||||
{
|
||||
return {data_, IndexRange(size_in_bits_)};
|
||||
}
|
||||
|
||||
operator MutableBitSpan()
|
||||
operator MutableBoundedBitSpan()
|
||||
{
|
||||
return {data_, IndexRange(size_in_bits_)};
|
||||
}
|
||||
|
@ -367,6 +367,18 @@ class BitVector {
|
|||
}
|
||||
};
|
||||
|
||||
template<int64_t InlineBufferCapacity, typename Allocator>
|
||||
inline BoundedBitSpan to_best_bit_span(const BitVector<InlineBufferCapacity, Allocator> &data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
template<int64_t InlineBufferCapacity, typename Allocator>
|
||||
inline MutableBoundedBitSpan to_best_bit_span(BitVector<InlineBufferCapacity, Allocator> &data)
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
} // namespace blender::bits
|
||||
|
||||
namespace blender {
|
||||
|
|
|
@ -198,11 +198,11 @@ void *resize_trivial_array_impl(void *old_data,
|
|||
int64_t old_size,
|
||||
int64_t new_size,
|
||||
int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info);
|
||||
const ImplicitSharingInfo **sharing_info);
|
||||
void *make_trivial_data_mutable_impl(void *old_data,
|
||||
int64_t size,
|
||||
int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info);
|
||||
const ImplicitSharingInfo **sharing_info);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
|
@ -212,9 +212,9 @@ void *make_trivial_data_mutable_impl(void *old_data,
|
|||
*/
|
||||
template<typename T>
|
||||
void copy_shared_pointer(T *src_ptr,
|
||||
ImplicitSharingInfo *src_sharing_info,
|
||||
const ImplicitSharingInfo *src_sharing_info,
|
||||
T **r_dst_ptr,
|
||||
ImplicitSharingInfo **r_dst_sharing_info)
|
||||
const ImplicitSharingInfo **r_dst_sharing_info)
|
||||
{
|
||||
*r_dst_ptr = src_ptr;
|
||||
*r_dst_sharing_info = src_sharing_info;
|
||||
|
@ -227,7 +227,7 @@ void copy_shared_pointer(T *src_ptr,
|
|||
/**
|
||||
* Remove this reference to the shared data and remove dangling pointers.
|
||||
*/
|
||||
template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **sharing_info)
|
||||
template<typename T> void free_shared_data(T **data, const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (*sharing_info) {
|
||||
BLI_assert(*data != nullptr);
|
||||
|
@ -241,13 +241,15 @@ template<typename T> void free_shared_data(T **data, ImplicitSharingInfo **shari
|
|||
* Create an implicit sharing object that takes ownership of the data, allowing it to be shared.
|
||||
* When it is no longer used, the data is freed with #MEM_freeN, so it must be a trivial type.
|
||||
*/
|
||||
ImplicitSharingInfo *info_for_mem_free(void *data);
|
||||
const ImplicitSharingInfo *info_for_mem_free(void *data);
|
||||
|
||||
/**
|
||||
* Make data mutable (single-user) if it is shared. For trivially-copyable data only.
|
||||
*/
|
||||
template<typename T>
|
||||
void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, const int64_t size)
|
||||
void make_trivial_data_mutable(T **data,
|
||||
const ImplicitSharingInfo **sharing_info,
|
||||
const int64_t size)
|
||||
{
|
||||
*data = static_cast<T *>(
|
||||
detail::make_trivial_data_mutable_impl(*data, sizeof(T) * size, alignof(T), sharing_info));
|
||||
|
@ -259,7 +261,7 @@ void make_trivial_data_mutable(T **data, ImplicitSharingInfo **sharing_info, con
|
|||
*/
|
||||
template<typename T>
|
||||
void resize_trivial_array(T **data,
|
||||
ImplicitSharingInfo **sharing_info,
|
||||
const ImplicitSharingInfo **sharing_info,
|
||||
int64_t old_size,
|
||||
int64_t new_size)
|
||||
{
|
||||
|
|
|
@ -145,11 +145,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
|||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3]);
|
||||
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3],
|
||||
const float normal[3]);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class MEMFreeImplicitSharing : public ImplicitSharingInfo {
|
|||
}
|
||||
};
|
||||
|
||||
ImplicitSharingInfo *info_for_mem_free(void *data)
|
||||
const ImplicitSharingInfo *info_for_mem_free(void *data)
|
||||
{
|
||||
return MEM_new<MEMFreeImplicitSharing>(__func__, data);
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace detail {
|
|||
void *make_trivial_data_mutable_impl(void *old_data,
|
||||
const int64_t size,
|
||||
const int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info)
|
||||
const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (!old_data) {
|
||||
BLI_assert(size == 0);
|
||||
|
@ -62,7 +62,7 @@ void *resize_trivial_array_impl(void *old_data,
|
|||
const int64_t old_size,
|
||||
const int64_t new_size,
|
||||
const int64_t alignment,
|
||||
ImplicitSharingInfo **sharing_info)
|
||||
const ImplicitSharingInfo **sharing_info)
|
||||
{
|
||||
if (new_size == 0) {
|
||||
if (*sharing_info) {
|
||||
|
@ -82,7 +82,8 @@ void *resize_trivial_array_impl(void *old_data,
|
|||
|
||||
BLI_assert(old_size != 0);
|
||||
if ((*sharing_info)->is_mutable()) {
|
||||
if (auto *info = dynamic_cast<MEMFreeImplicitSharing *>(*sharing_info)) {
|
||||
if (auto *info = const_cast<MEMFreeImplicitSharing *>(
|
||||
dynamic_cast<const MEMFreeImplicitSharing *>(*sharing_info))) {
|
||||
/* If the array was allocated with the MEM allocator, we can use realloc directly, which
|
||||
* could theoretically give better performance if the data can be reused in place. */
|
||||
void *new_data = static_cast<int *>(MEM_reallocN(old_data, new_size));
|
||||
|
|
|
@ -5889,6 +5889,9 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
|||
const float v3[3],
|
||||
const float v4[3])
|
||||
{
|
||||
/* NOTE: if the faces normal has been calculated it's possible to simplify the following checks,
|
||||
* however this means the solution may be different depending on the existence of normals
|
||||
* causing tessellation to be "unstable" depending on the existence of normals, see #106469. */
|
||||
float d_12[3], d_13[3], d_14[3];
|
||||
float cross_a[3], cross_b[3];
|
||||
sub_v3_v3v3(d_12, v2, v1);
|
||||
|
@ -5899,19 +5902,6 @@ bool is_quad_flip_v3_first_third_fast(const float v1[3],
|
|||
return dot_v3v3(cross_a, cross_b) > 0.0f;
|
||||
}
|
||||
|
||||
bool is_quad_flip_v3_first_third_fast_with_normal(const float v1[3],
|
||||
const float v2[3],
|
||||
const float v3[3],
|
||||
const float v4[3],
|
||||
const float normal[3])
|
||||
{
|
||||
float dir_v3v1[3], tangent[3];
|
||||
sub_v3_v3v3(dir_v3v1, v3, v1);
|
||||
cross_v3_v3v3(tangent, dir_v3v1, normal);
|
||||
const float dot = dot_v3v3(v1, tangent);
|
||||
return (dot_v3v3(v4, tangent) >= dot) || (dot_v3v3(v2, tangent) <= dot);
|
||||
}
|
||||
|
||||
float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3])
|
||||
{
|
||||
BLI_ASSERT_UNIT_V3(tan_l);
|
||||
|
|
|
@ -2728,7 +2728,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
|
|||
e[k + 1] += 1.0f;
|
||||
}
|
||||
e[k] = -e[k];
|
||||
if ((k + 1 < m) & (e[k] != 0.0f)) {
|
||||
if ((k + 1 < m) && (e[k] != 0.0f)) {
|
||||
float invek1;
|
||||
|
||||
/* Apply the transformation. */
|
||||
|
@ -2812,7 +2812,7 @@ void svd_m4(float U[4][4], float s[4], float V[4][4], float A_[4][4])
|
|||
/* If required, generate V. */
|
||||
|
||||
for (k = n - 1; k >= 0; k--) {
|
||||
if ((k < nrt) & (e[k] != 0.0f)) {
|
||||
if ((k < nrt) && (e[k] != 0.0f)) {
|
||||
for (j = k + 1; j < nu; j++) {
|
||||
float t = 0;
|
||||
for (i = k + 1; i < n; i++) {
|
||||
|
|
|
@ -1962,17 +1962,19 @@ static Face *cdt_tri_as_imesh_face(
|
|||
return facep;
|
||||
}
|
||||
|
||||
/* Like BLI_math's is_quad_flip_v3_first_third_fast_with_normal, with const double3's. */
|
||||
/* Like BLI_math's is_quad_flip_v3_first_third_fast, with const double3's. */
|
||||
static bool is_quad_flip_first_third(const double3 &v1,
|
||||
const double3 &v2,
|
||||
const double3 &v3,
|
||||
const double3 &v4,
|
||||
const double3 &normal)
|
||||
const double3 &v4)
|
||||
{
|
||||
double3 dir_v3v1 = v3 - v1;
|
||||
double3 tangent = math::cross(dir_v3v1, normal);
|
||||
double dot = math::dot(v1, tangent);
|
||||
return (math::dot(v4, tangent) >= dot) || (math::dot(v2, tangent) <= dot);
|
||||
const double3 d_12 = v2 - v1;
|
||||
const double3 d_13 = v3 - v1;
|
||||
const double3 d_14 = v4 - v1;
|
||||
|
||||
const double3 cross_a = math::cross(d_12, d_13);
|
||||
const double3 cross_b = math::cross(d_14, d_13);
|
||||
return math::dot(cross_a, cross_b) > 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2008,7 +2010,7 @@ static Array<Face *> polyfill_triangulate_poly(Face *f, IMeshArena *arena)
|
|||
int eo_23 = f->edge_orig[2];
|
||||
int eo_30 = f->edge_orig[3];
|
||||
Face *f0, *f1;
|
||||
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co, f->plane->norm))) {
|
||||
if (UNLIKELY(is_quad_flip_first_third(v0->co, v1->co, v2->co, v3->co))) {
|
||||
f0 = arena->add_face({v0, v1, v3}, f->orig, {eo_01, -1, eo_30}, {false, false, false});
|
||||
f1 = arena->add_face({v1, v2, v3}, f->orig, {eo_12, eo_23, -1}, {false, false, false});
|
||||
}
|
||||
|
|
|
@ -37,22 +37,16 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* Declarations */
|
||||
/* Declarations. */
|
||||
|
||||
static int BLI_path_unc_prefix_len(const char *path);
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/**
|
||||
* Return true if the path is absolute ie starts with a drive specifier
|
||||
* (eg A:\) or is a UNC path.
|
||||
*/
|
||||
static bool BLI_path_is_abs(const char *name);
|
||||
|
||||
static bool BLI_path_is_abs_win32(const char *name);
|
||||
#endif /* WIN32 */
|
||||
|
||||
// #define DEBUG_STRSIZE
|
||||
|
||||
/* implementation */
|
||||
|
||||
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
|
||||
{
|
||||
uint nums = 0, nume = 0;
|
||||
|
@ -102,9 +96,8 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
|
|||
strcpy(tail, string + name_end);
|
||||
}
|
||||
if (head) {
|
||||
/* name_end points to last character of head,
|
||||
* make it +1 so null-terminator is nicely placed
|
||||
*/
|
||||
/* Name_end points to last character of head,
|
||||
* make it +1 so null-terminator is nicely placed. */
|
||||
BLI_strncpy(head, string, name_end + 1);
|
||||
}
|
||||
if (r_digits_len) {
|
||||
|
@ -119,8 +112,6 @@ void BLI_path_sequence_encode(
|
|||
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
|
||||
}
|
||||
|
||||
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
|
||||
|
||||
void BLI_path_normalize(const char *relabase, char *path)
|
||||
{
|
||||
ptrdiff_t a;
|
||||
|
@ -131,19 +122,18 @@ void BLI_path_normalize(const char *relabase, char *path)
|
|||
else {
|
||||
if (path[0] == '/' && path[1] == '/') {
|
||||
if (path[2] == '\0') {
|
||||
return; /* path is "//" - can't clean it */
|
||||
return; /* Path is `//` - can't clean it. */
|
||||
}
|
||||
path = path + 2; /* leave the initial "//" untouched */
|
||||
path = path + 2; /* Leave the initial `//` untouched. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Note
|
||||
* memmove(start, eind, strlen(eind) + 1);
|
||||
/* NOTE(@ideasman42):
|
||||
* `memmove(start, eind, strlen(eind) + 1);`
|
||||
* is the same as
|
||||
* strcpy(start, eind);
|
||||
* except strcpy should not be used because there is overlap,
|
||||
* so use memmove's slightly more obscure syntax - Campbell
|
||||
*/
|
||||
* `strcpy(start, eind);`
|
||||
* except `strcpy` should not be used because there is overlap,
|
||||
* so use `memmove` 's slightly more obscure syntax. */
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
@ -152,8 +142,8 @@ void BLI_path_normalize(const char *relabase, char *path)
|
|||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
/* remove two consecutive backslashes, but skip the UNC prefix,
|
||||
* which needs to be preserved */
|
||||
/* Remove two consecutive backslashes, but skip the UNC prefix,
|
||||
* which needs to be preserved. */
|
||||
while ((start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\"))) {
|
||||
eind = start + strlen("\\\\") - 1;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
|
@ -179,21 +169,21 @@ void BLI_path_normalize(const char *relabase, char *path)
|
|||
#else
|
||||
|
||||
while ((start = strstr(path, "/./"))) {
|
||||
eind = start + (3 - 1) /* strlen("/./") - 1 */;
|
||||
eind = start + (3 - 1) /* `strlen("/./") - 1` */;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
while ((start = strstr(path, "//"))) {
|
||||
eind = start + (2 - 1) /* strlen("//") - 1 */;
|
||||
eind = start + (2 - 1) /* `strlen("//") - 1` */;
|
||||
memmove(start, eind, strlen(eind) + 1);
|
||||
}
|
||||
|
||||
while ((start = strstr(path, "/../"))) {
|
||||
a = start - path - 1;
|
||||
if (a > 0) {
|
||||
/* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
|
||||
eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
|
||||
while (a > 0 && path[a] != '/') { /* find start of <parent> */
|
||||
/* `<prefix>/<parent>/../<postfix> => <prefix>/<postfix>`. */
|
||||
eind = start + (4 - 1) /* `strlen("/../") - 1` */; /* Strip "/.." and keep last "/". */
|
||||
while (a > 0 && path[a] != '/') { /* Find start of `<parent>`. */
|
||||
a--;
|
||||
}
|
||||
memmove(path + a, eind, strlen(eind) + 1);
|
||||
|
@ -253,7 +243,7 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
|
|||
|
||||
/* Forbid only dots. */
|
||||
for (fn = fname; *fn == '.'; fn++) {
|
||||
/* pass */
|
||||
/* Pass. */
|
||||
}
|
||||
if (*fn == '\0') {
|
||||
*fname = '_';
|
||||
|
@ -279,15 +269,14 @@ bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens)
|
|||
|
||||
/* Check for forbidden names - not we have to check all combination
|
||||
* of upper and lower cases, hence the usage of lower_fname
|
||||
* (more efficient than using BLI_strcasestr repeatedly). */
|
||||
* (more efficient than using #BLI_strcasestr repeatedly). */
|
||||
BLI_str_tolower_ascii(lower_fname, len);
|
||||
for (iname = invalid_names; *iname; iname++) {
|
||||
if (strstr(lower_fname, *iname) == lower_fname) {
|
||||
const size_t iname_len = strlen(*iname);
|
||||
/* Only invalid if the whole name is made of the invalid chunk, or it has an
|
||||
* (assumed extension) dot just after. This means it will also catch 'valid'
|
||||
* names like 'aux.foo.bar', but should be
|
||||
* good enough for us! */
|
||||
* (assumed extension) dot just after. This means it will also catch *valid*
|
||||
* names like `aux.foo.bar`, but should be good enough for us! */
|
||||
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
|
||||
*fname = '_';
|
||||
changed = true;
|
||||
|
@ -311,14 +300,14 @@ bool BLI_filename_make_safe(char *fname)
|
|||
bool BLI_path_make_safe(char *path)
|
||||
{
|
||||
/* Simply apply #BLI_filename_make_safe() over each component of the path.
|
||||
* Luckily enough, same 'safe' rules applies to file & directory names. */
|
||||
* Luckily enough, same *safe* rules applies to file & directory names. */
|
||||
char *curr_slash, *curr_path = path;
|
||||
bool changed = false;
|
||||
bool skip_first = false;
|
||||
|
||||
#ifdef WIN32
|
||||
if (BLI_path_is_abs(path)) {
|
||||
/* Do not make safe 'C:' in 'C:\foo\bar'... */
|
||||
if (BLI_path_is_abs_win32(path)) {
|
||||
/* Do not make safe `C:` in `C:\foo\bar`. */
|
||||
skip_first = true;
|
||||
}
|
||||
#endif
|
||||
|
@ -361,7 +350,7 @@ static int BLI_path_unc_prefix_len(const char *path)
|
|||
{
|
||||
if (BLI_path_is_unc(path)) {
|
||||
if ((path[2] == '?') && (path[3] == '\\')) {
|
||||
/* we assume long UNC path like \\?\server\share\folder etc... */
|
||||
/* We assume long UNC path like `\\?\server\share\folder` etc. */
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
@ -374,10 +363,14 @@ static int BLI_path_unc_prefix_len(const char *path)
|
|||
#if defined(WIN32)
|
||||
|
||||
/**
|
||||
* Return true if the path is absolute ie starts with a drive specifier
|
||||
* (eg A:\) or is a UNC path.
|
||||
* Return true if the path is an absolute path on a WIN32 file-system, it either:
|
||||
* - Starts with a drive specifier* (eg `A:\`).
|
||||
* - Is a UNC path.
|
||||
*
|
||||
* \note Not to be confused with the opposite of #BLI_path_is_rel which checks for the
|
||||
* Blender specific convention of using `//` prefix for blend-file relative paths.
|
||||
*/
|
||||
static bool BLI_path_is_abs(const char *name)
|
||||
static bool BLI_path_is_abs_win32(const char *name)
|
||||
{
|
||||
return (name[1] == ':' && ELEM(name[2], '\\', '/')) || BLI_path_is_unc(name);
|
||||
}
|
||||
|
@ -409,9 +402,10 @@ static void BLI_path_unc_to_short(wchar_t *unc)
|
|||
wchar_t tmp[PATH_MAX];
|
||||
|
||||
int len = wcslen(unc);
|
||||
/* convert:
|
||||
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
|
||||
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
|
||||
/* Convert:
|
||||
* - `\\?\UNC\server\share\folder\...` to `\\server\share\folder\...`
|
||||
* - `\\?\C:\` to `C:\`
|
||||
* - `\\?\C:\folder\...` to `C:\folder\...`
|
||||
*/
|
||||
if ((len > 3) && (unc[0] == L'\\') && (unc[1] == L'\\') && (unc[2] == L'?') &&
|
||||
ELEM(unc[3], L'\\', L'/')) {
|
||||
|
@ -450,18 +444,18 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
char temp[FILE_MAX];
|
||||
char res[FILE_MAX];
|
||||
|
||||
/* if file is already relative, bail out */
|
||||
/* If file is already relative, bail out. */
|
||||
if (BLI_path_is_rel(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* also bail out if relative path is not set */
|
||||
/* Also bail out if relative path is not set. */
|
||||
if (relfile[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
|
||||
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs_win32(relfile)) {
|
||||
char *ptemp;
|
||||
/* Fix missing volume name in relative base,
|
||||
* can happen with old `recent-files.txt` files. */
|
||||
|
@ -479,12 +473,12 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
if (BLI_strnlen(file, 3) > 2) {
|
||||
bool is_unc = BLI_path_is_unc(file);
|
||||
|
||||
/* Ensure paths are both UNC paths or are both drives */
|
||||
/* Ensure paths are both UNC paths or are both drives. */
|
||||
if (BLI_path_is_unc(temp) != is_unc) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ensure both UNC paths are on the same share */
|
||||
/* Ensure both UNC paths are on the same share. */
|
||||
if (is_unc) {
|
||||
int off;
|
||||
int slash = 0;
|
||||
|
@ -509,16 +503,16 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
|
||||
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
|
||||
|
||||
/* remove /./ which confuse the following slash counting... */
|
||||
/* Remove `/./` which confuse the following slash counting. */
|
||||
BLI_path_normalize(NULL, file);
|
||||
BLI_path_normalize(NULL, temp);
|
||||
|
||||
/* the last slash in the file indicates where the path part ends */
|
||||
/* The last slash in the file indicates where the path part ends. */
|
||||
lslash = BLI_path_slash_rfind(temp);
|
||||
|
||||
if (lslash) {
|
||||
/* find the prefix of the filename that is equal for both filenames.
|
||||
* This is replaced by the two slashes at the beginning */
|
||||
/* Find the prefix of the filename that is equal for both filenames.
|
||||
* This is replaced by the two slashes at the beginning. */
|
||||
const char *p = temp;
|
||||
const char *q = file;
|
||||
char *r = res;
|
||||
|
@ -532,16 +526,14 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
p++;
|
||||
q++;
|
||||
|
||||
/* don't search beyond the end of the string
|
||||
* in the rare case they match */
|
||||
/* Don't search beyond the end of the string in the rare case they match. */
|
||||
if ((*p == '\0') || (*q == '\0')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* we might have passed the slash when the beginning of a dir matches
|
||||
* so we rewind. Only check on the actual filename
|
||||
*/
|
||||
/* We might have passed the slash when the beginning of a dir matches
|
||||
* so we rewind. Only check on the actual filename. */
|
||||
if (*q != '/') {
|
||||
while ((q >= file) && (*q != '/')) {
|
||||
q--;
|
||||
|
@ -557,11 +549,10 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
|
||||
r += BLI_strcpy_rlen(r, "//");
|
||||
|
||||
/* p now points to the slash that is at the beginning of the part
|
||||
/* `p` now points to the slash that is at the beginning of the part
|
||||
* where the path is different from the relative path.
|
||||
* We count the number of directories we need to go up in the
|
||||
* hierarchy to arrive at the common 'prefix' of the path
|
||||
*/
|
||||
* hierarchy to arrive at the common prefix of the path. */
|
||||
if (p < temp) {
|
||||
p = temp;
|
||||
}
|
||||
|
@ -572,7 +563,7 @@ void BLI_path_rel(char *file, const char *relfile)
|
|||
p++;
|
||||
}
|
||||
|
||||
/* don't copy the slash at the beginning */
|
||||
/* Don't copy the slash at the beginning. */
|
||||
r += BLI_strncpy_rlen(r, q + 1, FILE_MAX - (r - res));
|
||||
|
||||
#ifdef WIN32
|
||||
|
@ -627,7 +618,7 @@ bool BLI_path_parent_dir(char *path)
|
|||
return false;
|
||||
}
|
||||
if (tail_len == 1) {
|
||||
/* Last path is ".", as normalize should remove this, it's safe to assume failure.
|
||||
/* Last path is `.`, as normalize should remove this, it's safe to assume failure.
|
||||
* This happens when the input a single period (possibly with slashes before or after). */
|
||||
if (path[tail_ofs] == '.') {
|
||||
return false;
|
||||
|
@ -646,7 +637,7 @@ bool BLI_path_parent_dir_until_exists(char *dir)
|
|||
|
||||
/* Loop as long as cur path is not a dir, and we can get a parent path. */
|
||||
while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_path_parent_dir(dir))) {
|
||||
/* pass */
|
||||
/* Pass. */
|
||||
}
|
||||
return (valid_path && dir[0]);
|
||||
}
|
||||
|
@ -659,11 +650,11 @@ bool BLI_path_parent_dir_until_exists(char *dir)
|
|||
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
|
||||
{
|
||||
uint ch_sta, ch_end, i;
|
||||
/* Insert current frame: file### -> file001 */
|
||||
/* Insert current frame: `file###` -> `file001`. */
|
||||
ch_sta = ch_end = 0;
|
||||
for (i = 0; path[i] != '\0'; i++) {
|
||||
if (ELEM(path[i], '\\', '/')) {
|
||||
ch_end = 0; /* this is a directory name, don't use any hashes we found */
|
||||
ch_end = 0; /* This is a directory name, don't use any hashes we found. */
|
||||
}
|
||||
else if (path[i] == '#') {
|
||||
ch_sta = i;
|
||||
|
@ -671,9 +662,9 @@ static bool stringframe_chars(const char *path, int *char_start, int *char_end)
|
|||
while (path[ch_end] == '#') {
|
||||
ch_end++;
|
||||
}
|
||||
i = ch_end - 1; /* keep searching */
|
||||
i = ch_end - 1; /* Keep searching. */
|
||||
|
||||
/* don't break, there may be a slash after this that invalidates the previous #'s */
|
||||
/* Don't break, there may be a slash after this that invalidates the previous #'s. */
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -718,7 +709,7 @@ bool BLI_path_frame(char *path, int frame, int digits)
|
|||
ensure_digits(path, digits);
|
||||
}
|
||||
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
|
||||
char tmp[FILE_MAX];
|
||||
BLI_snprintf(
|
||||
tmp, sizeof(tmp), "%.*s%.*d%s", ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
|
||||
|
@ -736,7 +727,7 @@ bool BLI_path_frame_range(char *path, int sta, int end, int digits)
|
|||
ensure_digits(path, digits);
|
||||
}
|
||||
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
||||
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* Warning: `ch_end` is the last # +1. */
|
||||
char tmp[FILE_MAX];
|
||||
BLI_snprintf(tmp,
|
||||
sizeof(tmp),
|
||||
|
@ -812,8 +803,8 @@ void BLI_path_frame_strip(char *path, char *r_ext, const size_t ext_maxlen)
|
|||
|
||||
bool BLI_path_frame_check_chars(const char *path)
|
||||
{
|
||||
int ch_sta, ch_end; /* dummy args */
|
||||
return stringframe_chars(path, &ch_sta, &ch_end);
|
||||
int ch_sta_dummy, ch_end_dummy;
|
||||
return stringframe_chars(path, &ch_sta_dummy, &ch_end_dummy);
|
||||
}
|
||||
|
||||
void BLI_path_to_display_name(char *display_name, int maxlen, const char *name)
|
||||
|
@ -860,16 +851,14 @@ bool BLI_path_abs(char *path, const char *basepath)
|
|||
char base[FILE_MAX];
|
||||
#ifdef WIN32
|
||||
|
||||
/* without this: "" --> "C:\" */
|
||||
/* Without this, an empty string converts to: `C:\` */
|
||||
if (*path == '\0') {
|
||||
return wasrelative;
|
||||
}
|
||||
|
||||
/* we are checking here if we have an absolute path that is not in the current
|
||||
* blend file as a lib main - we are basically checking for the case that a
|
||||
* UNIX root '/' is passed.
|
||||
*/
|
||||
if (!wasrelative && !BLI_path_is_abs(path)) {
|
||||
/* We are checking here if we have an absolute path that is not in the current `.blend` file
|
||||
* as a lib main - we are basically checking for the case that a UNIX root `/` is passed. */
|
||||
if (!wasrelative && !BLI_path_is_abs_win32(path)) {
|
||||
char *p = path;
|
||||
BLI_windows_get_default_root_dir(tmp);
|
||||
/* Get rid of the slashes at the beginning of the path. */
|
||||
|
@ -892,7 +881,7 @@ bool BLI_path_abs(char *path, const char *basepath)
|
|||
* `C:\foo.JPG` -> `/c/foo.JPG` */
|
||||
|
||||
if (isalpha(tmp[0]) && (tmp[1] == ':') && ELEM(tmp[2], '\\', '/')) {
|
||||
tmp[1] = tolower(tmp[0]); /* Replace ':' with drive-letter. */
|
||||
tmp[1] = tolower(tmp[0]); /* Replace `:` with drive-letter. */
|
||||
tmp[0] = '/';
|
||||
/* `\` the slash will be converted later. */
|
||||
}
|
||||
|
@ -916,28 +905,28 @@ bool BLI_path_abs(char *path, const char *basepath)
|
|||
const char *lslash;
|
||||
BLI_strncpy(base, basepath, sizeof(base));
|
||||
|
||||
/* file component is ignored, so don't bother with the trailing slash */
|
||||
/* File component is ignored, so don't bother with the trailing slash. */
|
||||
BLI_path_normalize(NULL, base);
|
||||
lslash = BLI_path_slash_rfind(base);
|
||||
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
|
||||
|
||||
if (lslash) {
|
||||
/* length up to and including last "/" */
|
||||
/* Length up to and including last `/`. */
|
||||
const int baselen = (int)(lslash - base) + 1;
|
||||
/* use path for temp storage here, we copy back over it right away */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX); /* strip "//" */
|
||||
/* Use path for temp storage here, we copy back over it right away. */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX); /* Strip `//` prefix. */
|
||||
|
||||
memcpy(tmp, base, baselen); /* prefix with base up to last "/" */
|
||||
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* append path after "//" */
|
||||
BLI_strncpy(path, tmp, FILE_MAX); /* return as result */
|
||||
memcpy(tmp, base, baselen); /* Prefix with base up to last `/`. */
|
||||
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* Append path after `//`. */
|
||||
BLI_strncpy(path, tmp, FILE_MAX); /* Return as result. */
|
||||
}
|
||||
else {
|
||||
/* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
|
||||
/* Base doesn't seem to be a directory, ignore it and just strip `//` prefix on path. */
|
||||
BLI_strncpy(path, tmp + 2, FILE_MAX);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* base ignored */
|
||||
/* Base ignored. */
|
||||
BLI_strncpy(path, tmp, FILE_MAX);
|
||||
}
|
||||
|
||||
|
@ -948,7 +937,7 @@ bool BLI_path_abs(char *path, const char *basepath)
|
|||
BLI_str_replace_char(path + 2, '/', '\\');
|
||||
#endif
|
||||
|
||||
/* ensure this is after correcting for path switch */
|
||||
/* Ensure this is after correcting for path switch. */
|
||||
BLI_path_normalize(NULL, path);
|
||||
|
||||
return wasrelative;
|
||||
|
@ -960,7 +949,7 @@ bool BLI_path_is_abs_from_cwd(const char *path)
|
|||
const int path_len_clamp = BLI_strnlen(path, 3);
|
||||
|
||||
#ifdef WIN32
|
||||
if ((path_len_clamp >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path)) {
|
||||
if ((path_len_clamp >= 3 && BLI_path_is_abs_win32(path)) || BLI_path_is_unc(path)) {
|
||||
is_abs = true;
|
||||
}
|
||||
#else
|
||||
|
@ -979,7 +968,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
|||
|
||||
if (!BLI_path_is_abs_from_cwd(path)) {
|
||||
char cwd[FILE_MAX];
|
||||
/* in case the full path to the blend isn't used */
|
||||
/* In case the full path to the blend isn't used. */
|
||||
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
|
||||
char origpath[FILE_MAX];
|
||||
BLI_strncpy(origpath, path, FILE_MAX);
|
||||
|
@ -996,7 +985,7 @@ bool BLI_path_abs_from_cwd(char *path, const size_t maxlen)
|
|||
|
||||
#ifdef _WIN32
|
||||
/**
|
||||
* Tries appending each of the semicolon-separated extensions in the PATHEXT
|
||||
* Tries appending each of the semicolon-separated extensions in the `PATHEXT`
|
||||
* environment variable (Windows-only) onto `name` in turn until such a file is found.
|
||||
* Returns success/failure.
|
||||
*/
|
||||
|
@ -1007,7 +996,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
|
|||
|
||||
type = BLI_exists(name);
|
||||
if ((type == 0) || S_ISDIR(type)) {
|
||||
/* typically 3-5, ".EXE", ".BAT"... etc */
|
||||
/* Typically 3-5, ".EXE", ".BAT"... etc. */
|
||||
const int ext_max = 12;
|
||||
const char *ext = BLI_getenv("PATHEXT");
|
||||
if (ext) {
|
||||
|
@ -1016,7 +1005,7 @@ bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
|
|||
char *filename_ext;
|
||||
const char *ext_next;
|
||||
|
||||
/* null terminated in the loop */
|
||||
/* Null terminated in the loop. */
|
||||
memcpy(filename, name, name_len);
|
||||
filename_ext = filename + name_len;
|
||||
|
||||
|
@ -1101,11 +1090,9 @@ bool BLI_path_program_search(char *fullname, const size_t maxlen, const char *na
|
|||
|
||||
void BLI_setenv(const char *env, const char *val)
|
||||
{
|
||||
/* free windows */
|
||||
|
||||
#if (defined(_WIN32) || defined(_WIN64))
|
||||
/* MS-Windows. */
|
||||
uputenv(env, val);
|
||||
|
||||
#else
|
||||
/* Linux/macOS/BSD */
|
||||
if (val) {
|
||||
|
@ -1158,7 +1145,7 @@ bool BLI_make_existing_file(const char *name)
|
|||
char di[FILE_MAX];
|
||||
BLI_split_dir_part(name, di, sizeof(di));
|
||||
|
||||
/* make if the dir doesn't exist */
|
||||
/* Make if the dir doesn't exist. */
|
||||
return BLI_dir_create_recursive(di);
|
||||
}
|
||||
|
||||
|
@ -1260,7 +1247,7 @@ bool BLI_path_extension_glob_validate(char *ext_fnmatch)
|
|||
/* Non-wildcard char, we can break here and consider the pattern valid. */
|
||||
return false;
|
||||
}
|
||||
/* So far, only wildcards in last group of the pattern... */
|
||||
/* So far, only wildcards in last group of the pattern. */
|
||||
only_wildcards = true;
|
||||
}
|
||||
/* Only one group in the pattern, so even if its only made of wildcard(s),
|
||||
|
@ -1352,7 +1339,7 @@ void BLI_split_dirfile(
|
|||
|
||||
if (dir) {
|
||||
if (lslash) {
|
||||
/* +1 to include the slash and the last char */
|
||||
/* +1 to include the slash and the last char. */
|
||||
BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1));
|
||||
}
|
||||
else {
|
||||
|
@ -1379,7 +1366,7 @@ const char *BLI_path_extension_or_end(const char *filepath)
|
|||
{
|
||||
/* NOTE(@ideasman42): Skip the extension when there are no preceding non-extension characters in
|
||||
* the file name. This ignores extensions at the beginning of a string or directly after a slash.
|
||||
* Only using trailing extension characters has the advantage that stripping the extenion
|
||||
* Only using trailing extension characters has the advantage that stripping the extension
|
||||
* never leads to a blank string (which can't be used as a file path).
|
||||
* Matches Python's `os.path.splitext`. */
|
||||
const char *ext = NULL;
|
||||
|
@ -1429,7 +1416,7 @@ size_t BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__
|
|||
}
|
||||
|
||||
if (dirlen >= maxlen) {
|
||||
return dirlen; /* fills the path */
|
||||
return dirlen; /* Fills the path. */
|
||||
}
|
||||
|
||||
return dirlen + BLI_strncpy_rlen(dst + dirlen, file, maxlen - dirlen);
|
||||
|
@ -1470,7 +1457,7 @@ size_t BLI_path_join_array(char *__restrict dst,
|
|||
}
|
||||
|
||||
#ifdef WIN32
|
||||
/* Special case "//" for relative paths, don't use separator #SEP
|
||||
/* Special case `//` for relative paths, don't use separator #SEP
|
||||
* as this has a special meaning on both WIN32 & UNIX.
|
||||
* Without this check joining `"//", "path"`. results in `"//\path"`. */
|
||||
if (ofs != 0) {
|
||||
|
@ -1519,7 +1506,7 @@ size_t BLI_path_join_array(char *__restrict dst,
|
|||
}
|
||||
|
||||
if (len != 0) {
|
||||
/* the very first path may have a slash at the end */
|
||||
/* The very first path may have a slash at the end. */
|
||||
if (ofs && !BLI_path_slash_is_native_compat(dst[ofs - 1])) {
|
||||
dst[ofs++] = SEP;
|
||||
if (ofs == dst_last) {
|
||||
|
@ -1574,7 +1561,7 @@ static bool path_name_at_index_forward(const char *__restrict path,
|
|||
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
|
||||
if (prev + 1 != i) {
|
||||
prev += 1;
|
||||
/* Skip '/./' (behave as if they don't exist). */
|
||||
/* Skip `/./` (behave as if they don't exist). */
|
||||
if (!((i - prev == 1) && (prev != 0) && (path[prev] == '.'))) {
|
||||
if (index_step == index) {
|
||||
*r_offset = prev;
|
||||
|
@ -1609,7 +1596,7 @@ static bool path_name_at_index_backward(const char *__restrict path,
|
|||
if ((c == '\0') || BLI_path_slash_is_native_compat(c)) {
|
||||
if (prev - 1 != i) {
|
||||
i += 1;
|
||||
/* Skip '/./' (behave as if they don't exist). */
|
||||
/* Skip `/./` (behave as if they don't exist). */
|
||||
if (!((prev - i == 1) && (i != 0) && (path[i] == '.'))) {
|
||||
if (index_step == index) {
|
||||
*r_offset = i;
|
||||
|
@ -1644,7 +1631,7 @@ bool BLI_path_contains(const char *container_path, const char *containee_path)
|
|||
char containee_native[PATH_MAX];
|
||||
|
||||
/* Keep space for a trailing slash. If the path is truncated by this, the containee path is
|
||||
* longer than PATH_MAX and the result is ill-defined. */
|
||||
* longer than #PATH_MAX and the result is ill-defined. */
|
||||
BLI_strncpy(container_native, container_path, PATH_MAX - 1);
|
||||
BLI_strncpy(containee_native, containee_path, PATH_MAX);
|
||||
|
||||
|
|
|
@ -4305,6 +4305,9 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
|
|||
ARRAY_SIZE(tool_replace_table));
|
||||
}
|
||||
}
|
||||
|
||||
/* Rename Grease Pencil weight draw brush. */
|
||||
do_versions_rename_id(bmain, ID_BR, "Draw Weight", "Weight Draw");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -81,11 +81,8 @@ BLI_INLINE void bmesh_calc_tessellation_for_face_impl(BMLoop *(*looptris)[3],
|
|||
efa->no, l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co);
|
||||
}
|
||||
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast_with_normal(l_ptr_a[0]->v->co,
|
||||
l_ptr_a[1]->v->co,
|
||||
l_ptr_a[2]->v->co,
|
||||
l_ptr_b[2]->v->co,
|
||||
efa->no))) {
|
||||
if (UNLIKELY(is_quad_flip_v3_first_third_fast(
|
||||
l_ptr_a[0]->v->co, l_ptr_a[1]->v->co, l_ptr_a[2]->v->co, l_ptr_b[2]->v->co))) {
|
||||
/* Flip out of degenerate 0-2 state. */
|
||||
l_ptr_a[2] = l_ptr_b[2];
|
||||
l_ptr_b[0] = l_ptr_a[1];
|
||||
|
|
|
@ -118,6 +118,7 @@ set(GLSL_SRC
|
|||
shaders/compositor_glare_simple_star_vertical_pass.glsl
|
||||
shaders/compositor_glare_streaks_accumulate.glsl
|
||||
shaders/compositor_glare_streaks_filter.glsl
|
||||
shaders/compositor_id_mask.glsl
|
||||
shaders/compositor_image_crop.glsl
|
||||
shaders/compositor_map_uv.glsl
|
||||
shaders/compositor_morphological_distance.glsl
|
||||
|
@ -215,6 +216,7 @@ set(SRC_SHADER_CREATE_INFOS
|
|||
shaders/infos/compositor_filter_info.hh
|
||||
shaders/infos/compositor_flip_info.hh
|
||||
shaders/infos/compositor_glare_info.hh
|
||||
shaders/infos/compositor_id_mask_info.hh
|
||||
shaders/infos/compositor_image_crop_info.hh
|
||||
shaders/infos/compositor_map_uv_info.hh
|
||||
shaders/infos/compositor_morphological_distance_feather_info.hh
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
float input_mask_value = texture_load(input_mask_tx, texel).x;
|
||||
float mask = int(round(input_mask_value)) == index ? 1.0 : 0.0;
|
||||
|
||||
imageStore(output_mask_img, texel, vec4(mask));
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_id_mask)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::INT, "index")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_mask_tx")
|
||||
.image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img")
|
||||
.compute_source("compositor_id_mask.glsl")
|
||||
.do_static_compilation(true);
|
|
@ -590,7 +590,7 @@ void dof_gather_accumulator(sampler2D color_tx,
|
|||
* The full pixel neighborhood is gathered.
|
||||
* \{ */
|
||||
|
||||
void dof_slight_focus_gather(sampler2D depth_tx,
|
||||
void dof_slight_focus_gather(depth2D depth_tx,
|
||||
sampler2D color_tx,
|
||||
sampler2D bkh_lut_tx, /* Renamed because of ugly macro job. */
|
||||
float radius,
|
||||
|
|
|
@ -62,7 +62,7 @@ void main()
|
|||
int mask_shift = 1;
|
||||
|
||||
#define downsample_level(out_mip__, lod_) \
|
||||
active_thread = all(lessThan(local_px, gl_WorkGroupSize.xy >> uint(mask_shift))); \
|
||||
active_thread = all(lessThan(uvec2(local_px), gl_WorkGroupSize.xy >> uint(mask_shift))); \
|
||||
barrier(); /* Wait for previous writes to finish. */ \
|
||||
if (active_thread) { \
|
||||
max_depth = max_v4(load_local_depths(local_px)); \
|
||||
|
@ -89,12 +89,12 @@ void main()
|
|||
}
|
||||
finished_tile_counter = 0u;
|
||||
|
||||
ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize * 2u));
|
||||
ivec2 iter = divide_ceil(imageSize(out_mip_5), ivec2(gl_WorkGroupSize.xy * 2u));
|
||||
ivec2 image_border = imageSize(out_mip_5) - 1;
|
||||
for (int y = 0; y < iter.y; y++) {
|
||||
for (int x = 0; x < iter.x; x++) {
|
||||
/* Load result of the other work groups. */
|
||||
kernel_origin = ivec2(gl_WorkGroupSize) * ivec2(x, y);
|
||||
kernel_origin = ivec2(gl_WorkGroupSize.xy) * ivec2(x, y);
|
||||
src_px = ivec2(kernel_origin + local_px) * 2;
|
||||
vec4 samp;
|
||||
samp.x = imageLoad(out_mip_5, min(src_px + ivec2(0, 1), image_border)).x;
|
||||
|
|
|
@ -168,13 +168,15 @@ void main()
|
|||
}
|
||||
/* Fallthrough to the hemispheric case. */
|
||||
case LIGHT_RECT:
|
||||
case LIGHT_ELLIPSE:
|
||||
case LIGHT_ELLIPSE: {
|
||||
vec3 v000 = vP - v_right * radius - v_up * radius;
|
||||
vec3 v100 = v000 + v_right * (radius * 2.0);
|
||||
vec3 v010 = v000 + v_up * (radius * 2.0);
|
||||
vec3 v001 = v000 - v_back * radius;
|
||||
Box bbox = shape_box(v000, v100, v010, v001);
|
||||
intersect_tile = intersect_tile && intersect(tile, bbox);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -74,8 +74,10 @@ void main()
|
|||
|
||||
vec4 max_motion = imageLoad(in_tiles_img, src_tile);
|
||||
|
||||
MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy, src_tile);
|
||||
MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile);
|
||||
MotionPayload payload_prv = motion_blur_tile_indirection_pack_payload(max_motion.xy,
|
||||
uvec2(src_tile));
|
||||
MotionPayload payload_nxt = motion_blur_tile_indirection_pack_payload(max_motion.zw,
|
||||
uvec2(src_tile));
|
||||
if (true) {
|
||||
/* Rectangular area (in tiles) where the motion vector spreads. */
|
||||
MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy);
|
||||
|
@ -85,17 +87,20 @@ void main()
|
|||
for (int y = 0; y < motion_rect.extent.y; y++) {
|
||||
ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
|
||||
if (is_inside_motion_line(tile, motion_line)) {
|
||||
motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv);
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv);
|
||||
/* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
|
||||
* the motion next so that weighting in gather pass is better. */
|
||||
motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt);
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (true) {
|
||||
MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw, src_tile);
|
||||
MotionPayload payload = motion_blur_tile_indirection_pack_payload(max_motion.zw,
|
||||
uvec2(src_tile));
|
||||
/* Rectangular area (in tiles) where the motion vector spreads. */
|
||||
MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw);
|
||||
MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw);
|
||||
|
@ -104,10 +109,12 @@ void main()
|
|||
for (int y = 0; y < motion_rect.extent.y; y++) {
|
||||
ivec2 tile = motion_rect.bottom_left + ivec2(x, y);
|
||||
if (is_inside_motion_line(tile, motion_line)) {
|
||||
motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_NEXT, tile, payload_nxt);
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_NEXT, uvec2(tile), payload_nxt);
|
||||
/* FIXME: This is a bit weird, but for some reason, we need the store the same vector in
|
||||
* the motion next so that weighting in gather pass is better. */
|
||||
motion_blur_tile_indirection_store(tile_indirection_buf, MOTION_PREV, tile, payload_prv);
|
||||
motion_blur_tile_indirection_store(
|
||||
tile_indirection_buf, MOTION_PREV, uvec2(tile), payload_prv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -178,10 +178,10 @@ void main()
|
|||
vec4 max_motion;
|
||||
/* Load dilation result from the indirection table. */
|
||||
ivec2 tile_prev;
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, tile, tile_prev);
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_PREV, uvec2(tile), tile_prev);
|
||||
max_motion.xy = imageLoad(in_tiles_img, tile_prev).xy;
|
||||
ivec2 tile_next;
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, tile, tile_next);
|
||||
motion_blur_tile_indirection_load(tile_indirection_buf, MOTION_NEXT, uvec2(tile), tile_next);
|
||||
max_motion.zw = imageLoad(in_tiles_img, tile_next).zw;
|
||||
|
||||
Accumulator accum;
|
||||
|
|
|
@ -242,13 +242,13 @@ void output_aov(vec4 color, float value, uint hash)
|
|||
#if defined(MAT_AOV_SUPPORT) && defined(GPU_FRAGMENT_SHADER)
|
||||
for (int i = 0; i < AOV_MAX && i < aov_buf.color_len; i++) {
|
||||
if (aov_buf.hash_color[i] == hash) {
|
||||
imageStore(aov_color_img, ivec3(gl_FragCoord.xy, i), color);
|
||||
imageStore(aov_color_img, ivec3(ivec2(gl_FragCoord.xy), i), color);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < AOV_MAX && i < aov_buf.value_len; i++) {
|
||||
if (aov_buf.hash_value[i] == hash) {
|
||||
imageStore(aov_value_img, ivec3(gl_FragCoord.xy, i), vec4(value));
|
||||
imageStore(aov_value_img, ivec3(ivec2(gl_FragCoord.xy), i), vec4(value));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ void main()
|
|||
}
|
||||
|
||||
AABB aabb_tag;
|
||||
AABB aabb_map = AABB(vec3(-0.99999), vec3(0.99999));
|
||||
AABB aabb_map = shape_aabb(vec3(-0.99999), vec3(0.99999));
|
||||
|
||||
/* Directionnal winmat have no correct near/far in the Z dimension at this point.
|
||||
* Do not clip in this dimension. */
|
||||
|
@ -87,7 +87,7 @@ void main()
|
|||
for (int y = box_min.y; y <= box_max.y; y++) {
|
||||
for (int x = box_min.x; x <= box_max.x; x++) {
|
||||
int tile_index = shadow_tile_offset(ivec2(x, y), tilemap.tiles_index, lod);
|
||||
atomicOr(tiles_buf[tile_index], SHADOW_DO_UPDATE);
|
||||
atomicOr(tiles_buf[tile_index], uint(SHADOW_DO_UPDATE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_
|
|||
|
||||
tile_co >>= lod;
|
||||
int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod);
|
||||
atomicOr(tiles_buf[tile_index], SHADOW_IS_USED);
|
||||
atomicOr(tiles_buf[tile_index], uint(SHADOW_IS_USED));
|
||||
}
|
||||
|
||||
void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius)
|
||||
|
|
|
@ -44,7 +44,7 @@ bool is_visible(IsectBox box)
|
|||
|
||||
bool intersects_near_plane(IsectBox box)
|
||||
{
|
||||
vec4 near_plane = drw_view_culling.planes[4];
|
||||
vec4 near_plane = drw_view_culling.frustum_planes.planes[4];
|
||||
bool on_positive_side = false;
|
||||
bool on_negative_side = false;
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ typedef struct DispatchCommand DispatchCommand;
|
|||
typedef struct DRWDebugPrintBuffer DRWDebugPrintBuffer;
|
||||
typedef struct DRWDebugVert DRWDebugVert;
|
||||
typedef struct DRWDebugDrawBuffer DRWDebugDrawBuffer;
|
||||
typedef struct FrustumCorners FrustumCorners;
|
||||
typedef struct FrustumPlanes FrustumPlanes;
|
||||
|
||||
/* __cplusplus is true when compiling with MSL. */
|
||||
# if defined(__cplusplus) && !defined(GPU_SHADER)
|
||||
|
@ -94,11 +96,27 @@ uint drw_view_id = 0;
|
|||
# define DRW_VIEW_FROM_RESOURCE_ID drw_view_id = (drw_ResourceID & DRW_VIEW_MASK)
|
||||
#endif
|
||||
|
||||
struct FrustumCorners {
|
||||
float4 corners[8];
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(FrustumCorners, 16)
|
||||
|
||||
struct FrustumPlanes {
|
||||
/* [0] left
|
||||
* [1] right
|
||||
* [2] bottom
|
||||
* [3] top
|
||||
* [4] near
|
||||
* [5] far */
|
||||
float4 planes[6];
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(FrustumPlanes, 16)
|
||||
|
||||
struct ViewCullingData {
|
||||
/** \note vec3 array padded to vec4. */
|
||||
/** Frustum corners. */
|
||||
float4 corners[8];
|
||||
float4 planes[6];
|
||||
FrustumCorners frustum_corners;
|
||||
FrustumPlanes frustum_planes;
|
||||
float4 bound_sphere;
|
||||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(ViewCullingData, 16)
|
||||
|
|
|
@ -50,7 +50,8 @@ void View::frustum_boundbox_calc(int view_id)
|
|||
}
|
||||
#endif
|
||||
|
||||
MutableSpan<float4> corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)};
|
||||
MutableSpan<float4> corners = {culling_[view_id].frustum_corners.corners,
|
||||
ARRAY_SIZE(culling_[view_id].frustum_corners.corners)};
|
||||
|
||||
float left, right, bottom, top, near, far;
|
||||
bool is_persp = data_[view_id].winmat[3][3] == 0.0f;
|
||||
|
@ -89,15 +90,15 @@ void View::frustum_culling_planes_calc(int view_id)
|
|||
{
|
||||
float4x4 persmat = data_[view_id].winmat * data_[view_id].viewmat;
|
||||
planes_from_projmat(persmat.ptr(),
|
||||
culling_[view_id].planes[0],
|
||||
culling_[view_id].planes[5],
|
||||
culling_[view_id].planes[1],
|
||||
culling_[view_id].planes[3],
|
||||
culling_[view_id].planes[4],
|
||||
culling_[view_id].planes[2]);
|
||||
culling_[view_id].frustum_planes.planes[0],
|
||||
culling_[view_id].frustum_planes.planes[5],
|
||||
culling_[view_id].frustum_planes.planes[1],
|
||||
culling_[view_id].frustum_planes.planes[3],
|
||||
culling_[view_id].frustum_planes.planes[4],
|
||||
culling_[view_id].frustum_planes.planes[2]);
|
||||
|
||||
/* Normalize. */
|
||||
for (float4 &plane : culling_[view_id].planes) {
|
||||
for (float4 &plane : culling_[view_id].frustum_planes.planes) {
|
||||
plane.w /= normalize_v3(plane);
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +106,8 @@ void View::frustum_culling_planes_calc(int view_id)
|
|||
void View::frustum_culling_sphere_calc(int view_id)
|
||||
{
|
||||
BoundSphere &bsphere = *reinterpret_cast<BoundSphere *>(&culling_[view_id].bound_sphere);
|
||||
Span<float4> corners = {culling_[view_id].corners, ARRAY_SIZE(culling_[view_id].corners)};
|
||||
Span<float4> corners = {culling_[view_id].frustum_corners.corners,
|
||||
ARRAY_SIZE(culling_[view_id].frustum_corners.corners)};
|
||||
|
||||
/* Extract Bounding Sphere */
|
||||
if (data_[view_id].winmat[3][3] != 0.0f) {
|
||||
|
|
|
@ -9,6 +9,14 @@ struct AABB {
|
|||
vec3 min, max;
|
||||
};
|
||||
|
||||
AABB shape_aabb(vec3 min, vec3 max)
|
||||
{
|
||||
AABB aabb;
|
||||
aabb.min = min;
|
||||
aabb.max = max;
|
||||
return aabb;
|
||||
}
|
||||
|
||||
AABB aabb_init_min_max()
|
||||
{
|
||||
AABB aabb;
|
||||
|
|
|
@ -136,7 +136,7 @@ bool intersect_view(Pyramid pyramid)
|
|||
for (int p = 0; p < 6; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 5; ++v) {
|
||||
float test = dot(drw_view_culling.planes[p], vec4(pyramid.corners[v], 1.0));
|
||||
float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(pyramid.corners[v], 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -158,7 +158,8 @@ bool intersect_view(Pyramid pyramid)
|
|||
for (int p = 0; p < 5; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 8; ++v) {
|
||||
float test = dot(i_pyramid.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0));
|
||||
float test = dot(i_pyramid.planes[p],
|
||||
vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -181,7 +182,7 @@ bool intersect_view(Box box)
|
|||
for (int p = 0; p < 6; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 8; ++v) {
|
||||
float test = dot(drw_view_culling.planes[p], vec4(box.corners[v], 1.0));
|
||||
float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(box.corners[v], 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -203,7 +204,8 @@ bool intersect_view(Box box)
|
|||
for (int p = 0; p < 6; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 8; ++v) {
|
||||
float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0));
|
||||
float test = dot(i_box.planes[p],
|
||||
vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -227,7 +229,7 @@ bool intersect_view(IsectBox i_box)
|
|||
for (int p = 0; p < 6; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 8; ++v) {
|
||||
float test = dot(drw_view_culling.planes[p], vec4(i_box.corners[v], 1.0));
|
||||
float test = dot(drw_view_culling.frustum_planes.planes[p], vec4(i_box.corners[v], 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -247,7 +249,8 @@ bool intersect_view(IsectBox i_box)
|
|||
for (int p = 0; p < 6; ++p) {
|
||||
bool is_any_vertex_on_positive_side = false;
|
||||
for (int v = 0; v < 8; ++v) {
|
||||
float test = dot(i_box.planes[p], vec4(drw_view_culling.corners[v].xyz, 1.0));
|
||||
float test = dot(i_box.planes[p],
|
||||
vec4(drw_view_culling.frustum_corners.corners[v].xyz, 1.0));
|
||||
if (test > 0.0) {
|
||||
is_any_vertex_on_positive_side = true;
|
||||
break;
|
||||
|
@ -268,7 +271,7 @@ bool intersect_view(Sphere sphere)
|
|||
bool intersects = true;
|
||||
|
||||
for (int p = 0; p < 6 && intersects; ++p) {
|
||||
float dist_to_plane = dot(drw_view_culling.planes[p], vec4(sphere.center, 1.0));
|
||||
float dist_to_plane = dot(drw_view_culling.frustum_planes.planes[p], vec4(sphere.center, 1.0));
|
||||
if (dist_to_plane < -sphere.radius) {
|
||||
intersects = false;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@ struct Circle {
|
|||
|
||||
Circle shape_circle(vec2 center, float radius)
|
||||
{
|
||||
return Circle(center, radius);
|
||||
Circle circle;
|
||||
circle.center = center;
|
||||
circle.radius = radius;
|
||||
return circle;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -34,7 +37,10 @@ struct Sphere {
|
|||
|
||||
Sphere shape_sphere(vec3 center, float radius)
|
||||
{
|
||||
return Sphere(center, radius);
|
||||
Sphere sphere;
|
||||
sphere.center = center;
|
||||
sphere.radius = radius;
|
||||
return sphere;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -192,6 +198,14 @@ Frustum shape_frustum(vec3 corners[8])
|
|||
struct Cone {
|
||||
vec3 direction;
|
||||
float angle_cos;
|
||||
|
||||
#ifdef GPU_METAL
|
||||
inline Cone() = default;
|
||||
inline Cone(vec3 in_direction, float in_angle_cos)
|
||||
: direction(in_direction), angle_cos(in_angle_cos)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
Cone shape_cone(vec3 direction, float angle_cosine)
|
||||
|
|
|
@ -33,18 +33,19 @@ void projmat_dimensions(mat4 winmat,
|
|||
}
|
||||
}
|
||||
|
||||
void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8])
|
||||
void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out FrustumCorners frustum_corners)
|
||||
{
|
||||
float left, right, bottom, top, near, far;
|
||||
bool is_persp = winmat[3][3] == 0.0;
|
||||
|
||||
projmat_dimensions(winmat, left, right, bottom, top, near, far);
|
||||
|
||||
corners[0][2] = corners[3][2] = corners[7][2] = corners[4][2] = -near;
|
||||
corners[0][0] = corners[3][0] = left;
|
||||
corners[4][0] = corners[7][0] = right;
|
||||
corners[0][1] = corners[4][1] = bottom;
|
||||
corners[7][1] = corners[3][1] = top;
|
||||
frustum_corners.corners[0][2] = frustum_corners.corners[3][2] = frustum_corners.corners[7][2] =
|
||||
frustum_corners.corners[4][2] = -near;
|
||||
frustum_corners.corners[0][0] = frustum_corners.corners[3][0] = left;
|
||||
frustum_corners.corners[4][0] = frustum_corners.corners[7][0] = right;
|
||||
frustum_corners.corners[0][1] = frustum_corners.corners[4][1] = bottom;
|
||||
frustum_corners.corners[7][1] = frustum_corners.corners[3][1] = top;
|
||||
|
||||
/* Get the coordinates of the far plane. */
|
||||
if (is_persp) {
|
||||
|
@ -55,25 +56,20 @@ void frustum_boundbox_calc(mat4 winmat, mat4 viewinv, out vec4 corners[8])
|
|||
top *= sca_far;
|
||||
}
|
||||
|
||||
corners[1][2] = corners[2][2] = corners[6][2] = corners[5][2] = -far;
|
||||
corners[1][0] = corners[2][0] = left;
|
||||
corners[6][0] = corners[5][0] = right;
|
||||
corners[1][1] = corners[5][1] = bottom;
|
||||
corners[2][1] = corners[6][1] = top;
|
||||
frustum_corners.corners[1][2] = frustum_corners.corners[2][2] = frustum_corners.corners[6][2] =
|
||||
frustum_corners.corners[5][2] = -far;
|
||||
frustum_corners.corners[1][0] = frustum_corners.corners[2][0] = left;
|
||||
frustum_corners.corners[6][0] = frustum_corners.corners[5][0] = right;
|
||||
frustum_corners.corners[1][1] = frustum_corners.corners[5][1] = bottom;
|
||||
frustum_corners.corners[2][1] = frustum_corners.corners[6][1] = top;
|
||||
|
||||
/* Transform into world space. */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
corners[i].xyz = transform_point(viewinv, corners[i].xyz);
|
||||
frustum_corners.corners[i].xyz = transform_point(viewinv, frustum_corners.corners[i].xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void planes_from_projmat(mat4 mat,
|
||||
out vec4 left,
|
||||
out vec4 right,
|
||||
out vec4 bottom,
|
||||
out vec4 top,
|
||||
out vec4 near,
|
||||
out vec4 far)
|
||||
void planes_from_projmat(mat4 mat, out FrustumPlanes frustum_planes)
|
||||
{
|
||||
/* References:
|
||||
*
|
||||
|
@ -81,35 +77,35 @@ void planes_from_projmat(mat4 mat,
|
|||
* http://www8.cs.umu.se/kurser/5DV051/HT12/lab/plane_extraction.pdf
|
||||
*/
|
||||
mat = transpose(mat);
|
||||
left = mat[3] + mat[0];
|
||||
right = mat[3] - mat[0];
|
||||
bottom = mat[3] + mat[1];
|
||||
top = mat[3] - mat[1];
|
||||
near = mat[3] + mat[2];
|
||||
far = mat[3] - mat[2];
|
||||
frustum_planes.planes[0] = mat[3] + mat[0];
|
||||
frustum_planes.planes[1] = mat[3] - mat[0];
|
||||
frustum_planes.planes[2] = mat[3] + mat[1];
|
||||
frustum_planes.planes[3] = mat[3] - mat[1];
|
||||
frustum_planes.planes[4] = mat[3] + mat[2];
|
||||
frustum_planes.planes[5] = mat[3] - mat[2];
|
||||
}
|
||||
|
||||
void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out vec4 planes[6])
|
||||
void frustum_culling_planes_calc(mat4 winmat, mat4 viewmat, out FrustumPlanes frustum_planes)
|
||||
{
|
||||
mat4 persmat = winmat * viewmat;
|
||||
planes_from_projmat(persmat, planes[0], planes[5], planes[1], planes[3], planes[4], planes[2]);
|
||||
planes_from_projmat(persmat, frustum_planes);
|
||||
|
||||
/* Normalize. */
|
||||
for (int p = 0; p < 6; p++) {
|
||||
planes[p] /= length(planes[p].xyz);
|
||||
frustum_planes.planes[p] /= length(frustum_planes.planes[p].xyz);
|
||||
}
|
||||
}
|
||||
|
||||
vec4 frustum_culling_sphere_calc(vec4 corners[8])
|
||||
vec4 frustum_culling_sphere_calc(FrustumCorners frustum_corners)
|
||||
{
|
||||
/* Extract Bounding Sphere */
|
||||
/* TODO(fclem): This is significantly less precise than CPU, but it isn't used in most cases. */
|
||||
|
||||
vec4 bsphere;
|
||||
bsphere.xyz = (corners[0].xyz + corners[6].xyz) * 0.5;
|
||||
bsphere.xyz = (frustum_corners.corners[0].xyz + frustum_corners.corners[6].xyz) * 0.5;
|
||||
bsphere.w = 0.0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bsphere.w = max(bsphere.w, distance(bsphere.xyz, corners[i].xyz));
|
||||
bsphere.w = max(bsphere.w, distance(bsphere.xyz, frustum_corners.corners[i].xyz));
|
||||
}
|
||||
return bsphere;
|
||||
}
|
||||
|
@ -125,11 +121,15 @@ void main()
|
|||
return;
|
||||
}
|
||||
|
||||
frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, view_culling_buf[drw_view_id].corners);
|
||||
/* Read frustom_corners from device memory, update, and write back. */
|
||||
FrustumCorners frustum_corners = view_culling_buf[drw_view_id].frustum_corners;
|
||||
frustum_boundbox_calc(drw_view.winmat, drw_view.viewinv, frustum_corners);
|
||||
view_culling_buf[drw_view_id].frustum_corners = frustum_corners;
|
||||
|
||||
frustum_culling_planes_calc(
|
||||
drw_view.winmat, drw_view.viewmat, view_culling_buf[drw_view_id].planes);
|
||||
/* Read frustum_planes from device memory, update, and write back. */
|
||||
FrustumPlanes frustum_planes = view_culling_buf[drw_view_id].frustum_planes;
|
||||
frustum_culling_planes_calc(drw_view.winmat, drw_view.viewmat, frustum_planes);
|
||||
|
||||
view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc(
|
||||
view_culling_buf[drw_view_id].corners);
|
||||
view_culling_buf[drw_view_id].frustum_planes = frustum_planes;
|
||||
view_culling_buf[drw_view_id].bound_sphere = frustum_culling_sphere_calc(frustum_corners);
|
||||
}
|
||||
|
|
|
@ -34,8 +34,9 @@ void main()
|
|||
bounds.bounding_corners[1].xyz,
|
||||
bounds.bounding_corners[2].xyz,
|
||||
bounds.bounding_corners[3].xyz);
|
||||
Sphere bounding_sphere = Sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w);
|
||||
Sphere inscribed_sphere = Sphere(bounds.bounding_sphere.xyz, bounds._inner_sphere_radius);
|
||||
Sphere bounding_sphere = shape_sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w);
|
||||
Sphere inscribed_sphere = shape_sphere(bounds.bounding_sphere.xyz,
|
||||
bounds._inner_sphere_radius);
|
||||
|
||||
for (drw_view_id = 0; drw_view_id < view_len; drw_view_id++) {
|
||||
if (drw_view_culling.bound_sphere.w == -1.0) {
|
||||
|
|
|
@ -233,7 +233,8 @@ AnimData *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
|
|||
ANIMCONT_DOPESHEET,
|
||||
ANIMCONT_FCURVES,
|
||||
ANIMCONT_NLA,
|
||||
ANIMCONT_CHANNEL)) {
|
||||
ANIMCONT_CHANNEL,
|
||||
ANIMCONT_TIMELINE)) {
|
||||
/* handling depends on the type of animation-context we've got */
|
||||
if (ale) {
|
||||
/* NLA Control Curves occur on NLA strips,
|
||||
|
@ -343,12 +344,20 @@ static void fcurve_scene_coord_range_get(Scene *scene,
|
|||
int end = fcu->totvert;
|
||||
|
||||
if (use_preview_only) {
|
||||
/* Preview frame ranges need to be converted to bezt array indices. */
|
||||
bool replace = false;
|
||||
start = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, scene->r.psfra, fcu->totvert, &replace);
|
||||
if (fcu->bezt) {
|
||||
/* Preview frame ranges need to be converted to bezt array indices. */
|
||||
bool replace = false;
|
||||
start = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, scene->r.psfra, fcu->totvert, &replace);
|
||||
|
||||
end = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, scene->r.pefra, fcu->totvert, &replace);
|
||||
end = BKE_fcurve_bezt_binarysearch_index(
|
||||
fcu->bezt, scene->r.pefra + 1, fcu->totvert, &replace);
|
||||
}
|
||||
else if (fcu->fpt) {
|
||||
const int unclamped_start = (int)(scene->r.psfra - fcu->fpt[0].vec[0]);
|
||||
start = max_ii(unclamped_start, 0);
|
||||
end = min_ii(unclamped_start + (scene->r.pefra - scene->r.psfra) + 1, fcu->totvert);
|
||||
}
|
||||
}
|
||||
|
||||
if (fcu->bezt) {
|
||||
|
|
|
@ -808,11 +808,14 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
|
|||
ops.gpencil.primitive_line
|
||||
ops.gpencil.primitive_polyline
|
||||
ops.gpencil.radius
|
||||
ops.gpencil.sculpt_average
|
||||
ops.gpencil.sculpt_blur
|
||||
ops.gpencil.sculpt_clone
|
||||
ops.gpencil.sculpt_grab
|
||||
ops.gpencil.sculpt_pinch
|
||||
ops.gpencil.sculpt_push
|
||||
ops.gpencil.sculpt_randomize
|
||||
ops.gpencil.sculpt_smear
|
||||
ops.gpencil.sculpt_smooth
|
||||
ops.gpencil.sculpt_strength
|
||||
ops.gpencil.sculpt_thickness
|
||||
|
|
|
@ -2079,7 +2079,7 @@ static void gpencil_brush_delete_mode_brushes(Main *bmain,
|
|||
}
|
||||
|
||||
if (mode == CTX_MODE_WEIGHT_GPENCIL) {
|
||||
if (preset != GP_BRUSH_PRESET_DRAW_WEIGHT) {
|
||||
if ((preset < GP_BRUSH_PRESET_WEIGHT_DRAW) || (preset > GP_BRUSH_PRESET_WEIGHT_SMEAR)) {
|
||||
continue;
|
||||
}
|
||||
if ((brush_active) && (brush_active->gpencil_weight_tool != brush->gpencil_weight_tool)) {
|
||||
|
@ -2666,58 +2666,67 @@ static int gpencil_vertex_group_normalize_all_exec(bContext *C, wmOperator *op)
|
|||
continue;
|
||||
}
|
||||
|
||||
/* look for tot value */
|
||||
float *tot_values = MEM_callocN(gps->totpoints * sizeof(float), __func__);
|
||||
|
||||
/* Loop all points in stroke. */
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
int v;
|
||||
float sum = 0.0f;
|
||||
float sum_lock = 0.0f;
|
||||
float sum_unlock = 0.0f;
|
||||
|
||||
/* Get vertex groups and weights. */
|
||||
dvert = &gps->dvert[i];
|
||||
for (int v = 0; v < defbase_tot; v++) {
|
||||
|
||||
/* Sum weights. */
|
||||
for (v = 0; v < defbase_tot; v++) {
|
||||
/* Get vertex group. */
|
||||
defgroup = BLI_findlink(&gpd->vertex_group_names, v);
|
||||
/* skip NULL or locked groups */
|
||||
if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip current */
|
||||
if ((lock_active) && (v == def_nr)) {
|
||||
if (defgroup == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get weight in vertex group. */
|
||||
dw = BKE_defvert_find_index(dvert, v);
|
||||
if (dw != NULL) {
|
||||
tot_values[i] += dw->weight;
|
||||
if (dw == NULL) {
|
||||
continue;
|
||||
}
|
||||
sum += dw->weight;
|
||||
|
||||
/* Vertex group locked or unlocked? */
|
||||
if ((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr))) {
|
||||
sum_lock += dw->weight;
|
||||
}
|
||||
else {
|
||||
sum_unlock += dw->weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* normalize weights */
|
||||
for (int i = 0; i < gps->totpoints; i++) {
|
||||
if (tot_values[i] == 0.0f) {
|
||||
if ((sum == 1.0f) || (sum_unlock == 0.0f)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dvert = &gps->dvert[i];
|
||||
for (int v = 0; v < defbase_tot; v++) {
|
||||
/* Normalize weights. */
|
||||
float fac = MAX2(0, (1.0f - sum_lock) / sum_unlock);
|
||||
|
||||
for (v = 0; v < defbase_tot; v++) {
|
||||
/* Get vertex group. */
|
||||
defgroup = BLI_findlink(&gpd->vertex_group_names, v);
|
||||
/* skip NULL or locked groups */
|
||||
if ((defgroup == NULL) || (defgroup->flag & DG_LOCK_WEIGHT)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* skip current */
|
||||
if ((lock_active) && (v == def_nr)) {
|
||||
if (defgroup == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get weight in vertex group. */
|
||||
dw = BKE_defvert_find_index(dvert, v);
|
||||
if (dw != NULL) {
|
||||
dw->weight = dw->weight / tot_values[i];
|
||||
if (dw == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Normalize in unlocked vertex groups only. */
|
||||
if (!((defgroup->flag & DG_LOCK_WEIGHT) || ((lock_active) && (v == def_nr)))) {
|
||||
dw->weight *= fac;
|
||||
CLAMP(dw->weight, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free temp array */
|
||||
MEM_SAFE_FREE(tot_values);
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
|
|
|
@ -518,6 +518,8 @@ void GPENCIL_OT_stroke_editcurve_set_handle_type(struct wmOperatorType *ot);
|
|||
*/
|
||||
void GPENCIL_OT_sculpt_paint(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_weight_paint(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_weight_toggle_direction(struct wmOperatorType *ot);
|
||||
void GPENCIL_OT_weight_sample(struct wmOperatorType *ot);
|
||||
|
||||
/* buttons editing --- */
|
||||
|
||||
|
|
|
@ -292,6 +292,24 @@ static bool gpencil_stroke_weightmode_draw_poll(bContext *C)
|
|||
return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_DRAW);
|
||||
}
|
||||
|
||||
/* Poll callback for weight paint (Blur) */
|
||||
static bool gpencil_stroke_weightmode_blur_poll(bContext *C)
|
||||
{
|
||||
return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_BLUR);
|
||||
}
|
||||
|
||||
/* Poll callback for weight paint (Average) */
|
||||
static bool gpencil_stroke_weightmode_average_poll(bContext *C)
|
||||
{
|
||||
return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_AVERAGE);
|
||||
}
|
||||
|
||||
/* Poll callback for weight paint (Smear) */
|
||||
static bool gpencil_stroke_weightmode_smear_poll(bContext *C)
|
||||
{
|
||||
return gpencil_stroke_weightmode_poll_with_tool(C, GPWEIGHT_TOOL_SMEAR);
|
||||
}
|
||||
|
||||
/* Stroke Editing Keymap - Only when editmode is enabled */
|
||||
static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
|
||||
{
|
||||
|
@ -460,6 +478,24 @@ static void ed_keymap_gpencil_weightpainting_draw(wmKeyConfig *keyconf)
|
|||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Draw)", 0, 0);
|
||||
keymap->poll = gpencil_stroke_weightmode_draw_poll;
|
||||
}
|
||||
/* keys for weight with a blur brush */
|
||||
static void ed_keymap_gpencil_weightpainting_blur(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Blur)", 0, 0);
|
||||
keymap->poll = gpencil_stroke_weightmode_blur_poll;
|
||||
}
|
||||
/* keys for weight with a average brush */
|
||||
static void ed_keymap_gpencil_weightpainting_average(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Average)", 0, 0);
|
||||
keymap->poll = gpencil_stroke_weightmode_average_poll;
|
||||
}
|
||||
/* keys for weight with a smear brush */
|
||||
static void ed_keymap_gpencil_weightpainting_smear(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_ensure(keyconf, "Grease Pencil Stroke Weight (Smear)", 0, 0);
|
||||
keymap->poll = gpencil_stroke_weightmode_smear_poll;
|
||||
}
|
||||
|
||||
/* ==================== */
|
||||
|
||||
|
@ -485,6 +521,9 @@ void ED_keymap_gpencil(wmKeyConfig *keyconf)
|
|||
ed_keymap_gpencil_sculptpainting_clone(keyconf);
|
||||
ed_keymap_gpencil_weightpainting(keyconf);
|
||||
ed_keymap_gpencil_weightpainting_draw(keyconf);
|
||||
ed_keymap_gpencil_weightpainting_blur(keyconf);
|
||||
ed_keymap_gpencil_weightpainting_average(keyconf);
|
||||
ed_keymap_gpencil_weightpainting_smear(keyconf);
|
||||
ed_keymap_gpencil_vertexpainting(keyconf);
|
||||
ed_keymap_gpencil_vertexpainting_draw(keyconf);
|
||||
ed_keymap_gpencil_vertexpainting_blur(keyconf);
|
||||
|
@ -564,6 +603,8 @@ void ED_operatortypes_gpencil(void)
|
|||
|
||||
WM_operatortype_append(GPENCIL_OT_sculpt_paint);
|
||||
WM_operatortype_append(GPENCIL_OT_weight_paint);
|
||||
WM_operatortype_append(GPENCIL_OT_weight_toggle_direction);
|
||||
WM_operatortype_append(GPENCIL_OT_weight_sample);
|
||||
|
||||
/* Edit stroke editcurve */
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2215,6 +2215,15 @@ static int ui_id_brush_get_icon(const bContext *C, ID *id)
|
|||
case GP_BRUSH_ICON_GPBRUSH_WEIGHT:
|
||||
br->id.icon_id = ICON_GPBRUSH_WEIGHT;
|
||||
break;
|
||||
case GP_BRUSH_ICON_GPBRUSH_BLUR:
|
||||
br->id.icon_id = ICON_BRUSH_BLUR;
|
||||
break;
|
||||
case GP_BRUSH_ICON_GPBRUSH_AVERAGE:
|
||||
br->id.icon_id = ICON_BRUSH_BLUR;
|
||||
break;
|
||||
case GP_BRUSH_ICON_GPBRUSH_SMEAR:
|
||||
br->id.icon_id = ICON_BRUSH_BLUR;
|
||||
break;
|
||||
default:
|
||||
br->id.icon_id = ICON_GPBRUSH_PEN;
|
||||
break;
|
||||
|
|
|
@ -1845,6 +1845,18 @@ static void ed_default_handlers(
|
|||
wmKeyMap *keymap_weight_draw = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Weight (Draw)", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_weight_draw);
|
||||
|
||||
wmKeyMap *keymap_weight_blur = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Weight (Blur)", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_weight_blur);
|
||||
|
||||
wmKeyMap *keymap_weight_average = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Weight (Average)", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_weight_average);
|
||||
|
||||
wmKeyMap *keymap_weight_smear = WM_keymap_ensure(
|
||||
wm->defaultconf, "Grease Pencil Stroke Weight (Smear)", 0, 0);
|
||||
WM_event_add_keymap_handler(handlers, keymap_weight_smear);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,19 @@ static eGPBrush_Presets gpencil_get_brush_preset_from_tool(bToolRef *tool,
|
|||
break;
|
||||
}
|
||||
case CTX_MODE_WEIGHT_GPENCIL: {
|
||||
return GP_BRUSH_PRESET_DRAW_WEIGHT;
|
||||
if (STREQ(tool->runtime->data_block, "DRAW")) {
|
||||
return GP_BRUSH_PRESET_WEIGHT_DRAW;
|
||||
}
|
||||
if (STREQ(tool->runtime->data_block, "BLUR")) {
|
||||
return GP_BRUSH_PRESET_WEIGHT_BLUR;
|
||||
}
|
||||
if (STREQ(tool->runtime->data_block, "AVERAGE")) {
|
||||
return GP_BRUSH_PRESET_WEIGHT_AVERAGE;
|
||||
}
|
||||
if (STREQ(tool->runtime->data_block, "SMEAR")) {
|
||||
return GP_BRUSH_PRESET_WEIGHT_SMEAR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CTX_MODE_VERTEX_GPENCIL: {
|
||||
if (STREQ(tool->runtime->data_block, "DRAW")) {
|
||||
|
|
|
@ -154,7 +154,7 @@ struct SculptUndoNodeGeometry {
|
|||
CustomData ldata;
|
||||
CustomData pdata;
|
||||
int *poly_offset_indices;
|
||||
blender::ImplicitSharingInfo *poly_offsets_sharing_info;
|
||||
const blender::ImplicitSharingInfo *poly_offsets_sharing_info;
|
||||
int totvert;
|
||||
int totedge;
|
||||
int totloop;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue