Merge branch 'master' into sculpt-dev

This commit is contained in:
Pablo Dobarro 2021-01-15 19:47:28 +01:00
commit 58406eddb5
57 changed files with 1323 additions and 769 deletions

View File

@ -951,7 +951,7 @@ class CPUDevice : public Device {
SIMD_SET_FLUSH_TO_ZERO;
for (int sample = start_sample; sample < end_sample; sample++) {
if (task.get_cancel() || task_pool.canceled()) {
if (task.get_cancel() || TaskPool::canceled()) {
if (task.need_finish_queue == false)
break;
}
@ -1249,7 +1249,7 @@ class CPUDevice : public Device {
void thread_render(DeviceTask &task)
{
if (task_pool.canceled()) {
if (TaskPool::canceled()) {
if (task.need_finish_queue == false)
return;
}
@ -1319,7 +1319,7 @@ class CPUDevice : public Device {
task.release_tile(tile);
if (task_pool.canceled()) {
if (TaskPool::canceled()) {
if (task.need_finish_queue == false)
break;
}
@ -1416,7 +1416,7 @@ class CPUDevice : public Device {
task.offset,
sample);
if (task.get_cancel() || task_pool.canceled())
if (task.get_cancel() || TaskPool::canceled())
break;
task.update_progress(NULL);

View File

@ -27,6 +27,7 @@
#include <OSL/oslclosure.h>
#include <OSL/oslexec.h>
#include <OSL/rendererservices.h>
#ifdef WITH_PTEX
class PtexCache;

View File

@ -62,7 +62,7 @@ void TaskPool::cancel()
bool TaskPool::canceled()
{
return tbb_group.is_canceling();
return tbb::is_current_task_group_canceling();
}
/* Task Scheduler */

View File

@ -61,7 +61,7 @@ class TaskPool {
void wait_work(Summary *stats = NULL); /* work and wait until all tasks are done */
void cancel(); /* cancel all tasks and wait until they are no longer executing */
bool canceled(); /* for worker threads, test if canceled */
static bool canceled(); /* For worker threads, test if current task pool canceled. */
protected:
tbb::task_group tbb_group;

View File

@ -49,12 +49,6 @@ set(LIB
)
if(WIN32 AND NOT UNIX)
list(APPEND SRC
intern/mmap_win.c
mmap_win.h
)
list(APPEND INC_SYS
${PTHREADS_INC}
)

View File

@ -1,294 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup MEM
*/
#ifdef WIN32
# include <errno.h>
# include <io.h>
# include <stdio.h>
# include <sys/types.h>
# include <windows.h>
# include "mmap_win.h"
# ifndef FILE_MAP_EXECUTE
// not defined in earlier versions of the Platform SDK (before February 2003)
# define FILE_MAP_EXECUTE 0x0020
# endif
/* copied from BLI_utildefines.h, ugh */
# ifdef __GNUC__
# define UNUSED(x) UNUSED_##x __attribute__((__unused__))
# else
# define UNUSED(x) x
# endif
/* --------------------------------------------------------------------- */
/* local storage definitions */
/* --------------------------------------------------------------------- */
/* all memory mapped chunks are put in linked lists */
typedef struct mmapLink {
struct mmapLink *next, *prev;
} mmapLink;
typedef struct mmapListBase {
void *first, *last;
} mmapListBase;
typedef struct MemMap {
struct MemMap *next, *prev;
void *mmap;
HANDLE fhandle;
HANDLE maphandle;
} MemMap;
/* --------------------------------------------------------------------- */
/* local functions */
/* --------------------------------------------------------------------- */
static void mmap_addtail(volatile mmapListBase *listbase, void *vlink);
static void mmap_remlink(volatile mmapListBase *listbase, void *vlink);
static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr);
static int mmap_get_prot_flags(int flags);
static int mmap_get_access_flags(int flags);
/* --------------------------------------------------------------------- */
/* vars */
/* --------------------------------------------------------------------- */
volatile static struct mmapListBase _mmapbase;
volatile static struct mmapListBase *mmapbase = &_mmapbase;
/* --------------------------------------------------------------------- */
/* implementation */
/* --------------------------------------------------------------------- */
/* mmap for windows */
void *mmap(void *UNUSED(start), size_t len, int prot, int flags, int fd, off_t offset)
{
HANDLE fhandle = INVALID_HANDLE_VALUE;
HANDLE maphandle;
int prot_flags = mmap_get_prot_flags(prot);
int access_flags = mmap_get_access_flags(prot);
MemMap *mm = NULL;
void *ptr = NULL;
if (flags & MAP_FIXED) {
return MAP_FAILED;
}
# if 0
if (fd == -1) {
_set_errno(EBADF);
return MAP_FAILED;
}
# endif
if (fd != -1) {
fhandle = (HANDLE)_get_osfhandle(fd);
}
if (fhandle == INVALID_HANDLE_VALUE) {
if (!(flags & MAP_ANONYMOUS)) {
errno = EBADF;
return MAP_FAILED;
}
}
else {
if (!DuplicateHandle(GetCurrentProcess(),
fhandle,
GetCurrentProcess(),
&fhandle,
0,
FALSE,
DUPLICATE_SAME_ACCESS)) {
return MAP_FAILED;
}
}
/* Split 64 bit size into low and high bits. */
DWORD len_bits_high = len >> 32;
DWORD len_bits_low = len & 0xFFFFFFFF;
maphandle = CreateFileMapping(fhandle, NULL, prot_flags, len_bits_high, len_bits_low, NULL);
if (maphandle == 0) {
errno = EBADF;
return MAP_FAILED;
}
ptr = MapViewOfFile(maphandle, access_flags, 0, offset, 0);
if (ptr == NULL) {
DWORD dwLastErr = GetLastError();
if (dwLastErr == ERROR_MAPPED_ALIGNMENT) {
errno = EINVAL;
}
else {
errno = EACCES;
}
CloseHandle(maphandle);
return MAP_FAILED;
}
mm = (MemMap *)malloc(sizeof(MemMap));
if (!mm) {
errno = ENOMEM;
}
mm->fhandle = fhandle;
mm->maphandle = maphandle;
mm->mmap = ptr;
mmap_addtail(mmapbase, mm);
return ptr;
}
/* munmap for windows */
intptr_t munmap(void *ptr, size_t UNUSED(size))
{
MemMap *mm = mmap_findlink(mmapbase, ptr);
if (!mm) {
errno = EINVAL;
return -1;
}
UnmapViewOfFile(mm->mmap);
CloseHandle(mm->maphandle);
CloseHandle(mm->fhandle);
mmap_remlink(mmapbase, mm);
free(mm);
return 0;
}
/* --------------------------------------------------------------------- */
/* local functions */
/* --------------------------------------------------------------------- */
static void mmap_addtail(volatile mmapListBase *listbase, void *vlink)
{
struct mmapLink *link = vlink;
if (link == NULL) {
return;
}
if (listbase == NULL) {
return;
}
link->next = 0;
link->prev = listbase->last;
if (listbase->last) {
((struct mmapLink *)listbase->last)->next = link;
}
if (listbase->first == NULL) {
listbase->first = link;
}
listbase->last = link;
}
static void mmap_remlink(volatile mmapListBase *listbase, void *vlink)
{
struct mmapLink *link = vlink;
if (link == NULL) {
return;
}
if (listbase == NULL) {
return;
}
if (link->next) {
link->next->prev = link->prev;
}
if (link->prev) {
link->prev->next = link->next;
}
if (listbase->last == link) {
listbase->last = link->prev;
}
if (listbase->first == link) {
listbase->first = link->next;
}
}
static void *mmap_findlink(volatile mmapListBase *listbase, void *ptr)
{
MemMap *mm;
if (ptr == NULL) {
return NULL;
}
if (listbase == NULL) {
return NULL;
}
mm = (MemMap *)listbase->first;
while (mm) {
if (mm->mmap == ptr) {
return mm;
}
mm = mm->next;
}
return NULL;
}
static int mmap_get_prot_flags(int flags)
{
int prot = PAGE_NOACCESS;
if ((flags & PROT_READ) == PROT_READ) {
if ((flags & PROT_WRITE) == PROT_WRITE) {
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
}
else {
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_READONLY;
}
}
else if ((flags & PROT_WRITE) == PROT_WRITE) {
prot = (flags & PROT_EXEC) ? PAGE_EXECUTE_READ : PAGE_WRITECOPY;
}
else if ((flags & PROT_EXEC) == PROT_EXEC) {
prot = PAGE_EXECUTE_READ;
}
return prot;
}
static int mmap_get_access_flags(int flags)
{
int access = 0;
if ((flags & PROT_READ) == PROT_READ) {
if ((flags & PROT_WRITE) == PROT_WRITE) {
access = FILE_MAP_WRITE;
}
else {
access = (flags & PROT_EXEC) ? FILE_MAP_EXECUTE : FILE_MAP_READ;
}
}
else if ((flags & PROT_WRITE) == PROT_WRITE) {
access = FILE_MAP_COPY;
}
else if ((flags & PROT_EXEC) == PROT_EXEC) {
access = FILE_MAP_EXECUTE;
}
return access;
}
#endif // WIN32

View File

@ -1,50 +0,0 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup MEM
*/
#ifndef __MMAP_WIN_H__
#define __MMAP_WIN_H__
#define PROT_NONE 0
#define PROT_READ 1
#define PROT_WRITE 2
#define PROT_EXEC 4
#define MAP_FILE 0
#define MAP_SHARED 1
#define MAP_PRIVATE 2
#define MAP_TYPE 0xF
#define MAP_FIXED 0x10
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *)-1)
/* needed for uintptr_t, exception, dont use BLI anywhere else in MEM_* */
#include "../../source/blender/blenlib/BLI_sys_types.h"
#include <sys/types.h>
void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);
intptr_t munmap(void *ptr, size_t size);
#endif

View File

@ -678,16 +678,8 @@ class NODE_UL_interface_sockets(bpy.types.UIList):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
row = layout.row(align=True)
# inputs get icon on the left
if not socket.is_output:
row.template_node_socket(color=color)
row.template_node_socket(color=color)
row.prop(socket, "name", text="", emboss=False, icon_value=icon)
# outputs get icon on the right
if socket.is_output:
row.template_node_socket(color=color)
elif self.layout_type == 'GRID':
layout.alignment = 'CENTER'
layout.template_node_socket(color=color)

View File

@ -212,8 +212,7 @@ struct NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
const struct AnimationEvalContext *anim_eval_context,
const bool flush_to_original);
const struct AnimationEvalContext *anim_eval_context);
bool BKE_animsys_nla_remap_keyframe_values(struct NlaKeyframingContext *context,
struct PointerRNA *prop_ptr,
struct PropertyRNA *prop,

View File

@ -0,0 +1,94 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "BLI_color.hh"
#include "BLI_float2.hh"
#include "BLI_float3.hh"
#include "DNA_customdata_types.h"
namespace blender::attribute_math {
/**
* Utility function that simplifies calling a templated function based on a custom data type.
*/
template<typename Func>
void convert_to_static_type(const CustomDataType data_type, const Func &func)
{
switch (data_type) {
case CD_PROP_FLOAT:
func(float());
break;
case CD_PROP_FLOAT2:
func(float2());
break;
case CD_PROP_FLOAT3:
func(float3());
break;
case CD_PROP_INT32:
func(int());
break;
case CD_PROP_BOOL:
func(bool());
break;
case CD_PROP_COLOR:
func(Color4f());
break;
default:
BLI_assert(false);
break;
}
}
/* Interpolate between three values. */
template<typename T> T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2);
template<> inline bool mix3(const float3 &weights, const bool &v0, const bool &v1, const bool &v2)
{
return (weights.x * v0 + weights.y * v1 + weights.z * v2) >= 0.5f;
}
template<> inline int mix3(const float3 &weights, const int &v0, const int &v1, const int &v2)
{
return static_cast<int>(weights.x * v0 + weights.y * v1 + weights.z * v2);
}
template<>
inline float mix3(const float3 &weights, const float &v0, const float &v1, const float &v2)
{
return weights.x * v0 + weights.y * v1 + weights.z * v2;
}
template<>
inline float2 mix3(const float3 &weights, const float2 &v0, const float2 &v1, const float2 &v2)
{
return weights.x * v0 + weights.y * v1 + weights.z * v2;
}
template<>
inline float3 mix3(const float3 &weights, const float3 &v0, const float3 &v1, const float3 &v2)
{
return weights.x * v0 + weights.y * v1 + weights.z * v2;
}
template<>
inline Color4f mix3(const float3 &weights, const Color4f &v0, const Color4f &v1, const Color4f &v2)
{
Color4f result;
interp_v4_v4v4v4(result, v0, v1, v2, weights);
return result;
}
} // namespace blender::attribute_math

View File

@ -242,7 +242,8 @@ class GeometryComponent {
/**
* If an attribute with the given params exist, it is returned.
* If no attribute with the given name exists, it is created and returned.
* If no attribute with the given name exists, create it and
* fill it with the default value if it is provided.
* If an attribute with the given name but different domain or type exists, a temporary attribute
* is created that has to be saved after the output has been computed. This avoids deleting
* another attribute, before a computation is finished.
@ -251,7 +252,8 @@ class GeometryComponent {
*/
OutputAttributePtr attribute_try_get_for_output(const blender::StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type);
const CustomDataType data_type,
const void *default_value = nullptr);
};
template<typename T>

View File

@ -463,8 +463,8 @@ void ntreeSetOutput(struct bNodeTree *ntree);
void ntreeFreeCache(struct bNodeTree *ntree);
bool ntreeNodeExists(struct bNodeTree *ntree, struct bNode *testnode);
bool ntreeOutputExists(struct bNode *node, struct bNodeSocket *testsock);
bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode);
bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock);
void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable);
struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree);
void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree);
@ -501,7 +501,7 @@ struct bNodeSocket *ntreeInsertSocketInterfaceFromSocket(struct bNodeTree *ntree
struct bNodeSocket *from_sock);
void ntreeRemoveSocketInterface(struct bNodeTree *ntree, struct bNodeSocket *sock);
struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, int create);
struct StructRNA *ntreeInterfaceTypeGet(struct bNodeTree *ntree, bool create);
void ntreeInterfaceTypeFree(struct bNodeTree *ntree);
void ntreeInterfaceTypeUpdate(struct bNodeTree *ntree);
@ -624,12 +624,12 @@ struct bNodeLink *nodeAddLink(struct bNodeTree *ntree,
struct bNodeSocket *tosock);
void nodeRemLink(struct bNodeTree *ntree, struct bNodeLink *link);
void nodeRemSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
bool nodeLinkIsHidden(struct bNodeLink *link);
bool nodeLinkIsHidden(const struct bNodeLink *link);
void nodeInternalRelink(struct bNodeTree *ntree, struct bNode *node);
void nodeToView(struct bNode *node, float x, float y, float *rx, float *ry);
void nodeFromView(struct bNode *node, float x, float y, float *rx, float *ry);
bool nodeAttachNodeCheck(struct bNode *node, struct bNode *parent);
void nodeToView(const struct bNode *node, float x, float y, float *rx, float *ry);
void nodeFromView(const struct bNode *node, float x, float y, float *rx, float *ry);
bool nodeAttachNodeCheck(const struct bNode *node, const struct bNode *parent);
void nodeAttachNode(struct bNode *node, struct bNode *parent);
void nodeDetachNode(struct bNode *node);
@ -661,9 +661,9 @@ void nodeChainIterBackwards(const bNodeTree *ntree,
void nodeParentsIter(bNode *node, bool (*callback)(bNode *, void *), void *userdata);
struct bNodeLink *nodeFindLink(struct bNodeTree *ntree,
struct bNodeSocket *from,
struct bNodeSocket *to);
int nodeCountSocketLinks(struct bNodeTree *ntree, struct bNodeSocket *sock);
const struct bNodeSocket *from,
const struct bNodeSocket *to);
int nodeCountSocketLinks(const struct bNodeTree *ntree, const struct bNodeSocket *sock);
void nodeSetSelected(struct bNode *node, bool select);
void nodeSetActive(struct bNodeTree *ntree, struct bNode *node);
@ -678,11 +678,11 @@ void nodeUpdate(struct bNodeTree *ntree, struct bNode *node);
bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id);
void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
int nodeSocketIsHidden(struct bNodeSocket *sock);
int nodeSocketIsHidden(const struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
int nodeSocketLinkLimit(struct bNodeSocket *sock);
int nodeSocketLinkLimit(const struct bNodeSocket *sock);
/* Node Clipboard */
void BKE_node_clipboard_init(struct bNodeTree *ntree);
@ -767,7 +767,7 @@ BLI_INLINE bool BKE_node_instance_hash_iterator_done(bNodeInstanceHashIterator *
/* Node Previews */
int BKE_node_preview_used(struct bNode *node);
bool BKE_node_preview_used(const struct bNode *node);
bNodePreview *BKE_node_preview_verify(
struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create);
bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview);

View File

@ -275,6 +275,7 @@ set(SRC
BKE_asset.h
BKE_attribute.h
BKE_attribute_access.hh
BKE_attribute_math.hh
BKE_autoexec.h
BKE_blender.h
BKE_blender_copybuffer.h

View File

@ -362,6 +362,20 @@ void BKE_keyingsets_blend_read_expand(BlendExpander *expander, ListBase *list)
/* ***************************************** */
/* Evaluation Data-Setting Backend */
static bool is_fcurve_evaluatable(FCurve *fcu)
{
if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
return false;
}
if (fcu->grp != NULL && (fcu->grp->flag & AGRP_MUTED)) {
return false;
}
if (BKE_fcurve_is_empty(fcu)) {
return false;
}
return true;
}
bool BKE_animsys_store_rna_setting(PointerRNA *ptr,
/* typically 'fcu->rna_path', 'fcu->array_index' */
const char *rna_path,
@ -594,18 +608,11 @@ static void animsys_evaluate_fcurves(PointerRNA *ptr,
{
/* Calculate then execute each curve. */
LISTBASE_FOREACH (FCurve *, fcu, list) {
/* Check if this F-Curve doesn't belong to a muted group. */
if ((fcu->grp != NULL) && (fcu->grp->flag & AGRP_MUTED)) {
continue;
}
/* Check if this curve should be skipped. */
if ((fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED))) {
continue;
}
/* Skip empty curves, as if muted. */
if (BKE_fcurve_is_empty(fcu)) {
if (!is_fcurve_evaluatable(fcu)) {
continue;
}
PathResolvedRNA anim_rna;
if (BKE_animsys_store_rna_setting(ptr, fcu->rna_path, fcu->array_index, &anim_rna)) {
const float curval = calculate_fcurve(&anim_rna, fcu, anim_eval_context);
@ -979,6 +986,19 @@ NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list,
return nes;
}
static NlaEvalStrip *nlastrips_ctime_get_strip_single(
ListBase *dst_list,
NlaStrip *single_strip,
const AnimationEvalContext *anim_eval_context,
const bool flush_to_original)
{
ListBase single_tracks_list;
single_tracks_list.first = single_tracks_list.last = single_strip;
return nlastrips_ctime_get_strip(
dst_list, &single_tracks_list, -1, anim_eval_context, flush_to_original);
}
/* ---------------------- */
/* Initialize a valid mask, allocating memory if necessary. */
@ -1152,7 +1172,7 @@ static void nlaeval_snapshot_free_data(NlaEvalSnapshot *snapshot)
/* Free memory owned by this evaluation channel. */
static void nlaevalchan_free_data(NlaEvalChannel *nec)
{
nlavalidmask_free(&nec->valid);
nlavalidmask_free(&nec->domain);
if (nec->blend_snapshot != NULL) {
nlaevalchan_snapshot_free(nec->blend_snapshot);
@ -1353,7 +1373,7 @@ static NlaEvalChannel *nlaevalchan_verify_key(NlaEvalData *nlaeval,
nec->mix_mode = nlaevalchan_detect_mix_mode(key, length);
nlavalidmask_init(&nec->valid, length);
nlavalidmask_init(&nec->domain, length);
nec->base_snapshot.channel = nec;
nec->base_snapshot.length = length;
@ -1682,14 +1702,6 @@ static bool nlaeval_blend_value(NlaBlendData *blend,
return false;
}
if (nec->mix_mode == NEC_MIX_QUATERNION) {
/* For quaternion properties, always output all sub-channels. */
BLI_bitmap_set_all(nec->valid.ptr, true, 4);
}
else {
BLI_BITMAP_ENABLE(nec->valid.ptr, array_index);
}
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_ensure_channel(blend->snapshot, nec);
float *p_value = &nec_snapshot->values[array_index];
@ -1889,16 +1901,8 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
/* Evaluate all the F-Curves in the action,
* saving the relevant pointers to data that will need to be used. */
for (fcu = strip->act->curves.first; fcu; fcu = fcu->next) {
float value = 0.0f;
/* check if this curve should be skipped */
if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
continue;
}
if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) {
continue;
}
if (BKE_fcurve_is_empty(fcu)) {
if (!is_fcurve_evaluatable(fcu)) {
continue;
}
@ -1906,7 +1910,7 @@ static void nlastrip_evaluate_actionclip(PointerRNA *ptr,
* NOTE: we use the modified time here, since strip's F-Curve Modifiers
* are applied on top of this.
*/
value = evaluate_fcurve(fcu, evaltime);
float value = evaluate_fcurve(fcu, evaltime);
/* apply strip's F-Curve Modifiers on this value
* NOTE: we apply the strip's original evaluation time not the modified one
@ -2099,12 +2103,21 @@ void nladata_flush_channels(PointerRNA *ptr,
/* for each channel with accumulated values, write its value on the property it affects */
LISTBASE_FOREACH (NlaEvalChannel *, nec, &channels->channels) {
/**
* The bitmask is set for all channels touched by NLA due to the domain() function.
* Channels touched by current set of evaluated strips will have a snapshot channel directly
* from the evaluation snapshot.
*
* This function falls back to the default value if the snapshot channel doesn't exist.
* Thus channels, touched by NLA but not by the current set of evaluated strips, will be
* reset to default. If channel not touched by NLA then it's value is unchanged.
*/
NlaEvalChannelSnapshot *nec_snapshot = nlaeval_snapshot_find_channel(snapshot, nec);
PathResolvedRNA rna = {nec->key.ptr, nec->key.prop, -1};
for (int i = 0; i < nec_snapshot->length; i++) {
if (BLI_BITMAP_TEST(nec->valid.ptr, i)) {
if (BLI_BITMAP_TEST(nec->domain.ptr, i)) {
float value = nec_snapshot->values[i];
if (nec->is_array) {
rna.prop_index = i;
@ -2131,13 +2144,7 @@ static void nla_eval_domain_action(PointerRNA *ptr,
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
/* check if this curve should be skipped */
if (fcu->flag & (FCURVE_MUTED | FCURVE_DISABLED)) {
continue;
}
if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED)) {
continue;
}
if (BKE_fcurve_is_empty(fcu)) {
if (!is_fcurve_evaluatable(fcu)) {
continue;
}
@ -2146,14 +2153,14 @@ static void nla_eval_domain_action(PointerRNA *ptr,
if (nec != NULL) {
/* For quaternion properties, enable all sub-channels. */
if (nec->mix_mode == NEC_MIX_QUATERNION) {
BLI_bitmap_set_all(nec->valid.ptr, true, 4);
BLI_bitmap_set_all(nec->domain.ptr, true, 4);
continue;
}
int idx = nlaevalchan_validate_index(nec, fcu->array_index);
if (idx >= 0) {
BLI_BITMAP_ENABLE(nec->valid.ptr, idx);
BLI_BITMAP_ENABLE(nec->domain.ptr, idx);
}
}
}
@ -2212,177 +2219,226 @@ static void animsys_evaluate_nla_domain(PointerRNA *ptr, NlaEvalData *channels,
/* ---------------------- */
/** Tweaked strip is evaluated differently from other strips. Adjacent strips are ignored
* and includes a workaround for when user is not editing in place. */
static void animsys_create_tweak_strip(const AnimData *adt,
const bool keyframing_to_strip,
NlaStrip *r_tweak_strip)
{
/* Copy active strip so we can modify how it evaluates without affecting user data. */
memcpy(r_tweak_strip, adt->actstrip, sizeof(NlaStrip));
r_tweak_strip->next = r_tweak_strip->prev = NULL;
/* If tweaked strip is syncing action length, then evaluate using action length. */
if (r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
BKE_nlastrip_recalculate_bounds_sync_action(r_tweak_strip);
}
/* Strips with a user-defined time curve don't get properly remapped for editing
* at the moment, so mapping them just for display may be confusing. */
const bool is_inplace_tweak = !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
!(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
if (!is_inplace_tweak) {
/* Use Hold due to no proper remapping yet (the note above). */
r_tweak_strip->extendmode = NLASTRIP_EXTEND_HOLD;
/* Disable range. */
r_tweak_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
}
/** Controls whether able to keyframe outside range of tweaked strip. */
if (keyframing_to_strip) {
r_tweak_strip->extendmode = (is_inplace_tweak &&
!(r_tweak_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
NLASTRIP_EXTEND_NOTHING :
NLASTRIP_EXTEND_HOLD;
}
}
/** Action track and strip are associated with the non-pushed action. */
static void animsys_create_action_track_strip(const AnimData *adt,
const bool keyframing_to_strip,
NlaStrip *r_action_strip)
{
memset(r_action_strip, 0, sizeof(NlaStrip));
bAction *action = adt->action;
if ((adt->flag & ADT_NLA_EDIT_ON)) {
action = adt->tmpact;
}
/* Set settings of dummy NLA strip from AnimData settings. */
r_action_strip->act = action;
/* Action range is calculated taking F-Modifiers into account
* (which making new strips doesn't do due to the troublesome nature of that). */
calc_action_range(r_action_strip->act, &r_action_strip->actstart, &r_action_strip->actend, 1);
r_action_strip->start = r_action_strip->actstart;
r_action_strip->end = (IS_EQF(r_action_strip->actstart, r_action_strip->actend)) ?
(r_action_strip->actstart + 1.0f) :
(r_action_strip->actend);
r_action_strip->blendmode = adt->act_blendmode;
r_action_strip->extendmode = adt->act_extendmode;
r_action_strip->influence = adt->act_influence;
/* NOTE: must set this, or else the default setting overrides,
* and this setting doesn't work. */
r_action_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
/* Unless extendmode is Nothing (might be useful for flattening NLA evaluation), disable range.
* Extendmode Nothing and Hold will behave as normal. Hold Forward will behave just like Hold.
*/
if (r_action_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
r_action_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
}
const bool tweaking = (adt->flag & ADT_NLA_EDIT_ON) != 0;
const bool soloing = (adt->flag & ADT_NLA_SOLO_TRACK) != 0;
const bool actionstrip_evaluated = r_action_strip->act && !soloing && !tweaking;
if (!actionstrip_evaluated) {
r_action_strip->flag |= NLASTRIP_FLAG_MUTED;
}
/** If we're keyframing, then we must allow keyframing outside fcurve bounds. */
if (keyframing_to_strip) {
r_action_strip->extendmode = NLASTRIP_EXTEND_HOLD;
}
}
static bool is_nlatrack_evaluatable(const AnimData *adt, const NlaTrack *nlt)
{
/* Skip disabled tracks unless it contains the tweaked strip. */
const bool contains_tweak_strip = (adt->flag & ADT_NLA_EDIT_ON) &&
(nlt->index == adt->act_track->index);
if ((nlt->flag & NLATRACK_DISABLED) && !contains_tweak_strip) {
return false;
}
/* Solo and muting are mutually exclusive. */
if (adt->flag & ADT_NLA_SOLO_TRACK) {
/* Skip if there is a solo track, but this isn't it. */
if ((nlt->flag & NLATRACK_SOLO) == 0) {
return false;
}
}
else {
/* Skip track if muted. */
if (nlt->flag & NLATRACK_MUTED) {
return false;
}
}
return true;
}
/** Check for special case of non-pushed action being evaluated with no NLA influence (off and no
* strips evaluated) nor NLA interference (ensure NLA not soloing). */
static bool is_action_track_evaluated_without_nla(const AnimData *adt,
const bool any_strip_evaluated)
{
if (adt->action == NULL) {
return false;
}
if (any_strip_evaluated) {
return false;
}
/** NLA settings interference. */
if ((adt->flag & (ADT_NLA_SOLO_TRACK | ADT_NLA_EDIT_ON)) == 0) {
return false;
}
/** Allow action track to evaluate as if there isn't any NLA data. */
return true;
}
/** XXX Wayde Moss: BKE_nlatrack_find_tweaked() exists within nla.c, but it doesn't appear to
* work as expected. From animsys_evaluate_nla_for_flush(), it returns NULL in tweak mode. I'm not
* sure why. Preferably, it would be as simple as checking for (adt->act_Track == nlt) but that
* doesn't work either, neither does comparing indices.
*
* This function is a temporary work around. The first disabled track is always the tweaked track.
*/
static NlaTrack *nlatrack_find_tweaked(const AnimData *adt)
{
NlaTrack *nlt;
if (adt == NULL) {
return NULL;
}
/* Since the track itself gets disabled, we want the first disabled. */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
if (nlt->flag & NLATRACK_DISABLED) {
return nlt;
}
}
return NULL;
}
/**
* NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
*
* \param[out] echannels: Evaluation channels with calculated values
* \param[out] r_context: If not NULL,
* data about the currently edited strip is stored here and excluded from value calculation.
* \return false if NLA evaluation isn't actually applicable.
*/
static bool animsys_evaluate_nla(NlaEvalData *echannels,
PointerRNA *ptr,
AnimData *adt,
const AnimationEvalContext *anim_eval_context,
const bool flush_to_original,
NlaKeyframingContext *r_context)
static bool animsys_evaluate_nla_for_flush(NlaEvalData *echannels,
PointerRNA *ptr,
const AnimData *adt,
const AnimationEvalContext *anim_eval_context,
const bool flush_to_original)
{
NlaTrack *nlt;
short track_index = 0;
bool has_strips = false;
ListBase estrips = {NULL, NULL};
NlaEvalStrip *nes;
NlaStrip dummy_strip_buf;
/* dummy strip for active action */
NlaStrip *dummy_strip = r_context ? &r_context->strip : &dummy_strip_buf;
NlaStrip tweak_strip;
memset(dummy_strip, 0, sizeof(*dummy_strip));
NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
/* 1. get the stack of strips to evaluate at current time (influence calculated here) */
/* Get the stack of strips to evaluate at current time (influence calculated here). */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
/* stop here if tweaking is on and this strip is the tweaking track
* (it will be the first one that's 'disabled')... */
if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED)) {
break;
if (!is_nlatrack_evaluatable(adt, nlt)) {
continue;
}
/* solo and muting are mutually exclusive... */
if (adt->flag & ADT_NLA_SOLO_TRACK) {
/* skip if there is a solo track, but this isn't it */
if ((nlt->flag & NLATRACK_SOLO) == 0) {
continue;
}
/* else - mute doesn't matter */
}
else {
/* no solo tracks - skip track if muted */
if (nlt->flag & NLATRACK_MUTED) {
continue;
}
}
/* if this track has strips (but maybe they won't be suitable), set has_strips
* - used for mainly for still allowing normal action evaluation...
*/
if (nlt->strips.first) {
has_strips = true;
}
/* otherwise, get strip to evaluate for this channel */
nes = nlastrips_ctime_get_strip(
&estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
/** Append strip to evaluate for this track. */
if (nlt == tweaked_track) {
/** Tweaked strip is evaluated differently. */
animsys_create_tweak_strip(adt, false, &tweak_strip);
nes = nlastrips_ctime_get_strip_single(
&estrips, &tweak_strip, anim_eval_context, flush_to_original);
}
else {
nes = nlastrips_ctime_get_strip(
&estrips, &nlt->strips, track_index, anim_eval_context, flush_to_original);
}
if (nes) {
nes->track = nlt;
}
}
/* add 'active' Action (may be tweaking track) as last strip to evaluate in NLA stack
* - only do this if we're not exclusively evaluating the 'solo' NLA-track
* - however, if the 'solo' track houses the current 'tweaking' strip,
* then we should allow this to play, otherwise nothing happens
*/
if ((adt->action) && ((adt->flag & ADT_NLA_SOLO_TRACK) == 0 || (adt->flag & ADT_NLA_EDIT_ON))) {
/* if there are strips, evaluate action as per NLA rules */
if ((has_strips) || (adt->actstrip)) {
/* make dummy NLA strip, and add that to the stack */
ListBase dummy_trackslist;
dummy_trackslist.first = dummy_trackslist.last = dummy_strip;
/* Strips with a user-defined time curve don't get properly remapped for editing
* at the moment, so mapping them just for display may be confusing. */
bool is_inplace_tweak = (nlt) && !(adt->flag & ADT_NLA_EDIT_NOMAP) &&
!(adt->actstrip->flag & NLASTRIP_FLAG_USR_TIME);
if (is_inplace_tweak) {
/* edit active action in-place according to its active strip, so copy the data */
memcpy(dummy_strip, adt->actstrip, sizeof(NlaStrip));
/* Prevents nla eval from considering active strip's adj strips.
* For user, this means entering tweak mode on a strip ignores evaluating adjacent strips
* in the same track. */
dummy_strip->next = dummy_strip->prev = NULL;
/* If tweaked strip is syncing action length, then evaluate using action length. */
if (dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH) {
BKE_nlastrip_recalculate_bounds_sync_action(dummy_strip);
}
}
else {
/* set settings of dummy NLA strip from AnimData settings */
dummy_strip->act = adt->action;
/* action range is calculated taking F-Modifiers into account
* (which making new strips doesn't do due to the troublesome nature of that) */
calc_action_range(dummy_strip->act, &dummy_strip->actstart, &dummy_strip->actend, 1);
dummy_strip->start = dummy_strip->actstart;
dummy_strip->end = (IS_EQF(dummy_strip->actstart, dummy_strip->actend)) ?
(dummy_strip->actstart + 1.0f) :
(dummy_strip->actend);
/* Always use the blend mode of the strip in tweak mode, even if not in-place. */
if (nlt && adt->actstrip) {
dummy_strip->blendmode = adt->actstrip->blendmode;
dummy_strip->extendmode = NLASTRIP_EXTEND_HOLD;
}
else {
dummy_strip->blendmode = adt->act_blendmode;
dummy_strip->extendmode = adt->act_extendmode;
}
/* Unless extend-mode is Nothing (might be useful for flattening NLA evaluation),
* disable range. */
if (dummy_strip->extendmode != NLASTRIP_EXTEND_NOTHING) {
dummy_strip->flag |= NLASTRIP_FLAG_NO_TIME_MAP;
}
dummy_strip->influence = adt->act_influence;
/* NOTE: must set this, or else the default setting overrides,
* and this setting doesn't work. */
dummy_strip->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
}
/* add this to our list of evaluation strips */
if (r_context == NULL) {
nlastrips_ctime_get_strip(
&estrips, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
}
/* If computing the context for keyframing, store data there instead of the list. */
else {
/* The extend mode here effectively controls
* whether it is possible to key-frame beyond the ends.*/
dummy_strip->extendmode = (is_inplace_tweak &&
!(dummy_strip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) ?
NLASTRIP_EXTEND_NOTHING :
NLASTRIP_EXTEND_HOLD;
r_context->eval_strip = nes = nlastrips_ctime_get_strip(
NULL, &dummy_trackslist, -1, anim_eval_context, flush_to_original);
/* These setting combinations require no data from strips below, so exit immediately. */
if ((nes == NULL) ||
(dummy_strip->blendmode == NLASTRIP_MODE_REPLACE && dummy_strip->influence == 1.0f)) {
BLI_freelistN(&estrips);
return true;
}
}
}
else {
/* special case - evaluate as if there isn't any NLA data */
BLI_freelistN(&estrips);
return false;
}
if (is_action_track_evaluated_without_nla(adt, has_strips)) {
BLI_freelistN(&estrips);
return false;
}
/* only continue if there are strips to evaluate */
if (BLI_listbase_is_empty(&estrips)) {
return true;
}
NlaStrip action_strip = {0};
animsys_create_action_track_strip(adt, false, &action_strip);
nlastrips_ctime_get_strip_single(&estrips, &action_strip, anim_eval_context, flush_to_original);
/* 2. for each strip, evaluate then accumulate on top of existing channels,
* but don't set values yet. */
/* Per strip, evaluate and accumulate on top of existing channels. */
for (nes = estrips.first; nes; nes = nes->next) {
nlastrip_evaluate(ptr,
echannels,
@ -2393,11 +2449,116 @@ static bool animsys_evaluate_nla(NlaEvalData *echannels,
flush_to_original);
}
/* 3. free temporary evaluation data that's not used elsewhere */
/* Free temporary evaluation data that's not used elsewhere. */
BLI_freelistN(&estrips);
return true;
}
/** Lower blended values are calculated and accumulated into r_context->lower_eval_data. */
static void animsys_evaluate_nla_for_keyframing(PointerRNA *ptr,
const AnimData *adt,
const AnimationEvalContext *anim_eval_context,
NlaKeyframingContext *r_context)
{
if (!r_context) {
return;
}
/* Early out. If NLA track is soloing and tweaked action isn't it, then don't allow keyframe
* insertion. */
if (adt->flag & ADT_NLA_SOLO_TRACK) {
if (!(adt->act_track && (adt->act_track->flag & NLATRACK_SOLO))) {
r_context->eval_strip = NULL;
return;
}
}
NlaTrack *nlt;
short track_index = 0;
bool has_strips = false;
ListBase lower_estrips = {NULL, NULL};
NlaEvalStrip *nes;
NlaTrack *tweaked_track = nlatrack_find_tweaked(adt);
/* Get the lower stack of strips to evaluate at current time (influence calculated here). */
for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next, track_index++) {
if (!is_nlatrack_evaluatable(adt, nlt)) {
continue;
}
/* Tweaked strip effect should not be stored in any snapshot. */
if (nlt == tweaked_track) {
break;
}
if (nlt->strips.first) {
has_strips = true;
}
/* Get strip to evaluate for this channel. */
nes = nlastrips_ctime_get_strip(
&lower_estrips, &nlt->strips, track_index, anim_eval_context, false);
if (nes) {
nes->track = nlt;
}
}
/** Note: Although we early out, we can still keyframe to the non-pushed action since the
* keyframe remap function detects (r_context->strip.act == NULL) and will keyframe without
* remapping.
*/
if (is_action_track_evaluated_without_nla(adt, has_strips)) {
BLI_freelistN(&lower_estrips);
return;
}
/* Write r_context->eval_strip. */
if (adt->flag & ADT_NLA_EDIT_ON) {
NlaStrip *tweak_strip = &r_context->strip;
animsys_create_tweak_strip(adt, true, tweak_strip);
r_context->eval_strip = nlastrips_ctime_get_strip_single(
NULL, tweak_strip, anim_eval_context, false);
}
else {
NlaStrip *action_strip = &r_context->strip;
animsys_create_action_track_strip(adt, true, action_strip);
r_context->eval_strip = nlastrips_ctime_get_strip_single(
NULL, action_strip, anim_eval_context, false);
}
/* If NULL, then keyframing will fail. No need to do any more processing. */
if (!r_context->eval_strip) {
BLI_freelistN(&lower_estrips);
return;
}
/* If tweak strip is full REPLACE, then lower strips not needed. */
if (r_context->strip.blendmode == NLASTRIP_MODE_REPLACE &&
IS_EQF(r_context->strip.influence, 1.0f)) {
BLI_freelistN(&lower_estrips);
return;
}
/* For each strip, evaluate then accumulate on top of existing channels. */
for (nes = lower_estrips.first; nes; nes = nes->next) {
nlastrip_evaluate(ptr,
&r_context->lower_eval_data,
NULL,
nes,
&r_context->lower_eval_data.eval_snapshot,
anim_eval_context,
false);
}
/* Free temporary evaluation data that's not used elsewhere. */
BLI_freelistN(&lower_estrips);
}
/* NLA Evaluation function (mostly for use through do_animdata)
* - All channels that will be affected are not cleared anymore. Instead, we just evaluate into
* some temp channels, where values can be accumulated in one go.
@ -2412,7 +2573,7 @@ static void animsys_calculate_nla(PointerRNA *ptr,
nlaeval_init(&echannels);
/* evaluate the NLA stack, obtaining a set of values to flush */
if (animsys_evaluate_nla(&echannels, ptr, adt, anim_eval_context, flush_to_original, NULL)) {
if (animsys_evaluate_nla_for_flush(&echannels, ptr, adt, anim_eval_context, flush_to_original)) {
/* reset any channels touched by currently inactive actions to default value */
animsys_evaluate_nla_domain(ptr, &echannels, adt);
@ -2448,8 +2609,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
struct ListBase *cache,
struct PointerRNA *ptr,
struct AnimData *adt,
const AnimationEvalContext *anim_eval_context,
const bool flush_to_original)
const AnimationEvalContext *anim_eval_context)
{
/* No remapping needed if NLA is off or no action. */
if ((adt == NULL) || (adt->action == NULL) || (adt->nla_tracks.first == NULL) ||
@ -2472,8 +2632,7 @@ NlaKeyframingContext *BKE_animsys_get_nla_keyframing_context(
ctx->adt = adt;
nlaeval_init(&ctx->lower_eval_data);
animsys_evaluate_nla(
&ctx->lower_eval_data, ptr, adt, anim_eval_context, flush_to_original, ctx);
animsys_evaluate_nla_for_keyframing(ptr, adt, anim_eval_context, ctx);
BLI_assert(ELEM(ctx->strip.act, NULL, adt->action));
BLI_addtail(cache, ctx);

View File

@ -526,6 +526,10 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom
case CD_PROP_BOOL:
return std::make_unique<ArrayReadAttribute<bool>>(
domain, Span(static_cast<bool *>(layer.data), size));
case CD_MLOOPUV:
auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, decltype(get_uv)>>(
domain, Span(static_cast<MLoopUV *>(layer.data), size), get_uv);
}
}
}
@ -570,6 +574,12 @@ static WriteAttributePtr write_attribute_from_custom_data(
case CD_PROP_BOOL:
return std::make_unique<ArrayWriteAttribute<bool>>(
domain, MutableSpan(static_cast<bool *>(layer.data), size));
case CD_MLOOPUV:
auto get_uv = [](const MLoopUV &uv) { return float2(uv.uv); };
auto set_uv = [](MLoopUV &uv, const float2 value) { copy_v2_v2(uv.uv, value); };
return std::make_unique<
DerivedArrayWriteAttribute<MLoopUV, float2, decltype(get_uv), decltype(set_uv)>>(
domain, MutableSpan(static_cast<MLoopUV *>(layer.data), size), get_uv, set_uv);
}
}
}
@ -597,8 +607,9 @@ static void get_custom_data_layer_attribute_names(const CustomData &custom_data,
Set<std::string> &r_names)
{
for (const CustomDataLayer &layer : blender::Span(custom_data.layers, custom_data.totlayer)) {
if (component.attribute_domain_with_type_supported(domain,
static_cast<CustomDataType>(layer.type))) {
const CustomDataType data_type = static_cast<CustomDataType>(layer.type);
if (component.attribute_domain_with_type_supported(domain, data_type) ||
ELEM(data_type, CD_MLOOPUV)) {
r_names.add(layer.name);
}
}
@ -814,7 +825,8 @@ blender::bke::ReadAttributePtr GeometryComponent::attribute_get_constant_for_rea
OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringRef attribute_name,
const AttributeDomain domain,
const CustomDataType data_type)
const CustomDataType data_type,
const void *default_value)
{
BLI_assert(this->attribute_domain_with_type_supported(domain, data_type));
@ -827,6 +839,11 @@ OutputAttributePtr GeometryComponent::attribute_try_get_for_output(const StringR
if (!attribute) {
this->attribute_try_create(attribute_name, domain, data_type);
attribute = this->attribute_try_get_for_write(attribute_name);
if (default_value != nullptr) {
void *data = attribute->get_span_for_write_only().data();
cpp_type->fill_initialized(default_value, data, attribute->size());
attribute->apply_span();
}
return OutputAttributePtr(std::move(attribute));
}
@ -1307,7 +1324,7 @@ Set<std::string> MeshComponent::attribute_names() const
for (StringRef name : vertex_group_names_.keys()) {
names.add(name);
}
get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_CORNER, names);
get_custom_data_layer_attribute_names(mesh_->ldata, *this, ATTR_DOMAIN_CORNER, names);
get_custom_data_layer_attribute_names(mesh_->vdata, *this, ATTR_DOMAIN_POINT, names);
get_custom_data_layer_attribute_names(mesh_->edata, *this, ATTR_DOMAIN_EDGE, names);
get_custom_data_layer_attribute_names(mesh_->pdata, *this, ATTR_DOMAIN_POLYGON, names);

View File

@ -1261,10 +1261,17 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori
/* We may need our own flag to control that at some point, but for now 'no main' one should be
* good enough. */
if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0 && ID_IS_OVERRIDE_LIBRARY(id)) {
/* We do not want to copy existing override rules here, as they would break the proper
* remapping between IDs. Proper overrides rules will be re-generated anyway. */
BKE_lib_override_library_copy(new_id, id, false);
if ((orig_flag & LIB_ID_CREATE_NO_MAIN) == 0) {
if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
/* We do not want to copy existing override rules here, as they would break the proper
* remapping between IDs. Proper overrides rules will be re-generated anyway. */
BKE_lib_override_library_copy(new_id, id, false);
}
else if (ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id)) {
/* Just ensure virtual overrides do get properly tagged, there is not actual override data to
* copy here. */
new_id->flag |= LIB_EMBEDDED_DATA_LIB_OVERRIDE;
}
}
if (id_can_have_animdata(new_id)) {

View File

@ -1922,7 +1922,9 @@ ID *BKE_lib_override_library_operations_store_start(Main *bmain,
ID *local)
{
if (ID_IS_OVERRIDE_LIBRARY_TEMPLATE(local) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(local)) {
/* This is actually purely local data with an override template, nothing to do here! */
/* This is actually purely local data with an override template, or one of those embedded IDs
* (root node trees, master collections or shapekeys) that cannot have their own override.
* Nothing to do here! */
return NULL;
}

View File

@ -2149,7 +2149,7 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
ntree->update |= NTREE_UPDATE_LINKS;
}
bool nodeLinkIsHidden(bNodeLink *link)
bool nodeLinkIsHidden(const bNodeLink *link)
{
return nodeSocketIsHidden(link->fromsock) || nodeSocketIsHidden(link->tosock);
}
@ -2200,7 +2200,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node)
}
}
void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
void nodeToView(const bNode *node, float x, float y, float *rx, float *ry)
{
if (node->parent) {
nodeToView(node->parent, x + node->locx, y + node->locy, rx, ry);
@ -2211,7 +2211,7 @@ void nodeToView(bNode *node, float x, float y, float *rx, float *ry)
}
}
void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
void nodeFromView(const bNode *node, float x, float y, float *rx, float *ry)
{
if (node->parent) {
nodeFromView(node->parent, x, y, rx, ry);
@ -2224,10 +2224,10 @@ void nodeFromView(bNode *node, float x, float y, float *rx, float *ry)
}
}
bool nodeAttachNodeCheck(bNode *node, bNode *parent)
bool nodeAttachNodeCheck(const bNode *node, const bNode *parent)
{
for (bNode *parent_recurse = node; parent_recurse; parent_recurse = parent_recurse->parent) {
if (parent_recurse == parent) {
for (const bNode *parent_iter = node; parent_iter; parent_iter = parent_iter->parent) {
if (parent_iter == parent) {
return true;
}
}
@ -2317,8 +2317,6 @@ void nodePositionPropagate(bNode *node)
bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
{
bNodeTree *ntree;
/* trees are created as local trees for compositor, material or texture nodes,
* node groups and other tree types are created as library data.
*/
@ -2327,7 +2325,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname)
if (is_embedded) {
flag |= LIB_ID_CREATE_NO_MAIN;
}
ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag);
bNodeTree *ntree = BKE_libblock_alloc(bmain, ID_NT, name, flag);
if (is_embedded) {
ntree->id.flag |= LIB_EMBEDDED_DATA;
}
@ -2362,7 +2360,7 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree)
* using BKE_node_preview_init_tree to set up previews for a whole node tree in advance.
* This should be left more to the individual node tree implementations.
*/
int BKE_node_preview_used(bNode *node)
bool BKE_node_preview_used(const bNode *node)
{
/* XXX check for closed nodes? */
return (node->typeinfo->flag & NODE_PREVIEW) != 0;
@ -2959,9 +2957,9 @@ ID *BKE_node_tree_find_owner_ID(Main *bmain, struct bNodeTree *ntree)
return NULL;
}
bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode)
{
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) {
if (node == testnode) {
return true;
}
@ -2969,9 +2967,9 @@ bool ntreeNodeExists(bNodeTree *ntree, bNode *testnode)
return false;
}
bool ntreeOutputExists(bNode *node, bNodeSocket *testsock)
bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock)
{
LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) {
LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) {
if (sock == testsock) {
return true;
}
@ -3246,7 +3244,7 @@ static void ntree_interface_type_create(bNodeTree *ntree)
}
}
StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, bool create)
{
if (ntree->interface_type) {
/* strings are generated from base string + ID name, sizes are sufficient */
@ -3333,7 +3331,7 @@ bool ntreeHasTree(const bNodeTree *ntree, const bNodeTree *lookup)
return false;
}
bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
bNodeLink *nodeFindLink(bNodeTree *ntree, const bNodeSocket *from, const bNodeSocket *to)
{
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
if (link->fromsock == from && link->tosock == to) {
@ -3346,10 +3344,10 @@ bNodeLink *nodeFindLink(bNodeTree *ntree, bNodeSocket *from, bNodeSocket *to)
return NULL;
}
int nodeCountSocketLinks(bNodeTree *ntree, bNodeSocket *sock)
int nodeCountSocketLinks(const bNodeTree *ntree, const bNodeSocket *sock)
{
int tot = 0;
LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) {
LISTBASE_FOREACH (const bNodeLink *, link, &ntree->links) {
if (link->fromsock == sock || link->tosock == sock) {
tot++;
}
@ -3515,7 +3513,7 @@ void nodeSetActive(bNodeTree *ntree, bNode *node)
}
}
int nodeSocketIsHidden(bNodeSocket *sock)
int nodeSocketIsHidden(const bNodeSocket *sock)
{
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
@ -3530,7 +3528,7 @@ void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
}
}
int nodeSocketLinkLimit(struct bNodeSocket *sock)
int nodeSocketLinkLimit(const bNodeSocket *sock)
{
bNodeSocketType *stype = sock->typeinfo;
if (stype != NULL && stype->use_link_limits_of_type) {

View File

@ -112,8 +112,8 @@ typedef struct NlaEvalChannel {
struct NlaEvalChannel *next_blend;
NlaEvalChannelSnapshot *blend_snapshot;
/* Mask of array items controlled by NLA. */
NlaValidMask valid;
/* Associated with the RNA property's value(s), marks which elements are affected by NLA. */
NlaValidMask domain;
/* Base set of values. */
NlaEvalChannelSnapshot base_snapshot;

View File

@ -29,6 +29,14 @@ struct float2 {
{
}
explicit float2(float value) : x(value), y(value)
{
}
explicit float2(int value) : x(value), y(value)
{
}
float2(float x, float y) : x(x), y(y)
{
}
@ -52,6 +60,11 @@ struct float2 {
return len_v2(*this);
}
float length_squared() const
{
return len_squared_v2(*this);
}
float2 &operator+=(const float2 &other)
{
x += other.x;

View File

@ -0,0 +1,56 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
* All rights reserved.
*/
#pragma once
/** \file
* \ingroup bli
*/
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Memory-mapped file IO that implements all the OS-specific details and error handling. */
struct BLI_mmap_file;
typedef struct BLI_mmap_file BLI_mmap_file;
/* Prepares an opened file for memory-mapped IO.
* May return NULL if the operation fails.
* Note that this seeks to the end of the file to determine its length. */
BLI_mmap_file *BLI_mmap_open(int fd) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
/* Reads length bytes from file at the given offset into dest.
* Returns whether the operation was successful (may fail when reading beyond the file
* end or when IO errors occur). */
bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void *BLI_mmap_get_pointer(BLI_mmap_file *file) ATTR_WARN_UNUSED_RESULT;
void BLI_mmap_free(BLI_mmap_file *file) ATTR_NONNULL(1);
#ifdef __cplusplus
}
#endif

View File

@ -105,8 +105,10 @@ void BLI_task_pool_work_and_wait(TaskPool *pool);
/* cancel all tasks, keep worker threads running */
void BLI_task_pool_cancel(TaskPool *pool);
/* for worker threads, test if canceled */
bool BLI_task_pool_canceled(TaskPool *pool);
/* for worker threads, test if current task pool canceled. this function may
* only be called from worker threads and pool must be the task pool that the
* thread is currently executing a task from. */
bool BLI_task_pool_current_canceled(TaskPool *pool);
/* optional userdata pointer to pass along to run function */
void *BLI_task_pool_user_data(TaskPool *pool);

View File

@ -54,6 +54,7 @@ set(SRC
intern/BLI_memblock.c
intern/BLI_memiter.c
intern/BLI_mempool.c
intern/BLI_mmap.c
intern/BLI_timer.c
intern/DLRB_tree.c
intern/array_store.c
@ -243,6 +244,7 @@ set(SRC
BLI_mempool.h
BLI_mesh_boolean.hh
BLI_mesh_intersect.hh
BLI_mmap.h
BLI_mpq2.hh
BLI_mpq3.hh
BLI_multi_value_map.hh

View File

@ -0,0 +1,233 @@
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2020 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup bli
*/
#include "BLI_mmap.h"
#include "BLI_fileops.h"
#include "BLI_listbase.h"
#include "MEM_guardedalloc.h"
#include <string.h>
#ifndef WIN32
# include <stdlib.h>
# include <signal.h>
# include <sys/mman.h> // for mmap
# include <unistd.h> // for read close
#else
# include "BLI_winstuff.h"
# include <io.h> // for open close read
#endif
struct BLI_mmap_file {
/* The address to which the file was mapped. */
char *memory;
/* The length of the file (and therefore the mapped region). */
size_t length;
/* Platform-specific handle for the mapping. */
void *handle;
/* Flag to indicate IO errors. Needs to be volatile since it's being set from
* within the signal handler, which is not part of the normal execution flow. */
volatile bool io_error;
};
#ifndef WIN32
/* When using memory-mapped files, any IO errors will result in a SIGBUS signal.
* Therefore, we need to catch that signal and stop reading the file in question.
* To do so, we keep a list of all current FileDatas that use memory-mapped files,
* and if a SIGBUS is caught, we check if the failed address is inside one of the
* mapped regions.
* If it is, we set a flag to indicate a failed read and remap the memory in
* question to a zero-backed region in order to avoid additional signals.
* The code that actually reads the memory area has to check whether the flag was
* set after it's done reading.
* If the error occurred outside of a memory-mapped region, we call the previous
* handler if one was configured and abort the process otherwise.
*/
struct error_handler_data {
ListBase open_mmaps;
char configured;
void (*next_handler)(int, siginfo_t *, void *);
} error_handler = {0};
static void sigbus_handler(int sig, siginfo_t *siginfo, void *ptr)
{
/* We only handle SIGBUS here for now. */
BLI_assert(sig == SIGBUS);
char *error_addr = (char *)siginfo->si_addr;
/* Find the file that this error belongs to. */
LISTBASE_FOREACH (LinkData *, link, &error_handler.open_mmaps) {
BLI_mmap_file *file = link->data;
/* Is the address where the error occurred in this file's mapped range? */
if (error_addr >= file->memory && error_addr < file->memory + file->length) {
file->io_error = true;
/* Replace the mapped memory with zeroes. */
mmap(file->memory, file->length, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
return;
}
}
/* Fall back to other handler if there was one. */
if (error_handler.next_handler) {
error_handler.next_handler(sig, siginfo, ptr);
}
else {
fprintf(stderr, "Unhandled SIGBUS caught\n");
abort();
}
}
/* Ensures that the error handler is set up and ready. */
static bool sigbus_handler_setup(void)
{
if (!error_handler.configured) {
struct sigaction newact = {0}, oldact = {0};
newact.sa_sigaction = sigbus_handler;
newact.sa_flags = SA_SIGINFO;
if (sigaction(SIGBUS, &newact, &oldact)) {
return false;
}
/* Remember the previously configured handler to fall back to it if the error
* does not belong to any of the mapped files. */
error_handler.next_handler = oldact.sa_sigaction;
error_handler.configured = 1;
}
return true;
}
/* Adds a file to the list that the error handler checks. */
static void sigbus_handler_add(BLI_mmap_file *file)
{
BLI_addtail(&error_handler.open_mmaps, BLI_genericNodeN(file));
}
/* Removes a file from the list that the error handler checks. */
static void sigbus_handler_remove(BLI_mmap_file *file)
{
LinkData *link = BLI_findptr(&error_handler.open_mmaps, file, offsetof(LinkData, data));
BLI_freelinkN(&error_handler.open_mmaps, link);
}
#endif
BLI_mmap_file *BLI_mmap_open(int fd)
{
void *memory, *handle = NULL;
size_t length = BLI_lseek(fd, 0, SEEK_END);
#ifndef WIN32
/* Ensure that the SIGBUS handler is configured. */
if (!sigbus_handler_setup()) {
return NULL;
}
/* Map the given file to memory. */
memory = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (memory == MAP_FAILED) {
return NULL;
}
#else
/* Convert the POSIX-style file descriptor to a Windows handle. */
void *file_handle = (void *)_get_osfhandle(fd);
/* Memory mapping on Windows is a two-step process - first we create a mapping,
* then we create a view into that mapping.
* In our case, one view that spans the entire file is enough. */
handle = CreateFileMapping(file_handle, NULL, PAGE_READONLY, 0, 0, NULL);
if (handle == NULL) {
return NULL;
}
memory = MapViewOfFile(handle, FILE_MAP_READ, 0, 0, 0);
if (memory == NULL) {
CloseHandle(handle);
return NULL;
}
#endif
/* Now that the mapping was successful, allocate memory and set up the BLI_mmap_file. */
BLI_mmap_file *file = MEM_callocN(sizeof(BLI_mmap_file), __func__);
file->memory = memory;
file->handle = handle;
file->length = length;
#ifndef WIN32
/* Register the file with the error handler. */
sigbus_handler_add(file);
#endif
return file;
}
bool BLI_mmap_read(BLI_mmap_file *file, void *dest, size_t offset, size_t length)
{
/* If a previous read has already failed or we try to read past the end,
* don't even attempt to read any further. */
if (file->io_error || (offset + length > file->length)) {
return false;
}
#ifndef WIN32
/* If an error occurs in this call, sigbus_handler will be called and will set
* file->io_error to true. */
memcpy(dest, file->memory + offset, length);
#else
/* On Windows, we use exception handling to be notified of errors. */
__try {
memcpy(dest, file->memory + offset, length);
}
__except (GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER :
EXCEPTION_CONTINUE_SEARCH) {
file->io_error = true;
return false;
}
#endif
return !file->io_error;
}
void *BLI_mmap_get_pointer(BLI_mmap_file *file)
{
return file->memory;
}
void BLI_mmap_free(BLI_mmap_file *file)
{
#ifndef WIN32
munmap((void *)file->memory, file->length);
sigbus_handler_remove(file);
#else
UnmapViewOfFile(file->memory);
CloseHandle(file->handle);
#endif
MEM_freeN(file);
}

View File

@ -6295,7 +6295,7 @@ float geodesic_distance_propagate_across_triangle(
}
}
/* Fall back to Dijsktra approximaton in trivial case, or if no valid source
/* Fall back to Dijsktra approximation in trivial case, or if no valid source
* point found that connects to v0 across the triangle. */
return min_ff(dist1 + len_v3(v10), dist2 + len_v3v3(v0, v2));
}

View File

@ -268,7 +268,7 @@ static bool tbb_task_pool_canceled(TaskPool *pool)
{
#ifdef WITH_TBB
if (pool->use_threads) {
return pool->tbb_group.is_canceling();
return tbb::is_current_task_group_canceling();
}
#else
UNUSED_VARS(pool);
@ -520,7 +520,7 @@ void BLI_task_pool_cancel(TaskPool *pool)
}
}
bool BLI_task_pool_canceled(TaskPool *pool)
bool BLI_task_pool_current_canceled(TaskPool *pool)
{
switch (pool->type) {
case TASK_POOL_TBB:

View File

@ -68,6 +68,7 @@
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_mempool.h"
#include "BLI_mmap.h"
#include "BLI_threads.h"
#include "BLT_translation.h"
@ -1179,6 +1180,53 @@ static ssize_t fd_read_from_memory(FileData *filedata,
return readsize;
}
/* Memory-mapped file reading.
* By using mmap(), we can map a file so that it can be treated like normal memory,
* meaning that we can just read from it with memcpy() etc.
* This avoids system call overhead and can significantly speed up file loading.
*/
static ssize_t fd_read_from_mmap(FileData *filedata,
void *buffer,
size_t size,
bool *UNUSED(r_is_memchunck_identical))
{
/* don't read more bytes than there are available in the buffer */
size_t readsize = MIN2(size, (size_t)(filedata->buffersize - filedata->file_offset));
if (!BLI_mmap_read(filedata->mmap_file, buffer, filedata->file_offset, readsize)) {
return 0;
}
filedata->file_offset += readsize;
return readsize;
}
static off64_t fd_seek_from_mmap(FileData *filedata, off64_t offset, int whence)
{
off64_t new_pos;
if (whence == SEEK_CUR) {
new_pos = filedata->file_offset + offset;
}
else if (whence == SEEK_SET) {
new_pos = offset;
}
else if (whence == SEEK_END) {
new_pos = filedata->buffersize + offset;
}
else {
return -1;
}
if (new_pos < 0 || new_pos > filedata->buffersize) {
return -1;
}
filedata->file_offset = new_pos;
return filedata->file_offset;
}
/* MemFile reading. */
static ssize_t fd_read_from_memfile(FileData *filedata,
@ -1306,6 +1354,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
{
FileDataReadFn *read_fn = NULL;
FileDataSeekFn *seek_fn = NULL; /* Optional. */
size_t buffersize = 0;
BLI_mmap_file *mmap_file = NULL;
gzFile gzfile = (gzFile)Z_NULL;
@ -1322,14 +1372,21 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
return NULL;
}
BLI_lseek(file, 0, SEEK_SET);
/* Regular file. */
if (memcmp(header, "BLENDER", sizeof(header)) == 0) {
read_fn = fd_read_data_from_file;
seek_fn = fd_seek_data_from_file;
mmap_file = BLI_mmap_open(file);
if (mmap_file != NULL) {
read_fn = fd_read_from_mmap;
seek_fn = fd_seek_from_mmap;
buffersize = BLI_lseek(file, 0, SEEK_END);
}
}
BLI_lseek(file, 0, SEEK_SET);
/* Gzip file. */
errno = 0;
if ((read_fn == NULL) &&
@ -1363,6 +1420,8 @@ static FileData *blo_filedata_from_file_descriptor(const char *filepath,
fd->read = read_fn;
fd->seek = seek_fn;
fd->mmap_file = mmap_file;
fd->buffersize = buffersize;
return fd;
}
@ -1531,6 +1590,11 @@ void blo_filedata_free(FileData *fd)
fd->buffer = NULL;
}
if (fd->mmap_file) {
BLI_mmap_free(fd->mmap_file);
fd->mmap_file = NULL;
}
/* Free all BHeadN data blocks */
#ifndef NDEBUG
BLI_freelistN(&fd->bhead_list);

View File

@ -41,6 +41,7 @@ struct Object;
struct OldNewMap;
struct ReportList;
struct UserDef;
struct BLI_mmap_file;
typedef struct IDNameLib_Map IDNameLib_Map;
@ -83,8 +84,9 @@ typedef struct FileData {
/** Regular file reading. */
int filedes;
/** Variables needed for reading from memory / stream. */
/** Variables needed for reading from memory / stream / memory-mapped files. */
const char *buffer;
struct BLI_mmap_file *mmap_file;
/** Variables needed for reading from memfile (undo). */
struct MemFile *memfile;
/** Whether we are undoing (< 0) or redoing (> 0), used to choose which 'unchanged' flag to use

View File

@ -55,7 +55,7 @@ class BokehImageOperation : public NodeOperation {
NodeBokehImage *m_data;
/**
* \brief precalced center of the image
* \brief precalculate center of the image
*/
float m_center[2];
@ -87,7 +87,7 @@ class BokehImageOperation : public NodeOperation {
/**
* \brief determine the coordinate of a flap corner.
*
* \param r: result in bokehimage space are stored [x,y]
* \param r: result in bokeh-image space are stored [x,y]
* \param flapNumber: the flap number to calculate
* \param distance: the lens distance is used to simulate lens shifts
*/

View File

@ -39,7 +39,7 @@ void DotproductOperation::deinitExecution()
this->m_input2Operation = nullptr;
}
/** \todo: current implementation is the inverse of a dotproduct. not 'logically' correct
/** \todo current implementation is the inverse of a dot-product. not 'logically' correct
*/
void DotproductOperation::executePixelSampled(float output[4],
float x,

View File

@ -4710,7 +4710,7 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
(float)CFRA);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, adt, &anim_eval_context, false);
&nla_cache, &id_ptr, adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
@ -4766,7 +4766,7 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
const AnimationEvalContext anim_eval_context = BKE_animsys_eval_context_construct(depsgraph,
(float)CFRA);
NlaKeyframingContext *nla_context = BKE_animsys_get_nla_keyframing_context(
&nla_cache, &id_ptr, key->adt, &anim_eval_context, false);
&nla_cache, &id_ptr, key->adt, &anim_eval_context);
/* get current frame and apply NLA-mapping to it (if applicable) */
const float remapped_frame = BKE_nla_tweakedit_remap(

View File

@ -1384,7 +1384,7 @@ static AnimationEvalContext nla_time_remap(const AnimationEvalContext *anim_eval
if (adt && adt->action == act) {
/* Get NLA context for value remapping. */
*r_nla_context = BKE_animsys_get_nla_keyframing_context(
nla_cache, id_ptr, adt, anim_eval_context, false);
nla_cache, id_ptr, adt, anim_eval_context);
/* Apply NLA-mapping to frame. */
const float remapped_frame = BKE_nla_tweakedit_remap(

View File

@ -231,7 +231,7 @@ struct View2D *UI_view2d_fromcontext(const struct bContext *C);
struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C);
void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y);
void UI_view2d_scale_get(const struct View2D *v2d, float *r_x, float *r_y);
float UI_view2d_scale_get_x(const struct View2D *v2d);
float UI_view2d_scale_get_y(const struct View2D *v2d);
void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y);

View File

@ -1895,7 +1895,7 @@ void UI_view2d_scroller_size_get(const View2D *v2d, float *r_x, float *r_y)
*
* \param r_x, r_y: scale on each axis
*/
void UI_view2d_scale_get(View2D *v2d, float *r_x, float *r_y)
void UI_view2d_scale_get(const View2D *v2d, float *r_x, float *r_y)
{
if (r_x) {
*r_x = UI_view2d_scale_get_x(v2d);

View File

@ -65,6 +65,7 @@
#include "BKE_duplilist.h"
#include "BKE_effect.h"
#include "BKE_font.h"
#include "BKE_geometry_set.h"
#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "BKE_hair.h"
@ -2146,6 +2147,13 @@ static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
return false;
}
static bool object_has_geometry_set_instances(const Object *object_eval)
{
struct GeometrySet *geometry_set = object_eval->runtime.geometry_set_eval;
return (geometry_set != NULL) && BKE_geometry_set_has_instances(geometry_set);
}
static void make_object_duplilist_real(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
@ -2157,13 +2165,19 @@ static void make_object_duplilist_real(bContext *C,
ViewLayer *view_layer = CTX_data_view_layer(C);
GHash *parent_gh = NULL, *instancer_gh = NULL;
if (!(base->object->transflag & OB_DUPLI)) {
Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object);
if (!(base->object->transflag & OB_DUPLI) && !object_has_geometry_set_instances(object_eval)) {
return;
}
Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object);
ListBase *lb_duplis = object_duplilist(depsgraph, scene, object_eval);
if (BLI_listbase_is_empty(lb_duplis)) {
free_object_duplilist(lb_duplis);
return;
}
GHash *dupli_gh = BLI_ghash_ptr_new(__func__);
if (use_hierarchy) {
parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__);

View File

@ -35,9 +35,11 @@
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
#include "BKE_anim_data.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "GPU_immediate.h"
#include "GPU_matrix.h"
@ -77,7 +79,12 @@ static float fcurve_display_alpha(FCurve *fcu)
/* Envelope -------------- */
/* TODO: draw a shaded poly showing the region of influence too!!! */
static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
/**
* \param adt_nla_remap: Send NULL if no NLA remapping necessary.
*/
static void draw_fcurve_modifier_controls_envelope(FModifier *fcm,
View2D *v2d,
AnimData *adt_nla_remap)
{
FMod_Envelope *env = (FMod_Envelope *)fcm->data;
FCM_EnvelopeData *fed;
@ -124,12 +131,15 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, View2D *v2d)
immBeginAtMost(GPU_PRIM_POINTS, env->totvert * 2);
for (i = 0, fed = env->data; i < env->totvert; i++, fed++) {
const float env_scene_time = BKE_nla_tweakedit_remap(
adt_nla_remap, fed->time, NLATIME_CONVERT_MAP);
/* only draw if visible
* - min/max here are fixed, not relative
*/
if (IN_RANGE(fed->time, (v2d->cur.xmin - fac), (v2d->cur.xmax + fac))) {
immVertex2f(shdr_pos, fed->time, fed->min);
immVertex2f(shdr_pos, fed->time, fed->max);
if (IN_RANGE(env_scene_time, (v2d->cur.xmin - fac), (v2d->cur.xmax + fac))) {
immVertex2f(shdr_pos, env_scene_time, fed->min);
immVertex2f(shdr_pos, env_scene_time, fed->max);
}
}
@ -572,7 +582,8 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu)
/* Helper func - just draw the F-Curve by sampling the visible region
* (for drawing curves with modifiers). */
static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos)
static void draw_fcurve_curve(
bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos, const bool use_nla_remap)
{
SpaceGraph *sipo = (SpaceGraph *)ac->sl;
short mapping_flag = ANIM_get_normalization_flags(ac);
@ -646,9 +657,17 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2
if (n > 0) {
immBegin(GPU_PRIM_LINE_STRIP, (n + 1));
AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL;
/* NLA remapping is linear so we don't have to remap per iteration. */
const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP);
const float eval_freq = BKE_nla_tweakedit_remap(
adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) -
eval_start;
for (int i = 0; i <= n; i++) {
float ctime = stime + i * samplefreq;
immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, ctime) + offset) * unitFac);
const float eval_time = eval_start + i * eval_freq;
immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac);
}
immEnd();
@ -1015,7 +1034,20 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
/* draw a curve affected by modifiers or only allowed to have integer values
* by sampling it at various small-intervals over the visible region
*/
draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos);
if (adt) {
/** We have to do this mapping dance since the keyframes were remapped but the Fmodifier
* evaluations are not.
*
* So we undo the keyframe remapping and instead remap the evaluation time when drawing the
* curve itself. Afterward, we go back and redo the keyframe remapping so the controls are
* drawn properly. */
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, true, false);
draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, true);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, false, false);
}
else {
draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
}
}
else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) {
/* just draw curve based on defined data (i.e. no modifiers) */
@ -1024,7 +1056,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
draw_fcurve_curve_bezts(ac, ale->id, fcu, &region->v2d, shdr_pos);
}
else {
draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos);
draw_fcurve_curve(ac, ale->id, fcu, &region->v2d, shdr_pos, false);
}
}
else if (fcu->fpt) {
@ -1050,7 +1082,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn
if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) {
switch (fcm->type) {
case FMODIFIER_TYPE_ENVELOPE: /* envelope */
draw_fcurve_modifier_controls_envelope(fcm, &region->v2d);
draw_fcurve_modifier_controls_envelope(fcm, &region->v2d, adt);
break;
}
}

View File

@ -3817,9 +3817,9 @@ void draw_nodespace_back_pix(const bContext *C,
}
/* return quadratic beziers points for a given nodelink and clip if v2d is not NULL. */
static bool node_link_bezier_handles(View2D *v2d,
SpaceNode *snode,
bNodeLink *link,
static bool node_link_bezier_handles(const View2D *v2d,
const SpaceNode *snode,
const bNodeLink *link,
float vec[4][2])
{
float cursor[2] = {0.0f, 0.0f};
@ -3912,8 +3912,11 @@ static bool node_link_bezier_handles(View2D *v2d,
}
/* if v2d not NULL, it clips and returns 0 if not visible */
bool node_link_bezier_points(
View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol)
bool node_link_bezier_points(const View2D *v2d,
const SpaceNode *snode,
const bNodeLink *link,
float coord_array[][2],
const int resol)
{
float vec[4][2];
@ -4076,7 +4079,7 @@ static char nodelink_get_color_id(int th_col)
return 0;
}
static void nodelink_batch_draw(SpaceNode *snode)
static void nodelink_batch_draw(const SpaceNode *snode)
{
if (g_batch_link.count == 0) {
return;
@ -4116,7 +4119,7 @@ void nodelink_batch_end(SpaceNode *snode)
g_batch_link.enabled = false;
}
static void nodelink_batch_add_link(SpaceNode *snode,
static void nodelink_batch_add_link(const SpaceNode *snode,
const float p0[2],
const float p1[2],
const float p2[2],
@ -4148,8 +4151,12 @@ static void nodelink_batch_add_link(SpaceNode *snode,
}
/* don't do shadows if th_col3 is -1. */
void node_draw_link_bezier(
View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int th_col2, int th_col3)
void node_draw_link_bezier(const View2D *v2d,
const SpaceNode *snode,
const bNodeLink *link,
int th_col1,
int th_col2,
int th_col3)
{
float vec[4][2];

View File

@ -317,14 +317,14 @@ static void node_uiblocks_init(const bContext *C, bNodeTree *ntree)
}
}
void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry)
void node_to_view(const bNode *node, float x, float y, float *rx, float *ry)
{
nodeToView(node, x, y, rx, ry);
*rx *= UI_DPI_FAC;
*ry *= UI_DPI_FAC;
}
void node_to_updated_rect(struct bNode *node, rctf *r_rect)
void node_to_updated_rect(const bNode *node, rctf *r_rect)
{
node_to_view(node, node->offsetx, node->offsety, &r_rect->xmin, &r_rect->ymax);
node_to_view(node,
@ -334,7 +334,7 @@ void node_to_updated_rect(struct bNode *node, rctf *r_rect)
&r_rect->ymin);
}
void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry)
void node_from_view(const bNode *node, float x, float y, float *rx, float *ry)
{
x /= UI_DPI_FAC;
y /= UI_DPI_FAC;
@ -689,11 +689,11 @@ int node_get_colorid(bNode *node)
/* note: in cmp_util.c is similar code, for node_compo_pass_on()
* the same goes for shader and texture nodes. */
/* note: in node_edit.c is similar code, for untangle node */
static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node)
static void node_draw_mute_line(const View2D *v2d, const SpaceNode *snode, const bNode *node)
{
GPU_blend(GPU_BLEND_ALPHA);
LISTBASE_FOREACH (bNodeLink *, link, &node->internal_links) {
LISTBASE_FOREACH (const bNodeLink *, link, &node->internal_links) {
node_draw_link_bezier(v2d, snode, link, TH_REDALERT, TH_REDALERT, -1);
}
@ -947,14 +947,14 @@ static void node_toggle_button_cb(struct bContext *C, void *node_argv, void *op_
WM_operator_name_call(C, opname, WM_OP_INVOKE_DEFAULT, NULL);
}
void node_draw_shadow(SpaceNode *snode, bNode *node, float radius, float alpha)
void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha)
{
rctf *rct = &node->totr;
const rctf *rct = &node->totr;
UI_draw_roundbox_corner_set(UI_CNR_ALL);
ui_draw_dropshadow(rct, radius, snode->aspect, alpha, node->flag & SELECT);
}
void node_draw_sockets(View2D *v2d,
void node_draw_sockets(const View2D *v2d,
const bContext *C,
bNodeTree *ntree,
bNode *node,
@ -1118,8 +1118,8 @@ void node_draw_sockets(View2D *v2d,
}
static void node_draw_basis(const bContext *C,
ARegion *region,
SpaceNode *snode,
const View2D *v2d,
const SpaceNode *snode,
bNodeTree *ntree,
bNode *node,
bNodeInstanceKey key)
@ -1127,8 +1127,6 @@ static void node_draw_basis(const bContext *C,
/* float socket_size = NODE_SOCKSIZE*U.dpi/72; */ /* UNUSED */
float iconbutw = 0.8f * UI_UNIT_X;
View2D *v2d = &region->v2d;
/* skip if out of view */
if (BLI_rctf_isect(&node->totr, &v2d->cur, NULL) == false) {
UI_block_end(C, node->block);
@ -1343,8 +1341,8 @@ static void node_draw_basis(const bContext *C,
}
static void node_draw_hidden(const bContext *C,
ARegion *region,
SpaceNode *snode,
const View2D *v2d,
const SpaceNode *snode,
bNodeTree *ntree,
bNode *node,
bNodeInstanceKey UNUSED(key))
@ -1353,8 +1351,6 @@ static void node_draw_hidden(const bContext *C,
float centy = BLI_rctf_cent_y(rct);
float hiddenrad = BLI_rctf_size_y(rct) / 2.0f;
View2D *v2d = &region->v2d;
float scale;
UI_view2d_scale_get(v2d, &scale, NULL);
@ -1438,7 +1434,7 @@ static void node_draw_hidden(const bContext *C,
/* disable lines */
if (node->flag & NODE_MUTED) {
node_draw_mute_line(&region->v2d, snode, node);
node_draw_mute_line(v2d, snode, node);
}
char showname[128]; /* 128 is used below */
@ -1550,11 +1546,12 @@ void node_draw_default(const bContext *C,
bNode *node,
bNodeInstanceKey key)
{
const View2D *v2d = &region->v2d;
if (node->flag & NODE_HIDDEN) {
node_draw_hidden(C, region, snode, ntree, node, key);
node_draw_hidden(C, v2d, snode, ntree, node, key);
}
else {
node_draw_basis(C, region, snode, ntree, node, key);
node_draw_basis(C, v2d, snode, ntree, node, key);
}
}
@ -1607,8 +1604,7 @@ void node_draw_nodetree(const bContext *C,
#endif
/* draw background nodes, last nodes in front */
int a = 0;
LISTBASE_FOREACH_INDEX (bNode *, node, &ntree->nodes, a) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
#ifdef USE_DRAW_TOT_UPDATE
/* unrelated to background nodes, update the v2d->tot,
* can be anywhere before we draw the scroll bars */
@ -1635,8 +1631,7 @@ void node_draw_nodetree(const bContext *C,
GPU_blend(GPU_BLEND_NONE);
/* draw foreground nodes, last nodes in front */
a = 0;
LISTBASE_FOREACH_INDEX (bNode *, node, &ntree->nodes, a) {
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
if (node->flag & NODE_BACKGROUND) {
continue;
}
@ -1686,8 +1681,8 @@ static void draw_nodetree(const bContext *C,
/* shade the parent node group and add a uiBlock to clip mouse events */
static void draw_group_overlay(const bContext *C, ARegion *region)
{
View2D *v2d = &region->v2d;
rctf rect = v2d->cur;
const View2D *v2d = &region->v2d;
const rctf rect = v2d->cur;
float color[4];
/* shade node groups to separate them visually */

View File

@ -61,14 +61,17 @@ void space_node_group_offset(struct SpaceNode *snode, float *x, float *y);
/* node_draw.c */
int node_get_colorid(struct bNode *node);
int node_get_resize_cursor(int directions);
void node_draw_shadow(struct SpaceNode *snode, struct bNode *node, float radius, float alpha);
void node_draw_shadow(const struct SpaceNode *snode,
const struct bNode *node,
float radius,
float alpha);
void node_draw_default(const struct bContext *C,
struct ARegion *region,
struct SpaceNode *snode,
struct bNodeTree *ntree,
struct bNode *node,
bNodeInstanceKey key);
void node_draw_sockets(struct View2D *v2d,
void node_draw_sockets(const struct View2D *v2d,
const struct bContext *C,
struct bNodeTree *ntree,
struct bNode *node,
@ -92,9 +95,9 @@ void node_draw_space(const bContext *C, ARegion *region);
void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]);
/* DPI scaled coords */
void node_to_view(struct bNode *node, float x, float y, float *rx, float *ry);
void node_to_updated_rect(struct bNode *node, rctf *r_rect);
void node_from_view(struct bNode *node, float x, float y, float *rx, float *ry);
void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry);
void node_to_updated_rect(const struct bNode *node, rctf *r_rect);
void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry);
/* node_buttons.c */
void node_buttons_register(struct ARegionType *art);
@ -145,17 +148,17 @@ void nodelink_batch_start(struct SpaceNode *snode);
void nodelink_batch_end(struct SpaceNode *snode);
void node_draw_link(struct View2D *v2d, struct SpaceNode *snode, struct bNodeLink *link);
void node_draw_link_bezier(struct View2D *v2d,
struct SpaceNode *snode,
struct bNodeLink *link,
void node_draw_link_bezier(const struct View2D *v2d,
const struct SpaceNode *snode,
const struct bNodeLink *link,
int th_col1,
int th_col2,
int th_col3);
bool node_link_bezier_points(struct View2D *v2d,
struct SpaceNode *snode,
struct bNodeLink *link,
bool node_link_bezier_points(const struct View2D *v2d,
const struct SpaceNode *snode,
const struct bNodeLink *link,
float coord_array[][2],
int resol);
const int resol);
void draw_nodespace_back_pix(const struct bContext *C,
struct ARegion *region,
struct SpaceNode *snode,

View File

@ -58,7 +58,7 @@
static bool ntree_has_drivers(bNodeTree *ntree)
{
AnimData *adt = BKE_animdata_from_id(&ntree->id);
const AnimData *adt = BKE_animdata_from_id(&ntree->id);
if (adt == NULL) {
return false;
}

View File

@ -48,7 +48,23 @@
*
* \{ */
static void mesh_skin_transdata_create(TransDataBasic *td, BMEditMesh *em, BMVert *eve)
static float *mesh_skin_transdata_center(const struct TransIslandData *island_data,
const int island_index,
BMVert *eve)
{
if (island_data->center && island_index != -1) {
return island_data->center[island_index];
}
else {
return eve->co;
}
}
static void mesh_skin_transdata_create(TransDataBasic *td,
BMEditMesh *em,
BMVert *eve,
const struct TransIslandData *island_data,
const int island_index)
{
BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0);
MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN);
@ -65,6 +81,7 @@ static void mesh_skin_transdata_create(TransDataBasic *td, BMEditMesh *em, BMVer
td->flag |= TD_SELECTED;
}
copy_v3_v3(td->center, mesh_skin_transdata_center(island_data, island_index, eve));
td->extra = eve;
}
@ -188,8 +205,15 @@ void createTransMeshSkin(TransInfo *t)
continue;
}
int island_index = -1;
if (island_data.island_vert_map) {
const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
island_index = island_data.island_vert_map[connected_index];
}
if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
mesh_skin_transdata_create((TransDataBasic *)td_mirror, em, eve);
mesh_skin_transdata_create(
(TransDataBasic *)td_mirror, em, eve, &island_data, island_index);
int elem_index = mirror_data.vert_map[a].index;
BMVert *v_src = BM_vert_at_index(bm, elem_index);
@ -200,7 +224,7 @@ void createTransMeshSkin(TransInfo *t)
td_mirror++;
}
else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
mesh_skin_transdata_create((TransDataBasic *)td, em, eve);
mesh_skin_transdata_create((TransDataBasic *)td, em, eve, &island_data, island_index);
if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
createSpaceNormal(td->axismtx, eve->no);

View File

@ -80,10 +80,10 @@ typedef struct TransformInitContext {
TransInfo *t;
TransDataContainer *tc;
/* MOTE: There pointers will be nullptr during counting step.
/* MOTE: There pointers will be `nullptr` during counting step.
* This means, that the transformation data initialization functions are to increment
* `tc->data_len` instead of filling in the transformation data when these pointers are nullptr.
* For simplicitly, check the `current.td` against nullptr.
* `tc->data_len` instead of filling in the transformation data when these pointers are
* `nullptr`. For simplicity, check the `current.td` against `nullptr`.
* Do not `tc->data_len` when filling in the transformation data. */
struct {
TransData *td;
@ -619,8 +619,8 @@ static void cancelTransTracking(TransInfo *t)
}
else if (tdt->mode == transDataTracking_ModePlaneTracks) {
MovieTrackingPlaneTrack *plane_track = tdt->plane_track;
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get(plane_track,
tdt->framenr);
MovieTrackingPlaneMarker *plane_marker = BKE_tracking_plane_marker_get_exact(plane_track,
tdt->framenr);
BLI_assert(plane_marker != NULL);

View File

@ -110,11 +110,11 @@ static bool dependsOnTime(GpencilModifierData *md)
return (mmd->flag & GP_NOISE_USE_RANDOM) != 0;
}
static float *noise_table(int len, int seed)
static float *noise_table(int len, int offset, int seed)
{
float *table = MEM_callocN(sizeof(float) * len, __func__);
for (int i = 0; i < len; i++) {
table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + 1));
table[i] = BLI_hash_int_01(BLI_hash_int_2d(seed, i + offset + 1));
}
return table;
}
@ -172,11 +172,19 @@ static void deformStroke(GpencilModifierData *md,
/* Sanitize as it can create out of bound reads. */
float noise_scale = clamp_f(mmd->noise_scale, 0.0f, 1.0f);
int len = ceilf(gps->totpoints * noise_scale) + 1;
float *noise_table_position = (mmd->factor > 0.0f) ? noise_table(len, seed + 2) : NULL;
float *noise_table_strength = (mmd->factor_strength > 0.0f) ? noise_table(len, seed + 3) : NULL;
float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ? noise_table(len, seed) : NULL;
float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ? noise_table(len, seed + 4) : NULL;
int len = ceilf(gps->totpoints * noise_scale) + 2;
float *noise_table_position = (mmd->factor > 0.0f) ?
noise_table(len, (int)floor(mmd->noise_offset), seed + 2) :
NULL;
float *noise_table_strength = (mmd->factor_strength > 0.0f) ?
noise_table(len, (int)floor(mmd->noise_offset), seed + 3) :
NULL;
float *noise_table_thickness = (mmd->factor_thickness > 0.0f) ?
noise_table(len, (int)floor(mmd->noise_offset), seed) :
NULL;
float *noise_table_uvs = (mmd->factor_uvs > 0.0f) ?
noise_table(len, (int)floor(mmd->noise_offset), seed + 4) :
NULL;
/* Calculate stroke normal. */
if (gps->totpoints > 2) {
@ -225,24 +233,27 @@ static void deformStroke(GpencilModifierData *md,
cross_v3_v3v3(vec2, vec1, normal);
normalize_v3(vec2);
float noise = table_sample(noise_table_position, i * noise_scale);
float noise = table_sample(noise_table_position,
i * noise_scale + fractf(mmd->noise_offset));
madd_v3_v3fl(&pt->x, vec2, (noise * 2.0f - 1.0f) * weight * mmd->factor * 0.1f);
}
if (mmd->factor_thickness > 0.0f) {
float noise = table_sample(noise_table_thickness, i * noise_scale);
float noise = table_sample(noise_table_thickness,
i * noise_scale + fractf(mmd->noise_offset));
pt->pressure *= max_ff(1.0f + (noise * 2.0f - 1.0f) * weight * mmd->factor_thickness, 0.0f);
CLAMP_MIN(pt->pressure, GPENCIL_STRENGTH_MIN);
}
if (mmd->factor_strength > 0.0f) {
float noise = table_sample(noise_table_strength, i * noise_scale);
float noise = table_sample(noise_table_strength,
i * noise_scale + fractf(mmd->noise_offset));
pt->strength *= max_ff(1.0f - noise * weight * mmd->factor_strength, 0.0f);
CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
}
if (mmd->factor_uvs > 0.0f) {
float noise = table_sample(noise_table_uvs, i * noise_scale);
float noise = table_sample(noise_table_uvs, i * noise_scale + fractf(mmd->noise_offset));
pt->uv_rot += (noise * 2.0f - 1.0f) * weight * mmd->factor_uvs * M_PI_2;
CLAMP(pt->uv_rot, -M_PI_2, M_PI_2);
}
@ -292,6 +303,7 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel)
uiItemR(col, ptr, "factor_thickness", 0, IFACE_("Thickness"), ICON_NONE);
uiItemR(col, ptr, "factor_uvs", 0, IFACE_("UV"), ICON_NONE);
uiItemR(col, ptr, "noise_scale", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "noise_offset", 0, NULL, ICON_NONE);
uiItemR(col, ptr, "seed", 0, NULL, ICON_NONE);
gpencil_modifier_panel_end(layout, ptr);

View File

@ -32,7 +32,7 @@ struct ImBuf;
void imb_refcounter_lock_init(void);
void imb_refcounter_lock_exit(void);
#ifdef WIN32
#ifndef WIN32
void imb_mmap_lock_init(void);
void imb_mmap_lock_exit(void);
void imb_mmap_lock(void);

View File

@ -53,7 +53,7 @@ void imb_refcounter_lock_exit(void)
BLI_spin_end(&refcounter_spin);
}
#ifdef WIN32
#ifndef WIN32
static SpinLock mmap_spin;
void imb_mmap_lock_init(void)

View File

@ -23,13 +23,13 @@
*/
#ifdef _WIN32
# include "mmap_win.h"
# include <io.h>
# include <stddef.h>
# include <sys/types.h>
#endif
#include "BLI_fileops.h"
#include "BLI_mmap.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
@ -186,20 +186,19 @@ ImBuf *IMB_loadifffile(
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
if (mem == (unsigned char *)-1) {
if (mmap_file == NULL) {
fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr);
return NULL;
}
mem = BLI_mmap_get_pointer(mmap_file);
ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr);
imb_mmap_lock();
if (munmap(mem, size)) {
fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr);
}
BLI_mmap_free(mmap_file);
imb_mmap_unlock();
return ibuf;
@ -292,14 +291,15 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
size = BLI_file_descriptor_size(file);
imb_mmap_lock();
mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
BLI_mmap_file *mmap_file = BLI_mmap_open(file);
imb_mmap_unlock();
if (mem == (unsigned char *)-1) {
if (mmap_file == NULL) {
fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename);
return;
}
mem = BLI_mmap_get_pointer(mmap_file);
const ImFileType *type = IMB_file_type_from_ibuf(ibuf);
if (type != NULL) {
if (type->load_tile != NULL) {
@ -308,9 +308,7 @@ static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int
}
imb_mmap_lock();
if (munmap(mem, size)) {
fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename);
}
BLI_mmap_free(mmap_file);
imb_mmap_unlock();
}

View File

@ -515,7 +515,7 @@ typedef enum ID_Type {
((const ID *)(_id))->override_library->reference != NULL)
#define ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id) \
((((const ID *)(_id))->flag & LIB_EMBEDDED_DATA_LIB_OVERRIDE) != 0)
((((const ID *)(_id))->flag & (LIB_EMBEDDED_DATA_LIB_OVERRIDE | LIB_EMBEDDED_DATA)) != 0)
#define ID_IS_OVERRIDE_LIBRARY(_id) \
(ID_IS_OVERRIDE_LIBRARY_REAL(_id) || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(_id))

View File

@ -152,6 +152,7 @@
.factor_thickness = 0.0f, \
.factor_uvs = 0.0f, \
.noise_scale = 0.0f, \
.noise_offset = 0.0f, \
.step = 4, \
.layer_pass = 0, \
.seed = 1, \

View File

@ -107,6 +107,8 @@ typedef struct NoiseGpencilModifierData {
float factor_uvs;
/** Noise Frequency scaling */
float noise_scale;
float noise_offset;
char _pad[4];
/** How many frames before recalculate randoms. */
int step;
/** Custom index for passes. */

View File

@ -48,12 +48,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
)
if(WIN32 AND NOT UNIX)
list(APPEND SRC
../../../../intern/guardedalloc/intern/mmap_win.c
)
endif()
# SRC_DNA_INC is defined in the parent dir
add_cc_flags_custom_test(makesdna)

View File

@ -189,7 +189,6 @@ set(SRC
../../../../intern/guardedalloc/intern/mallocn.c
../../../../intern/guardedalloc/intern/mallocn_guarded_impl.c
../../../../intern/guardedalloc/intern/mallocn_lockfree_impl.c
../../../../intern/guardedalloc/intern/mmap_win.c
# Needed for defaults.
../../../../release/datafiles/userdef/userdef_default.c

View File

@ -4758,8 +4758,14 @@ static const char *cpp_classes =
"class CollectionIterator {\n"
"public:\n"
" CollectionIterator() : iter(), t(iter.ptr), init(false) { iter.valid = false; }\n"
" CollectionIterator(const PointerRNA &ptr) : CollectionIterator() { this->begin(ptr); }\n"
" ~CollectionIterator(void) { if (init) Tend(&iter); };\n"
"\n"
" CollectionIterator(const CollectionIterator &other) = delete;\n"
" CollectionIterator(CollectionIterator &&other) = delete;\n"
" CollectionIterator &operator=(const CollectionIterator &other) = delete;\n"
" CollectionIterator &operator=(CollectionIterator &&other) = delete;\n"
"\n"
" operator bool(void)\n"
" { return iter.valid != 0; }\n"
" const CollectionIterator<T, Tbegin, Tnext, Tend>& operator++() { Tnext(&iter); t = "
@ -4777,9 +4783,6 @@ static const char *cpp_classes =
"true; }\n"
"\n"
"private:\n"
" const CollectionIterator<T, Tbegin, Tnext, Tend>& operator = "
"(const CollectionIterator<T, Tbegin, Tnext, Tend>& /*copy*/) {}\n"
""
" CollectionPropertyIterator iter;\n"
" T t;\n"
" bool init;\n"
@ -4794,6 +4797,8 @@ static const char *cpp_classes =
"\n"
" void begin(CollectionIterator<T, Tbegin, Tnext, Tend>& iter)\n"
" { iter.begin(ptr); }\n"
" CollectionIterator<T, Tbegin, Tnext, Tend> begin()\n"
" { return CollectionIterator<T, Tbegin, Tnext, Tend>(ptr); }\n"
" CollectionIterator<T, Tbegin, Tnext, Tend> end()\n"
" { return CollectionIterator<T, Tbegin, Tnext, Tend>(); } /* test */ \n"
""

View File

@ -498,6 +498,13 @@ static void rna_def_modifier_gpencilnoise(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Noise Scale", "Scale the noise frequency");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "noise_offset", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "noise_offset");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3);
RNA_def_property_ui_text(prop, "Noise Offset", "Offset the noise along the strokes");
RNA_def_property_update(prop, 0, "rna_GpencilModifier_update");
prop = RNA_def_property(srna, "use_custom_curve", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_NOISE_CUSTOM_CURVE);
RNA_def_property_ui_text(

View File

@ -1279,12 +1279,22 @@ static int rna_property_override_diff_propptr(Main *bmain,
0);
if (is_id) {
/* For now, once we deal with nodetrees we'll want to get rid of that one. */
// BLI_assert(no_ownership);
/* Owned IDs (the ones we want to actually compare in depth, instead of just comparing pointer
* values) should be always properly tagged as 'virtual' overrides. */
ID *id = propptr_a->owner_id;
if (id != NULL && !ID_IS_OVERRIDE_LIBRARY(id)) {
id = propptr_b->owner_id;
if (id != NULL && !ID_IS_OVERRIDE_LIBRARY(id)) {
id = NULL;
}
}
BLI_assert(no_ownership || id == NULL || ID_IS_OVERRIDE_LIBRARY_VIRTUAL(id));
UNUSED_VARS_NDEBUG(id);
}
if (override) {
if (no_ownership /* || is_id */ || is_null || is_type_diff || !is_valid_for_diffing) {
if (no_ownership || is_null || is_type_diff || !is_valid_for_diffing) {
/* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
* This is a quite safe path to infinite loop, among other nasty issues.
* Instead, just compare pointers themselves. */
@ -1468,7 +1478,6 @@ int rna_property_override_diff_default(Main *bmain,
rna_path != NULL;
const bool no_ownership = (prop_a->rnaprop->flag & PROP_PTR_NO_OWNERSHIP) != 0;
const bool no_prop_name = (prop_a->rnaprop->flag_override & PROPOVERRIDE_NO_PROP_NAME) != 0;
/* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
* and that we never remove anything. */
@ -1724,6 +1733,11 @@ int rna_property_override_diff_default(Main *bmain,
}
case PROP_POINTER: {
/* Using property name check only makes sense for items of a collection, not for a single
* pointer.
* Doing this here avoids having to manually specify `PROPOVERRIDE_NO_PROP_NAME` to things
* like ShapeKey pointers. */
const bool no_prop_name = true;
if (STREQ(prop_a->identifier, "rna_type")) {
/* Dummy 'pass' answer, this is a meta-data and must be ignored... */
return 0;
@ -1752,6 +1766,8 @@ int rna_property_override_diff_default(Main *bmain,
}
case PROP_COLLECTION: {
const bool no_prop_name = (prop_a->rnaprop->flag_override & PROPOVERRIDE_NO_PROP_NAME) != 0;
bool equals = true;
bool abort = false;
int idx_a = 0;

View File

@ -26,6 +26,7 @@
#include "DNA_meshdata_types.h"
#include "DNA_pointcloud_types.h"
#include "BKE_attribute_math.hh"
#include "BKE_bvhutils.h"
#include "BKE_deform.h"
#include "BKE_mesh.h"
@ -217,13 +218,141 @@ BLI_NOINLINE static void eliminate_points_based_on_mask(Span<bool> elimination_m
}
}
BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
MutableSpan<float3> r_normals,
MutableSpan<int> r_ids,
MutableSpan<float3> r_rotations)
template<typename T>
BLI_NOINLINE static void interpolate_attribute_point(const Mesh &mesh,
const Span<float3> bary_coords,
const Span<int> looptri_indices,
const Span<T> data_in,
MutableSpan<T> data_out)
{
BLI_assert(data_in.size() == mesh.totvert);
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
const int v0_index = mesh.mloop[looptri.tri[0]].v;
const int v1_index = mesh.mloop[looptri.tri[1]].v;
const int v2_index = mesh.mloop[looptri.tri[2]].v;
const T &v0 = data_in[v0_index];
const T &v1 = data_in[v1_index];
const T &v2 = data_in[v2_index];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
data_out[i] = interpolated_value;
}
}
template<typename T>
BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh,
const Span<float3> bary_coords,
const Span<int> looptri_indices,
const Span<T> data_in,
MutableSpan<T> data_out)
{
BLI_assert(data_in.size() == mesh.totloop);
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
const MLoopTri &looptri = looptris[looptri_index];
const float3 &bary_coord = bary_coords[i];
const int loop_index_0 = looptri.tri[0];
const int loop_index_1 = looptri.tri[1];
const int loop_index_2 = looptri.tri[2];
const T &v0 = data_in[loop_index_0];
const T &v1 = data_in[loop_index_1];
const T &v2 = data_in[loop_index_2];
const T interpolated_value = attribute_math::mix3(bary_coord, v0, v1, v2);
data_out[i] = interpolated_value;
}
}
BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh,
Span<float3> bary_coords,
Span<int> looptri_indices,
const StringRef attribute_name,
const ReadAttribute &attribute_in,
GeometryComponent &component)
{
const CustomDataType data_type = attribute_in.custom_data_type();
const AttributeDomain domain = attribute_in.domain();
if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) {
/* Not supported currently. */
return;
}
OutputAttributePtr attribute_out = component.attribute_try_get_for_output(
attribute_name, ATTR_DOMAIN_POINT, data_type);
if (!attribute_out) {
return;
}
attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
using T = decltype(dummy);
Span data_in = attribute_in.get_span<T>();
MutableSpan data_out = attribute_out->get_span_for_write_only<T>();
switch (domain) {
case ATTR_DOMAIN_POINT: {
interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
break;
}
case ATTR_DOMAIN_CORNER: {
interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out);
break;
}
default: {
BLI_assert(false);
break;
}
}
});
attribute_out.apply_span_and_save();
}
BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component,
GeometryComponent &component,
Span<float3> bary_coords,
Span<int> looptri_indices)
{
const Mesh &mesh = *mesh_component.get_for_read();
Set<std::string> attribute_names = mesh_component.attribute_names();
for (StringRefNull attribute_name : attribute_names) {
if (ELEM(attribute_name, "position", "normal", "id")) {
continue;
}
ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name);
interpolate_attribute(
mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component);
}
}
BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
GeometryComponent &component,
Span<float3> bary_coords,
Span<int> looptri_indices)
{
OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
"normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
MutableSpan<int> ids = id_attribute->get_span_for_write_only<int>();
MutableSpan<float3> normals = normal_attribute->get_span_for_write_only<float3>();
MutableSpan<float3> rotations = rotation_attribute->get_span_for_write_only<float3>();
Span<MLoopTri> looptris = get_mesh_looptris(mesh);
for (const int i : bary_coords.index_range()) {
const int looptri_index = looptri_indices[i];
@ -237,36 +366,26 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh,
const float3 v1_pos = mesh.mvert[v1_index].co;
const float3 v2_pos = mesh.mvert[v2_index].co;
r_ids[i] = (int)(bary_coord.hash()) + looptri_index;
normal_tri_v3(r_normals[i], v0_pos, v1_pos, v2_pos);
r_rotations[i] = normal_to_euler_rotation(r_normals[i]);
ids[i] = (int)(bary_coord.hash()) + looptri_index;
normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos);
rotations[i] = normal_to_euler_rotation(normals[i]);
}
}
BLI_NOINLINE static void add_remaining_point_attributes(const Mesh &mesh,
GeometryComponent &component,
Span<float3> bary_coords,
Span<int> looptri_indices)
{
OutputAttributePtr id_attribute = component.attribute_try_get_for_output(
"id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
OutputAttributePtr normal_attribute = component.attribute_try_get_for_output(
"normal", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output(
"rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
compute_special_attributes(mesh,
bary_coords,
looptri_indices,
normal_attribute->get_span_for_write_only<float3>(),
id_attribute->get_span_for_write_only<int>(),
rotation_attribute->get_span_for_write_only<float3>());
id_attribute.apply_span_and_save();
normal_attribute.apply_span_and_save();
rotation_attribute.apply_span_and_save();
}
BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component,
GeometryComponent &component,
Span<float3> bary_coords,
Span<int> looptri_indices)
{
interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices);
compute_special_attributes(
*mesh_component.get_for_read(), component, bary_coords, looptri_indices);
}
static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh,
const float max_density,
const float minimum_distance,
@ -351,7 +470,7 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params)
geometry_set_out.get_component_for_write<PointCloudComponent>();
point_component.replace(pointcloud);
add_remaining_point_attributes(*mesh_in, point_component, bary_coords, looptri_indices);
add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices);
params.set_output("Geometry", std::move(geometry_set_out));
}

View File

@ -34,8 +34,9 @@ namespace blender::nodes {
static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component)
{
static const float3 scale_default = float3(1.0f);
OutputAttributePtr scale_attribute = component.attribute_try_get_for_output(
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
"scale", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, &scale_default);
ReadAttributePtr attribute = params.get_input_attribute(
"Factor", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr);
if (!attribute) {

View File

@ -19,6 +19,7 @@
#include "FN_multi_function_network_evaluation.hh"
#include "BLI_color.hh"
#include "BLI_float2.hh"
#include "BLI_float3.hh"
namespace blender::nodes {
@ -191,27 +192,57 @@ static void add_implicit_conversion(DataTypeConversions &conversions,
static DataTypeConversions create_implicit_conversions()
{
DataTypeConversions conversions;
add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, float2>(conversions);
add_implicit_conversion<float, float3>(conversions);
add_implicit_conversion<int32_t, float>(conversions);
add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, bool>(conversions);
add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<float3, float>(
conversions, "Vector Length", [](float3 a) { return a.length(); });
add_implicit_conversion<int32_t, float3>(
conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
add_implicit_conversion<float3, Color4f>(
conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
add_implicit_conversion<Color4f, float3>(
conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
add_implicit_conversion<float, Color4f>(
conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); });
add_implicit_conversion<Color4f, float>(
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
add_implicit_conversion<float2, float3>(conversions);
add_implicit_conversion<float2, float>(
conversions, "float2 to float", [](float2 a) { return a.length(); });
add_implicit_conversion<float2, int32_t>(
conversions, "float2 to int32_t", [](float2 a) { return (int32_t)a.length(); });
add_implicit_conversion<float2, bool>(
conversions, "float2 to bool", [](float2 a) { return a.length_squared() == 0.0f; });
add_implicit_conversion<float2, Color4f>(
conversions, "float2 to Color4f", [](float2 a) { return Color4f(a.x, a.y, 0.0f, 1.0f); });
add_implicit_conversion<float3, bool>(
conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; });
add_implicit_conversion<float3, float>(
conversions, "Vector Length", [](float3 a) { return a.length(); });
add_implicit_conversion<float3, int32_t>(
conversions, "float3 to int32_t", [](float3 a) { return (int)a.length(); });
add_implicit_conversion<float3, float2>(conversions);
add_implicit_conversion<float3, Color4f>(
conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); });
add_implicit_conversion<int32_t, bool>(conversions);
add_implicit_conversion<int32_t, float>(conversions);
add_implicit_conversion<int32_t, float2>(
conversions, "int32 to float2", [](int32_t a) { return float2((float)a); });
add_implicit_conversion<int32_t, float3>(
conversions, "int32 to float3", [](int32_t a) { return float3((float)a); });
add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<bool, int32_t>(conversions);
add_implicit_conversion<bool, float2>(
conversions, "boolean to float2", [](bool a) { return (a) ? float2(1.0f) : float2(0.0f); });
add_implicit_conversion<bool, float3>(
conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); });
add_implicit_conversion<bool, Color4f>(conversions, "boolean to Color4f", [](bool a) {
return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f);
});
add_implicit_conversion<Color4f, float>(
conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); });
add_implicit_conversion<Color4f, float2>(
conversions, "Color4f to float2", [](Color4f a) { return float2(a.r, a.g); });
add_implicit_conversion<Color4f, float3>(
conversions, "Color4f to float3", [](Color4f a) { return float3(a.r, a.g, a.b); });
return conversions;
}