UI: Asset Shelf (Experimental Feature) #104831
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
@ -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)) &&
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -2376,9 +2376,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];
|
||||
|
|
|
@ -110,11 +110,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
|
||||
|
||||
|
@ -124,9 +124,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;
|
||||
|
@ -139,7 +139,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);
|
||||
|
@ -153,13 +153,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));
|
||||
|
@ -171,7 +173,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);
|
||||
|
@ -59,7 +59,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) {
|
||||
|
@ -79,7 +79,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 {
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -166,7 +166,8 @@ void DepthOfField::sync()
|
|||
/* Now that we know the maximum render resolution of every view, using depth of field, allocate
|
||||
* the reduced buffers. Color needs to be signed format here. See note in shader for
|
||||
* explanation. Do not use texture pool because of needs mipmaps. */
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_ATTACHMENT |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
|
||||
reduced_color_tx_.ensure_2d(GPU_RGBA16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
|
||||
reduced_coc_tx_.ensure_2d(GPU_R16F, reduce_size, usage, nullptr, DOF_MIP_COUNT);
|
||||
reduced_color_tx_.ensure_mip_views();
|
||||
|
|
|
@ -24,7 +24,8 @@ void HiZBuffer::sync()
|
|||
int2 hiz_extent = math::ceil_to_multiple(render_extent, int2(1u << (HIZ_MIP_COUNT - 1)));
|
||||
int2 dispatch_size = math::divide_ceil(hiz_extent, int2(HIZ_GROUP_SIZE));
|
||||
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE;
|
||||
eGPUTextureUsage usage = GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW;
|
||||
hiz_tx_.ensure_2d(GPU_R32F, hiz_extent, usage, nullptr, HIZ_MIP_COUNT);
|
||||
hiz_tx_.ensure_mip_views();
|
||||
GPU_texture_mipmap_mode(hiz_tx_, true, false);
|
||||
|
|
|
@ -628,7 +628,7 @@ struct LightData {
|
|||
float radius_squared;
|
||||
/** NOTE: It is ok to use float3 here. A float is declared right after it.
|
||||
* float3 is also aligned to 16 bytes. */
|
||||
float3 color;
|
||||
packed_float3 color;
|
||||
/** Light Type. */
|
||||
eLightType type;
|
||||
/** Spot size. Aligned to size of float2. */
|
||||
|
|
|
@ -257,7 +257,8 @@ class ShadowModule {
|
|||
/** Tile to physical page mapping. This is an array texture with one layer per view. */
|
||||
Texture render_map_tx_ = {"ShadowRenderMap",
|
||||
GPU_R32UI,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ | GPU_TEXTURE_USAGE_SHADER_WRITE |
|
||||
GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
int2(SHADOW_TILEMAP_RES),
|
||||
64,
|
||||
nullptr,
|
||||
|
|
|
@ -12,7 +12,7 @@ void main()
|
|||
|
||||
/* Display backfacing surfels with a transparent checkerboard grid. */
|
||||
if (!gl_FrontFacing) {
|
||||
ivec2 grid_uv = ivec2(gl_FragCoord) / 5;
|
||||
ivec2 grid_uv = ivec2(gl_FragCoord.xy) / 5;
|
||||
if ((grid_uv.x + grid_uv.y) % 2 == 0) {
|
||||
discard;
|
||||
return;
|
||||
|
|
|
@ -45,7 +45,8 @@ void main()
|
|||
case LIGHT_RECT:
|
||||
case LIGHT_ELLIPSE:
|
||||
case LIGHT_POINT:
|
||||
sphere = Sphere(light._position, light.influence_radius_max);
|
||||
sphere.center = light._position;
|
||||
sphere.radius = light.influence_radius_max;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ bool debug_tilemaps(vec3 P, LightData light)
|
|||
out_color_add = vec4(debug_tile_state_color(tile), 0.0);
|
||||
out_color_mul = vec4(0.0);
|
||||
|
||||
if (ivec2(gl_FragCoord.xy) == ivec2(0)) {
|
||||
if (all(equal(ivec2(gl_FragCoord.xy), ivec2(0)))) {
|
||||
drw_print(light.object_mat);
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
#pragma BLENDER_REQUIRE(eevee_shadow_tilemap_lib.glsl)
|
||||
|
||||
/* TODO(@fclem): Implement. */
|
||||
#define assert(check)
|
||||
#ifndef GPU_METAL
|
||||
# define assert(check)
|
||||
#endif
|
||||
|
||||
/* Remove page ownership from the tile and append it to the cache. */
|
||||
void shadow_page_free(inout ShadowTileData tile)
|
||||
|
|
|
@ -45,7 +45,7 @@ float pixel_size_at(float linear_depth)
|
|||
if (is_persp) {
|
||||
pixel_size *= max(0.01, linear_depth);
|
||||
}
|
||||
return pixel_size * exp2(fb_lod);
|
||||
return pixel_size * exp2(float(fb_lod));
|
||||
}
|
||||
|
||||
void step_bounding_sphere(vec3 vs_near_plane,
|
||||
|
@ -117,6 +117,7 @@ void main()
|
|||
step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius);
|
||||
vec3 vP = point_world_to_view(P);
|
||||
|
||||
shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod));
|
||||
shadow_tag_usage(
|
||||
vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(float(fb_lod)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP)
|
|||
{
|
||||
vec3 vP = point_world_to_view(P);
|
||||
|
||||
float inflate_scale = pixel_world_radius * exp2(fb_lod);
|
||||
float inflate_scale = pixel_world_radius * exp2(float(fb_lod));
|
||||
bool is_persp = (ProjectionMatrix[3][3] == 0.0);
|
||||
if (is_persp) {
|
||||
inflate_scale *= -vP.z;
|
||||
|
|
|
@ -45,6 +45,8 @@ void write_depth(ivec2 texel_co, const int lod, ivec2 tile_co, float depth)
|
|||
/* Quantization bias. Equivalent to nextafter in C without all the safety. 1 is not enough. */
|
||||
u_depth += 2;
|
||||
|
||||
/* TOOD(Metal): For Metal, textures will need to be viewed as buffers to workaround missing image
|
||||
* atomics support. */
|
||||
imageAtomicMin(shadow_atlas_img, out_texel, u_depth);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
/** \name Shadow pipeline
|
||||
* \{ */
|
||||
|
||||
/* NOTE(Metal): As this is implemented using a fundamental data type, this needs to be specified
|
||||
* explicitly as uint for code generation, as the MSLShaderGenerator needs to be able to
|
||||
* distinguish between classes and fundamental types during code generation. */
|
||||
#define SHADOW_TILE_DATA_PACKED "uint"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear)
|
||||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_CLIPMAP_GROUP_SIZE)
|
||||
|
@ -34,7 +39,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_init)
|
|||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
.additional_info("eevee_shared")
|
||||
|
@ -44,7 +49,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_update)
|
|||
.do_static_compilation(true)
|
||||
.local_group_size(1, 1, 1)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(5, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, "uint", "resource_ids_buf[]")
|
||||
.additional_info("eevee_shared", "draw_view", "draw_view_culling")
|
||||
|
@ -55,7 +60,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque)
|
|||
.local_group_size(SHADOW_DEPTH_SCAN_GROUP_SIZE, SHADOW_DEPTH_SCAN_GROUP_SIZE)
|
||||
.sampler(0, ImageType::DEPTH_2D, "depth_tx")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.additional_info("eevee_shared", "draw_view", "draw_view_culling", "eevee_light_data")
|
||||
.compute_source("eevee_shadow_tag_usage_comp.glsl");
|
||||
|
@ -71,7 +76,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent)
|
|||
.vertex_in(0, Type::VEC3, "pos")
|
||||
.storage_buf(4, Qualifier::READ, "ObjectBounds", "bounds_buf[]")
|
||||
.storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.push_constant(Type::FLOAT, "tilemap_projection_ratio")
|
||||
.push_constant(Type::FLOAT, "pixel_world_radius")
|
||||
.push_constant(Type::IVEC2, "fb_resolution")
|
||||
|
@ -91,7 +96,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_mask)
|
|||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.additional_info("eevee_shared")
|
||||
.compute_source("eevee_shadow_page_mask_comp.glsl");
|
||||
|
||||
|
@ -99,7 +104,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_free)
|
|||
.do_static_compilation(true)
|
||||
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
|
@ -110,7 +115,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_defrag)
|
|||
.do_static_compilation(true)
|
||||
.local_group_size(1)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
|
@ -124,7 +129,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_page_allocate)
|
|||
.local_group_size(SHADOW_TILEMAP_LOD0_LEN)
|
||||
.typedef_source("draw_shader_shared.h")
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::READ_WRITE, "uint", "pages_free_buf[]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "uvec2", "pages_cached_buf[]")
|
||||
|
@ -137,7 +142,7 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_finalize)
|
|||
.typedef_source("draw_shader_shared.h")
|
||||
.local_group_size(SHADOW_TILEMAP_RES, SHADOW_TILEMAP_RES)
|
||||
.storage_buf(0, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(1, Qualifier::READ_WRITE, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.storage_buf(2, Qualifier::READ_WRITE, "ShadowPagesInfoData", "pages_infos_buf")
|
||||
.storage_buf(3, Qualifier::WRITE, "ViewMatrices", "view_infos_buf[64]")
|
||||
.storage_buf(4, Qualifier::READ_WRITE, "ShadowStatistics", "statistics_buf")
|
||||
|
@ -183,11 +188,12 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_debug)
|
|||
.do_static_compilation(true)
|
||||
.additional_info("eevee_shared")
|
||||
.storage_buf(5, Qualifier::READ, "ShadowTileMapData", "tilemaps_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, "ShadowTileDataPacked", "tiles_buf[]")
|
||||
.storage_buf(6, Qualifier::READ, SHADOW_TILE_DATA_PACKED, "tiles_buf[]")
|
||||
.fragment_out(0, Type::VEC4, "out_color_add", DualBlend::SRC_0)
|
||||
.fragment_out(0, Type::VEC4, "out_color_mul", DualBlend::SRC_1)
|
||||
.push_constant(Type::INT, "debug_mode")
|
||||
.push_constant(Type::INT, "debug_tilemap_index")
|
||||
.depth_write(DepthWrite::ANY)
|
||||
.fragment_source("eevee_shadow_debug_frag.glsl")
|
||||
.additional_info(
|
||||
"draw_fullscreen", "draw_view", "eevee_hiz_data", "eevee_light_data", "eevee_shadow_data");
|
||||
|
|
|
@ -350,6 +350,16 @@ struct DRWDebugVert {
|
|||
};
|
||||
BLI_STATIC_ASSERT_ALIGN(DRWDebugVert, 16)
|
||||
|
||||
inline DRWDebugVert debug_vert_make(uint in_pos0, uint in_pos1, uint in_pos2, uint in_vert_color)
|
||||
{
|
||||
DRWDebugVert debug_vert;
|
||||
debug_vert.pos0 = in_pos0;
|
||||
debug_vert.pos1 = in_pos1;
|
||||
debug_vert.pos2 = in_pos2;
|
||||
debug_vert.vert_color = in_vert_color;
|
||||
return debug_vert;
|
||||
}
|
||||
|
||||
/* Take the header (DrawCommand) into account. */
|
||||
#define DRW_DEBUG_DRAW_VERT_MAX (64 * 8192) - 1
|
||||
|
||||
|
|
|
@ -34,9 +34,9 @@ uint drw_debug_color_pack(vec4 v_color)
|
|||
|
||||
void drw_debug_line(inout uint vertid, vec3 v1, vec3 v2, uint v_color)
|
||||
{
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
drw_debug_verts_buf[vertid++] = debug_vert_make(
|
||||
floatBitsToUint(v1.x), floatBitsToUint(v1.y), floatBitsToUint(v1.z), v_color);
|
||||
drw_debug_verts_buf[vertid++] = DRWDebugVert(
|
||||
drw_debug_verts_buf[vertid++] = debug_vert_make(
|
||||
floatBitsToUint(v2.x), floatBitsToUint(v2.y), floatBitsToUint(v2.z), v_color);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -118,7 +118,6 @@ static void tracking_segment_knot_cb(void *userdata,
|
|||
float val)
|
||||
{
|
||||
TrackMotionCurveUserData *data = (TrackMotionCurveUserData *)userdata;
|
||||
int sel = 0, sel_flag;
|
||||
|
||||
if (track != data->act_track) {
|
||||
return;
|
||||
|
@ -127,8 +126,9 @@ static void tracking_segment_knot_cb(void *userdata,
|
|||
return;
|
||||
}
|
||||
|
||||
sel_flag = value_source == CLIP_VALUE_SOURCE_SPEED_X ? MARKER_GRAPH_SEL_X : MARKER_GRAPH_SEL_Y;
|
||||
sel = (marker->flag & sel_flag) ? 1 : 0;
|
||||
const int sel_flag = value_source == CLIP_VALUE_SOURCE_SPEED_X ? MARKER_GRAPH_SEL_X :
|
||||
MARKER_GRAPH_SEL_Y;
|
||||
const bool sel = (marker->flag & sel_flag) != 0;
|
||||
|
||||
if (sel == data->sel) {
|
||||
immUniformThemeColor(sel ? TH_HANDLE_VERTEX_SELECT : TH_HANDLE_VERTEX);
|
||||
|
|
|
@ -510,28 +510,23 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
|
||||
Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval);
|
||||
if (mesh == nullptr) {
|
||||
return geometry_set;
|
||||
if (BLI_listbase_is_single(&sspreadsheet->viewer_path.path)) {
|
||||
if (const GeometrySet *geometry_eval = object_eval->runtime.geometry_set_eval) {
|
||||
geometry_set = *geometry_eval;
|
||||
}
|
||||
|
||||
if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) {
|
||||
if (Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval)) {
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
geometry_set.replace_mesh(mesh, GeometryOwnershipType::ReadOnly);
|
||||
}
|
||||
}
|
||||
BKE_mesh_wrapper_ensure_mdata(mesh);
|
||||
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
|
||||
mesh_component.replace(mesh, GeometryOwnershipType::ReadOnly);
|
||||
}
|
||||
else {
|
||||
if (BLI_listbase_count(&sspreadsheet->viewer_path.path) == 1) {
|
||||
/* Use final evaluated object. */
|
||||
if (object_eval->runtime.geometry_set_eval != nullptr) {
|
||||
geometry_set = *object_eval->runtime.geometry_set_eval;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (const ViewerNodeLog *viewer_log =
|
||||
nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path(
|
||||
sspreadsheet->viewer_path)) {
|
||||
geometry_set = viewer_log->geometry;
|
||||
}
|
||||
if (const ViewerNodeLog *viewer_log =
|
||||
nodes::geo_eval_log::GeoModifierLog::find_viewer_node_log_for_path(
|
||||
sspreadsheet->viewer_path)) {
|
||||
geometry_set = viewer_log->geometry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -580,6 +580,33 @@ void ED_transform_calc_orientation_from_type(const bContext *C, float r_mat[3][3
|
|||
scene, view_layer, v3d, rv3d, ob, obedit, orient_index, pivot_point, r_mat);
|
||||
}
|
||||
|
||||
static void handle_armature_parent_orientation(Object *ob, float r_mat[3][3])
|
||||
{
|
||||
bPoseChannel *active_pchan = BKE_pose_channel_active(ob, false);
|
||||
|
||||
/* Check if target bone is a child. */
|
||||
if (active_pchan->parent) {
|
||||
/* For child, show parent local regardless if "local location" is set for parent bone. */
|
||||
transform_orientations_create_from_axis(r_mat, UNPACK3(active_pchan->parent->pose_mat));
|
||||
return;
|
||||
}
|
||||
|
||||
/* For root, use local transform of armature object. */
|
||||
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->object_to_world));
|
||||
}
|
||||
|
||||
static void handle_object_parent_orientation(Object *ob, float r_mat[3][3])
|
||||
{
|
||||
/* If object has parent, then orient to parent. */
|
||||
if (ob->parent) {
|
||||
transform_orientations_create_from_axis(r_mat, UNPACK3(ob->parent->object_to_world));
|
||||
}
|
||||
else {
|
||||
/* If object doesn't have parent, then orient to world. */
|
||||
unit_m3(r_mat);
|
||||
}
|
||||
}
|
||||
|
||||
short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
|
||||
ViewLayer *view_layer,
|
||||
const View3D *v3d,
|
||||
|
@ -609,6 +636,20 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
|
|||
/* If not gimbal, fall through to normal. */
|
||||
ATTR_FALLTHROUGH;
|
||||
}
|
||||
case V3D_ORIENT_PARENT: {
|
||||
if (ob) {
|
||||
if (ob->mode & OB_MODE_POSE) {
|
||||
handle_armature_parent_orientation(ob, r_mat);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
handle_object_parent_orientation(ob, r_mat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* No break; we define 'parent' as 'normal' otherwise. */
|
||||
ATTR_FALLTHROUGH;
|
||||
}
|
||||
case V3D_ORIENT_NORMAL: {
|
||||
if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
|
||||
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
|
||||
|
@ -621,7 +662,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene,
|
|||
if (ob) {
|
||||
if (ob->mode & OB_MODE_POSE) {
|
||||
/* Each bone moves on its own local axis, but to avoid confusion,
|
||||
* use the active pones axis for display #33575, this works as expected on a single
|
||||
* use the active bone's axis for display #33575, this works as expected on a single
|
||||
* bone and users who select many bones will understand what's going on and what local
|
||||
* means when they start transforming. */
|
||||
ED_getTransformOrientationMatrix(scene, view_layer, v3d, ob, obedit, pivot_point, r_mat);
|
||||
|
@ -741,6 +782,8 @@ const char *transform_orientations_spacename_get(TransInfo *t, const short orien
|
|||
return TIP_("view");
|
||||
case V3D_ORIENT_CURSOR:
|
||||
return TIP_("cursor");
|
||||
case V3D_ORIENT_PARENT:
|
||||
return TIP_("parent");
|
||||
case V3D_ORIENT_CUSTOM_MATRIX:
|
||||
return TIP_("custom");
|
||||
case V3D_ORIENT_CUSTOM:
|
||||
|
|
|
@ -3181,7 +3181,7 @@ static float uv_sphere_project(const Scene *scene,
|
|||
const float branch_init)
|
||||
{
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
|
@ -3358,7 +3358,7 @@ static float uv_cylinder_project(const Scene *scene,
|
|||
const float branch_init)
|
||||
{
|
||||
float max_u = 0.0f;
|
||||
if (BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
if (use_seams && BM_elem_flag_test(efa_init, BM_ELEM_TAG)) {
|
||||
return max_u;
|
||||
}
|
||||
|
||||
|
|
|
@ -458,6 +458,9 @@ GPUTexture *GPU_texture_create_view(const char *name,
|
|||
{
|
||||
BLI_assert(mip_len > 0);
|
||||
BLI_assert(layer_len > 0);
|
||||
BLI_assert_msg(
|
||||
GPU_texture_usage(src) & GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW,
|
||||
"Source texture of TextureView must have GPU_TEXTURE_USAGE_MIP_SWIZZLE_VIEW usage flag.");
|
||||
Texture *view = GPUBackend::get()->texture_alloc(name);
|
||||
view->init_view(src,
|
||||
format,
|
||||
|
|
|
@ -189,6 +189,16 @@ MTLContext::MTLContext(void *ghost_window, void *ghost_context)
|
|||
[this->queue retain];
|
||||
[this->device retain];
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wobjc-method-access"
|
||||
/* Enable increased concurrent shader compiler limit.
|
||||
* Note: Disable warning for missing method when building on older OS's, as compiled code will
|
||||
* still work correctly when run on a system with the API available. */
|
||||
if (@available(macOS 13.3, *)) {
|
||||
[this->device setShouldMaximizeConcurrentCompilation:YES];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
/* Register present callback. */
|
||||
this->ghost_context_->metalRegisterPresentCallback(&present);
|
||||
|
||||
|
|
|
@ -83,9 +83,7 @@ struct constexp_uvec3 {
|
|||
uint3 xyz;
|
||||
};
|
||||
|
||||
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z)
|
||||
{
|
||||
}
|
||||
constexpr constexp_uvec3(uint _x, uint _y, uint _z) : x(_x), y(_y), z(_z) {}
|
||||
constexpr uint operator[](int i)
|
||||
{
|
||||
/* Note: Need to switch on each elem value as array accessor triggers
|
||||
|
@ -294,6 +292,8 @@ struct SStruct {
|
|||
#define textureGather3(__tex, __uv, __comp) _texture_gather_internal(__tex, __uv, __comp)
|
||||
#define textureGatherOffset(__tex, __offset, __uv, __comp) \
|
||||
_texture_gather_internal(__tex, __uv, __comp, __offset)
|
||||
#define textureGrad(__tex, __uv, __dpdx, __dpdy) \
|
||||
_texture_grad_internal(__tex, __uv, __dpdx, __dpdy)
|
||||
|
||||
#define TEXURE_MACRO(_1, _2, _3, TEXNAME, ...) TEXNAME
|
||||
#define texture(...) TEXURE_MACRO(__VA_ARGS__, texture3, texture2)(__VA_ARGS__)
|
||||
|
@ -849,6 +849,34 @@ inline vec<T, 4> _texture_gather_internal(
|
|||
return tex.texture->gather(*tex.samp, uva.xy, uint(uva.z), offset);
|
||||
}
|
||||
|
||||
/* Texture Grad. */
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_2d<float, access::sample> tex,
|
||||
float2 uv,
|
||||
float2 dpdx,
|
||||
float2 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uv, gradient2d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_2d_array<float, access::sample> tex,
|
||||
float3 uva,
|
||||
float2 dpdx,
|
||||
float2 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uva.xy, uint(uva.z), gradient2d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
inline float4 _texture_grad_internal(
|
||||
thread _mtl_combined_image_sampler_3d<float, access::sample> tex,
|
||||
float3 uvw,
|
||||
float3 dpdx,
|
||||
float3 dpdy)
|
||||
{
|
||||
return tex.texture->sample(*tex.samp, uvw, gradient3d(dpdx, dpdy));
|
||||
}
|
||||
|
||||
/* Texture write support. */
|
||||
template<typename S, typename T, access A>
|
||||
inline void _texture_write_internal(thread _mtl_combined_image_sampler_1d<S, A> tex,
|
||||
|
|
|
@ -230,7 +230,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
|
|||
|
||||
const uint8_t *data_end = data + data_size;
|
||||
|
||||
for (uint i = 0; i < levels; i++) {
|
||||
for (uint level = 0; level < levels; level++) {
|
||||
uint blocks_per_row = (mip_width + 3) / 4;
|
||||
uint blocks_per_col = (mip_height + 3) / 4;
|
||||
uint blocks = blocks_per_row * blocks_per_col;
|
||||
|
@ -238,7 +238,7 @@ static void FlipDXTCImage(ImBuf *ibuf)
|
|||
if (data + block_bytes * blocks > data_end) {
|
||||
/* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
|
||||
* on a malformed files. */
|
||||
*num_valid_levels = i;
|
||||
*num_valid_levels = level;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
/* Include our own math header first to avoid warnings about M_PI
|
||||
* redefinition between OpenImageIO and Windows headers. */
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include <OpenImageIO/filesystem.h>
|
||||
#include <OpenImageIO/imageio.h>
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "IMB_imbuf.h"
|
||||
#include "IMB_imbuf_types.h"
|
||||
|
||||
|
|
|
@ -560,6 +560,12 @@ static bool imb_save_openexr_half(ImBuf *ibuf, const char *name, const int flags
|
|||
|
||||
return false;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
delete file_stream;
|
||||
printf("OpenEXR-save: UNKNOWN ERROR\n");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
delete file_stream;
|
||||
return true;
|
||||
|
@ -636,6 +642,11 @@ static bool imb_save_openexr_float(ImBuf *ibuf, const char *name, const int flag
|
|||
delete file_stream;
|
||||
return false;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
printf("OpenEXR-save: UNKNOWN ERROR\n");
|
||||
delete file_stream;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete file_stream;
|
||||
return true;
|
||||
|
@ -939,6 +950,15 @@ bool IMB_exr_begin_write(void *handle,
|
|||
data->ofile = nullptr;
|
||||
data->ofile_stream = nullptr;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "IMB_exr_begin_write: UNKNOWN ERROR" << std::endl;
|
||||
|
||||
delete data->ofile;
|
||||
delete data->ofile_stream;
|
||||
|
||||
data->ofile = nullptr;
|
||||
data->ofile_stream = nullptr;
|
||||
}
|
||||
|
||||
return (data->ofile != nullptr);
|
||||
}
|
||||
|
@ -999,7 +1019,7 @@ void IMB_exrtile_begin_write(
|
|||
data->ofile_stream = new OFileStream(filepath);
|
||||
data->mpofile = new MultiPartOutputFile(*(data->ofile_stream), headers.data(), headers.size());
|
||||
}
|
||||
catch (const std::exception &) {
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
delete data->mpofile;
|
||||
delete data->ofile_stream;
|
||||
|
||||
|
@ -1024,7 +1044,7 @@ bool IMB_exr_begin_read(
|
|||
data->ifile_stream = new IFileStream(filepath);
|
||||
data->ifile = new MultiPartInputFile(*(data->ifile_stream));
|
||||
}
|
||||
catch (const std::exception &) {
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
delete data->ifile;
|
||||
delete data->ifile_stream;
|
||||
|
||||
|
@ -1199,6 +1219,9 @@ void IMB_exr_write_channels(void *handle)
|
|||
catch (const std::exception &exc) {
|
||||
std::cerr << "OpenEXR-writePixels: ERROR: " << exc.what() << std::endl;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "OpenEXR-writePixels: UNKNOWN ERROR" << std::endl;
|
||||
}
|
||||
/* Free temporary buffers. */
|
||||
if (rect_half != nullptr) {
|
||||
MEM_freeN(rect_half);
|
||||
|
@ -1258,6 +1281,9 @@ void IMB_exrtile_write_channels(
|
|||
catch (const std::exception &exc) {
|
||||
std::cerr << "OpenEXR-writeTile: ERROR: " << exc.what() << std::endl;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "OpenEXR-writeTile: UNKNOWN ERROR" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void IMB_exr_read_channels(void *handle)
|
||||
|
@ -1336,6 +1362,10 @@ void IMB_exr_read_channels(void *handle)
|
|||
std::cerr << "OpenEXR-readPixels: ERROR: " << exc.what() << std::endl;
|
||||
break;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "OpenEXR-readPixels: UNKNOWN ERROR: " << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2150,6 +2180,16 @@ struct ImBuf *imb_load_openexr(const uchar *mem,
|
|||
delete file;
|
||||
delete membuf;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "OpenEXR-Load: UNKNOWN ERROR" << std::endl;
|
||||
if (ibuf) {
|
||||
IMB_freeImBuf(ibuf);
|
||||
}
|
||||
delete file;
|
||||
delete membuf;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -2254,6 +2294,12 @@ struct ImBuf *imb_load_filepath_thumbnail_openexr(const char *filepath,
|
|||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
catch (...) { /* Catch-all for edge cases or compiler bugs. */
|
||||
std::cerr << "OpenEXR-Thumbnail: UNKNOWN ERROR" << std::endl;
|
||||
delete file;
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -632,6 +632,7 @@ enum {
|
|||
V3D_ORIENT_VIEW = 3,
|
||||
V3D_ORIENT_GIMBAL = 4,
|
||||
V3D_ORIENT_CURSOR = 5,
|
||||
V3D_ORIENT_PARENT = 6,
|
||||
V3D_ORIENT_CUSTOM = 1024,
|
||||
/** Runtime only, never saved to DNA. */
|
||||
V3D_ORIENT_CUSTOM_MATRIX = (V3D_ORIENT_CUSTOM - 1),
|
||||
|
|
|
@ -753,6 +753,7 @@ static void rna_def_attribute_float(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -785,6 +786,7 @@ static void rna_def_attribute_float_vector(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatVectorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -823,6 +825,7 @@ static void rna_def_attribute_float_color(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "FloatColorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -870,6 +873,7 @@ static void rna_def_attribute_byte_color(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ByteColorAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -918,6 +922,7 @@ static void rna_def_attribute_int(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "IntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -947,6 +952,7 @@ static void rna_def_attribute_string(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "StringAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -976,6 +982,7 @@ static void rna_def_attribute_bool(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -1005,6 +1012,7 @@ static void rna_def_attribute_int8(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "ByteIntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -1036,6 +1044,7 @@ static void rna_def_attribute_int2(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Int2AttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -1071,6 +1080,7 @@ static void rna_def_attribute_float2(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Float2AttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Attribute_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
|
|
@ -345,6 +345,7 @@ static void rna_def_curves_curve(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||
RNA_def_property_ui_text(prop, "Points", "Control points of the curve");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_CurveSlice_points_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -384,6 +385,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
|||
/* Point and Curve RNA API helpers. */
|
||||
|
||||
prop = RNA_def_property(srna, "curves", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_curves_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -398,6 +400,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "CurvePoint");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_position_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -412,6 +415,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
|||
/* Direct access to built-in attributes. */
|
||||
|
||||
prop = RNA_def_property(srna, "position_data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_position_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -426,6 +430,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
|||
|
||||
prop = RNA_def_property(srna, "curve_offset_data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "IntAttributeValue");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_Curves_curve_offset_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -440,6 +445,7 @@ static void rna_def_curves(BlenderRNA *brna)
|
|||
rna_def_read_only_float_vector(brna);
|
||||
|
||||
prop = RNA_def_property(srna, "normals", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_struct_type(prop, "FloatVectorValueReadOnly");
|
||||
/* `lookup_int` isn't provided since the entire normals array is allocated and calculated when
|
||||
* it's accessed. */
|
||||
|
|
|
@ -3107,6 +3107,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
|||
prop,
|
||||
"MeshUVLoop (Deprecated)",
|
||||
"Deprecated, use 'uv', 'vertex_select', 'edge_select' or 'pin' properties instead");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3147,6 +3148,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "uv", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Float2AttributeValue");
|
||||
RNA_def_property_ui_text(prop, "UV", "UV coordinates on face corners");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_uv_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3161,6 +3163,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
|||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "UV Vertex Selection", "Selection state of the face corner the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_vert_select_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3175,6 +3178,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
|||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(
|
||||
prop, "UV Edge Selection", "Selection state of the edge in the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_edge_select_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3188,6 +3192,7 @@ static void rna_def_mloopuv(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "pin", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "BoolAttributeValue");
|
||||
RNA_def_property_ui_text(prop, "UV Pin", "UV pinned state in the UV editor");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshUVLoopLayer_pin_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3256,6 +3261,7 @@ static void rna_def_mloopcol(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshLoopColor");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshLoopColorLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3317,6 +3323,7 @@ static void rna_def_MPropCol(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshVertColor");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshVertColorLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -3362,6 +3369,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "FloatProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "FloatPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
|
@ -3405,6 +3413,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "IntProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "IntPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
|
@ -3447,6 +3456,7 @@ static void rna_def_mproperties(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE); \
|
||||
RNA_def_property_struct_type(prop, "Mesh" elemname "StringProperty"); \
|
||||
RNA_def_property_ui_text(prop, "Data", ""); \
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE); \
|
||||
RNA_def_property_collection_funcs(prop, \
|
||||
"rna_Mesh" elemname "StringPropertyLayer_data_begin", \
|
||||
"rna_iterator_array_next", \
|
||||
|
@ -3955,6 +3965,7 @@ static void rna_def_skin_vertices(BlenderRNA *brna, PropertyRNA *UNUSED(cprop))
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshSkinVertex");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshSkinVertexLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -4008,6 +4019,7 @@ static void rna_def_vertex_creases(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshVertexCrease");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshVertexCreaseLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
@ -4042,6 +4054,7 @@ static void rna_def_edge_creases(BlenderRNA *brna)
|
|||
prop = RNA_def_property(srna, "data", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "MeshEdgeCrease");
|
||||
RNA_def_property_ui_text(prop, "Data", "");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_MeshEdgeCreaseLayer_data_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
|
|
@ -177,6 +177,7 @@ static void rna_def_pointcloud(BlenderRNA *brna)
|
|||
/* geometry */
|
||||
prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "Point");
|
||||
RNA_def_property_override_flag(prop, PROPOVERRIDE_IGNORE);
|
||||
RNA_def_property_collection_funcs(prop,
|
||||
"rna_PointCloud_points_begin",
|
||||
"rna_iterator_array_next",
|
||||
|
|
|
@ -628,6 +628,11 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
|
|||
ICON_ORIENTATION_CURSOR,
|
||||
"Cursor",
|
||||
"Align the transformation axes to the 3D cursor"},
|
||||
{V3D_ORIENT_PARENT,
|
||||
"PARENT",
|
||||
ICON_BLANK1,
|
||||
"Parent",
|
||||
"Align the transformation axes to the object's parent space"},
|
||||
// {V3D_ORIENT_CUSTOM, "CUSTOM", 0, "Custom", "Use a custom transform orientation"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
|
|
@ -158,6 +158,12 @@ class StringBuilder : public SocketDeclarationBuilder<String> {
|
|||
class IDSocketDeclaration : public SocketDeclaration {
|
||||
public:
|
||||
const char *idname;
|
||||
/**
|
||||
* Get the default ID pointer for this socket. This is a function to avoid dangling pointers,
|
||||
* since bNode::id pointers are remapped as ID pointers change, but pointers in socket
|
||||
* declarations are not managed the same way.
|
||||
*/
|
||||
std::function<ID *(const bNode &node)> default_value_fn;
|
||||
|
||||
public:
|
||||
IDSocketDeclaration(const char *idname);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "DNA_pointcloud_types.h"
|
||||
|
||||
#include "BKE_attribute_math.hh"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_pointcloud.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
|
|
@ -124,7 +124,41 @@ bool nodeGroupPoll(const bNodeTree *nodetree,
|
|||
|
||||
namespace blender::nodes {
|
||||
|
||||
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &io_socket)
|
||||
static std::function<ID *(const bNode &node)> get_default_id_getter(const bNodeTree &ntree,
|
||||
const bNodeSocket &io_socket)
|
||||
{
|
||||
const int socket_index = io_socket.in_out == SOCK_IN ? BLI_findindex(&ntree.inputs, &io_socket) :
|
||||
BLI_findindex(&ntree.outputs, &io_socket);
|
||||
/* Avoid capturing pointers that can become dangling. */
|
||||
return [in_out = io_socket.in_out, socket_index](const bNode &node) -> ID * {
|
||||
if (node.id == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
if (GS(node.id->name) != ID_NT) {
|
||||
return nullptr;
|
||||
}
|
||||
const bNodeTree &ntree = *reinterpret_cast<const bNodeTree *>(node.id);
|
||||
const bNodeSocket *io_socket;
|
||||
if (in_out == SOCK_IN) {
|
||||
/* Better be safe than sorry when the underlying node group changed. */
|
||||
if (socket_index < ntree.interface_inputs().size()) {
|
||||
io_socket = ntree.interface_inputs()[socket_index];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (socket_index < ntree.interface_outputs().size()) {
|
||||
io_socket = ntree.interface_outputs()[socket_index];
|
||||
}
|
||||
}
|
||||
if (io_socket == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return *static_cast<ID **>(io_socket->default_value);
|
||||
};
|
||||
}
|
||||
|
||||
static SocketDeclarationPtr declaration_for_interface_socket(const bNodeTree &ntree,
|
||||
const bNodeSocket &io_socket)
|
||||
{
|
||||
SocketDeclarationPtr dst;
|
||||
switch (io_socket.type) {
|
||||
|
@ -184,24 +218,39 @@ static SocketDeclarationPtr declaration_for_interface_socket(const bNodeSocket &
|
|||
dst = std::move(decl);
|
||||
break;
|
||||
}
|
||||
case SOCK_OBJECT:
|
||||
dst = std::make_unique<decl::Object>();
|
||||
case SOCK_OBJECT: {
|
||||
auto value = std::make_unique<decl::Object>();
|
||||
value->default_value_fn = get_default_id_getter(ntree, io_socket);
|
||||
dst = std::move(value);
|
||||
break;
|
||||
case SOCK_IMAGE:
|
||||
dst = std::make_unique<decl::Image>();
|
||||
}
|
||||
case SOCK_IMAGE: {
|
||||
auto value = std::make_unique<decl::Image>();
|
||||
value->default_value_fn = get_default_id_getter(ntree, io_socket);
|
||||
dst = std::move(value);
|
||||
break;
|
||||
}
|
||||
case SOCK_GEOMETRY:
|
||||
dst = std::make_unique<decl::Geometry>();
|
||||
break;
|
||||
case SOCK_COLLECTION:
|
||||
dst = std::make_unique<decl::Collection>();
|
||||
case SOCK_COLLECTION: {
|
||||
auto value = std::make_unique<decl::Collection>();
|
||||
value->default_value_fn = get_default_id_getter(ntree, io_socket);
|
||||
dst = std::move(value);
|
||||
break;
|
||||
case SOCK_TEXTURE:
|
||||
dst = std::make_unique<decl::Texture>();
|
||||
}
|
||||
case SOCK_TEXTURE: {
|
||||
auto value = std::make_unique<decl::Texture>();
|
||||
value->default_value_fn = get_default_id_getter(ntree, io_socket);
|
||||
dst = std::move(value);
|
||||
break;
|
||||
case SOCK_MATERIAL:
|
||||
dst = std::make_unique<decl::Material>();
|
||||
}
|
||||
case SOCK_MATERIAL: {
|
||||
auto value = std::make_unique<decl::Material>();
|
||||
value->default_value_fn = get_default_id_getter(ntree, io_socket);
|
||||
dst = std::move(value);
|
||||
break;
|
||||
}
|
||||
case SOCK_CUSTOM:
|
||||
std::unique_ptr<decl::Custom> decl = std::make_unique<decl::Custom>();
|
||||
decl->idname_ = io_socket.idname;
|
||||
|
@ -232,10 +281,10 @@ void node_group_declare_dynamic(const bNodeTree & /*node_tree*/,
|
|||
r_declaration.skip_updating_sockets = false;
|
||||
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &group->inputs) {
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(*input));
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(*group, *input));
|
||||
}
|
||||
LISTBASE_FOREACH (const bNodeSocket *, output, &group->outputs) {
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(*output));
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(*group, *output));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,7 +499,7 @@ static void group_input_declare_dynamic(const bNodeTree &node_tree,
|
|||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.inputs) {
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(*input));
|
||||
r_declaration.outputs.append(declaration_for_interface_socket(node_tree, *input));
|
||||
r_declaration.outputs.last()->in_out = SOCK_OUT;
|
||||
}
|
||||
r_declaration.outputs.append(extend_declaration(SOCK_OUT));
|
||||
|
@ -461,7 +510,7 @@ static void group_output_declare_dynamic(const bNodeTree &node_tree,
|
|||
NodeDeclaration &r_declaration)
|
||||
{
|
||||
LISTBASE_FOREACH (const bNodeSocket *, input, &node_tree.outputs) {
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(*input));
|
||||
r_declaration.inputs.append(declaration_for_interface_socket(node_tree, *input));
|
||||
r_declaration.inputs.last()->in_out = SOCK_IN;
|
||||
}
|
||||
r_declaration.inputs.append(extend_declaration(SOCK_IN));
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "NOD_socket_declarations.hh"
|
||||
#include "NOD_socket_declarations_geometry.hh"
|
||||
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_node_runtime.hh"
|
||||
|
||||
|
@ -435,6 +436,13 @@ bNodeSocket &IDSocketDeclaration::build(bNodeTree &ntree, bNode &node) const
|
|||
{
|
||||
bNodeSocket &socket = *nodeAddSocket(
|
||||
&ntree, &node, this->in_out, this->idname, this->identifier.c_str(), this->name.c_str());
|
||||
if (this->default_value_fn) {
|
||||
ID *id = this->default_value_fn(node);
|
||||
/* Assumes that all ID sockets like #bNodeSocketValueObject and #bNodeSocketValueImage have the
|
||||
* ID pointer at the start of the struct. */
|
||||
*static_cast<ID **>(socket.default_value) = id;
|
||||
id_us_plus(id);
|
||||
}
|
||||
this->set_common_flags(socket);
|
||||
return socket;
|
||||
}
|
||||
|
|
|
@ -785,11 +785,11 @@ static PyObject *bpy_bmlayercollection_subscript_slice(BPy_BMLayerCollection *se
|
|||
|
||||
BPY_BM_CHECK_OBJ(self);
|
||||
|
||||
if (start >= len) {
|
||||
start = len - 1;
|
||||
if (start > len) {
|
||||
start = len;
|
||||
}
|
||||
if (stop >= len) {
|
||||
stop = len - 1;
|
||||
if (stop > len) {
|
||||
stop = len;
|
||||
}
|
||||
|
||||
tuple = PyTuple_New(stop - start);
|
||||
|
@ -915,7 +915,7 @@ static PyObject *bpy_bmlayercollection_iter(BPy_BMLayerCollection *self)
|
|||
|
||||
BPY_BM_CHECK_OBJ(self);
|
||||
|
||||
ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MIN);
|
||||
ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
|
||||
|
||||
if (ret) {
|
||||
iter = PyObject_GetIter(ret);
|
||||
|
|
|
@ -467,8 +467,6 @@ static void wm_init_userdef(Main *bmain)
|
|||
/* Not versioning, just avoid errors. */
|
||||
#ifndef WITH_CYCLES
|
||||
BKE_addon_remove_safe(&U.addons, "cycles");
|
||||
#else
|
||||
UNUSED_VARS(BKE_addon_remove_safe);
|
||||
#endif
|
||||
|
||||
UI_init_userdef();
|
||||
|
@ -1584,7 +1582,7 @@ static void wm_history_file_update(void)
|
|||
/* Write current file to #BLENDER_HISTORY_FILE. */
|
||||
wm_history_file_write();
|
||||
|
||||
/* also update most recent files on System */
|
||||
/* Also update most recent files on system. */
|
||||
GHOST_addToSystemRecentFiles(blendfile_path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue