Merge branch 'master' into temp_bmesh_multires

This commit is contained in:
Joseph Eagar 2021-05-11 14:18:48 -07:00
commit dbe767f5d9
146 changed files with 3716 additions and 2187 deletions

View File

@ -255,6 +255,7 @@ ForEachMacros:
- SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN
- SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN
- SEQ_ALL_BEGIN
- SEQ_ITERATOR_FOREACH
- SURFACE_QUAD_ITER_BEGIN
- foreach
- ED_screen_areas_iter

View File

@ -96,7 +96,49 @@ bool BlenderSync::object_is_light(BL::Object &b_ob)
return (b_ob_data && b_ob_data.is_a(&RNA_Light));
}
/* Object */
void BlenderSync::sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object)
{
/* Initialize motion blur for object, detecting if it's enabled and creating motion
* steps array if so. */
array<Transform> motion;
object->set_motion(motion);
Scene::MotionType need_motion = scene->need_motion();
if (need_motion == Scene::MOTION_NONE || !object->get_geometry()) {
return;
}
Geometry *geom = object->get_geometry();
geom->set_use_motion_blur(false);
geom->set_motion_steps(0);
uint motion_steps;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
geom->set_use_motion_blur(true);
}
}
else {
motion_steps = 3;
geom->set_motion_steps(motion_steps);
}
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
motion[motion_steps / 2] = object->get_tfm();
/* update motion socket before trying to access object->motion_time */
object->set_motion(motion);
for (size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
}
}
}
Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
BL::ViewLayer &b_view_layer,
@ -277,43 +319,6 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object->set_pass_id(b_ob.pass_index());
object->set_color(get_float3(b_ob.color()));
object->set_tfm(tfm);
array<Transform> motion;
object->set_motion(motion);
/* motion blur */
Scene::MotionType need_motion = scene->need_motion();
if (need_motion != Scene::MOTION_NONE && object->get_geometry()) {
Geometry *geom = object->get_geometry();
geom->set_use_motion_blur(false);
geom->set_motion_steps(0);
uint motion_steps;
if (need_motion == Scene::MOTION_BLUR) {
motion_steps = object_motion_steps(b_parent, b_ob, Object::MAX_MOTION_STEPS);
geom->set_motion_steps(motion_steps);
if (motion_steps && object_use_deform_motion(b_parent, b_ob)) {
geom->set_use_motion_blur(true);
}
}
else {
motion_steps = 3;
geom->set_motion_steps(motion_steps);
}
motion.resize(motion_steps, transform_empty());
if (motion_steps) {
motion[motion_steps / 2] = tfm;
/* update motion socket before trying to access object->motion_time */
object->set_motion(motion);
for (size_t step = 0; step < motion_steps; step++) {
motion_times.insert(object->motion_time(step));
}
}
}
/* dupli texture coordinates and random_id */
if (is_instance) {
@ -331,6 +336,8 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
object->tag_update(scene);
}
sync_object_motion_init(b_parent, b_ob, object);
if (is_instance) {
/* Sync possible particle data. */
sync_dupli_particle(b_parent, b_instance, object);
@ -613,7 +620,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render,
if (b_cam) {
sync_camera_motion(b_render, b_cam, width, height, 0.0f);
}
sync_objects(b_depsgraph, b_v3d, 0.0f);
sync_objects(b_depsgraph, b_v3d);
}
/* Insert motion times from camera. Motion times from other objects

View File

@ -739,12 +739,18 @@ void BlenderSync::free_data_after_sync(BL::Depsgraph &b_depsgraph)
* caches to be releases from blender side in order to reduce peak memory
* footprint during synchronization process.
*/
const bool is_interface_locked = b_engine.render() && b_engine.render().use_lock_interface();
const bool can_free_caches = (BlenderSession::headless || is_interface_locked) &&
/* Baking re-uses the depsgraph multiple times, clearing crashes
* reading un-evaluated mesh data which isn't aligned with the
* geometry we're baking, see T71012. */
!scene->bake_manager->get_baking();
const bool is_persistent_data = b_engine.render() && b_engine.render().use_persistent_data();
const bool can_free_caches =
(BlenderSession::headless || is_interface_locked) &&
/* Baking re-uses the depsgraph multiple times, clearing crashes
* reading un-evaluated mesh data which isn't aligned with the
* geometry we're baking, see T71012. */
!scene->bake_manager->get_baking() &&
/* Persistent data must main caches for performance and correctness. */
!is_persistent_data;
if (!can_free_caches) {
return;
}

View File

@ -150,6 +150,7 @@ class BlenderSync {
BlenderObjectCulling &culling,
bool *use_portal,
TaskPool *geom_task_pool);
void sync_object_motion_init(BL::Object &b_parent, BL::Object &b_ob, Object *object);
bool sync_object_attributes(BL::DepsgraphObjectInstance &b_instance, Object *object);

View File

@ -25,8 +25,9 @@ CCL_NAMESPACE_BEGIN
ccl_device_inline float3
subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, float r, bool all)
{
/* this is the veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting */
/* This is the Veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting. For branched
* path tracing (all) we sample all closure and don't use MIS. */
float3 eval_sum = zero_float3();
float pdf_sum = 0.0f;
float sample_weight_inv = 0.0f;
@ -65,6 +66,30 @@ subsurface_scatter_eval(ShaderData *sd, const ShaderClosure *sc, float disk_r, f
return (pdf_sum > 0.0f) ? eval_sum / pdf_sum : zero_float3();
}
ccl_device_inline float3 subsurface_scatter_walk_eval(ShaderData *sd,
const ShaderClosure *sc,
float3 throughput,
bool all)
{
/* This is the Veach one-sample model with balance heuristic, some pdf
* factors drop out when using balance heuristic weighting. For branched
* path tracing (all) we sample all closure and don't use MIS. */
if (!all) {
float bssrdf_weight = 0.0f;
float weight = sc->sample_weight;
for (int i = 0; i < sd->num_closure; i++) {
sc = &sd->closure[i];
if (CLOSURE_IS_BSSRDF(sc->type)) {
bssrdf_weight += sc->sample_weight;
}
}
throughput *= bssrdf_weight / weight;
}
return throughput;
}
/* replace closures with a single diffuse bsdf closure after scatter step */
ccl_device void subsurface_scatter_setup_diffuse_bsdf(
KernelGlobals *kg, ShaderData *sd, ClosureType type, float roughness, float3 weight, float3 N)
@ -437,7 +462,8 @@ ccl_device_noinline
ccl_addr_space PathState *state,
const ShaderClosure *sc,
const float bssrdf_u,
const float bssrdf_v)
const float bssrdf_v,
bool all)
{
/* Sample diffuse surface scatter into the object. */
float3 D;
@ -669,7 +695,7 @@ ccl_device_noinline
/* TODO: gain back performance lost from merging with disk BSSRDF. We
* only need to return on hit so this indirect ray push/pop overhead
* is not actually needed, but it does keep the code simpler. */
ss_isect->weight[0] = throughput;
ss_isect->weight[0] = subsurface_scatter_walk_eval(sd, sc, throughput, all);
#ifdef __SPLIT_KERNEL__
ss_isect->ray = *ray;
#endif
@ -691,7 +717,7 @@ ccl_device_inline int subsurface_scatter_multi_intersect(KernelGlobals *kg,
return subsurface_scatter_disk(kg, ss_isect, sd, sc, lcg_state, bssrdf_u, bssrdf_v, all);
}
else {
return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v);
return subsurface_random_walk(kg, ss_isect, sd, state, sc, bssrdf_u, bssrdf_v, all);
}
}

View File

@ -362,7 +362,7 @@ ccl_device float fast_atan2f(float y, float x)
ccl_device float fast_log2f(float x)
{
/* NOTE: clamp to avoid special cases and make result "safe" from large
* negative values/nans. */
* negative values/NAN's. */
x = clamp(x, FLT_MIN, FLT_MAX);
unsigned bits = __float_as_uint(x);
int exponent = (int)(bits >> 23) - 127;

View File

@ -22,10 +22,17 @@
#include <libavformat/avformat.h>
/* check our ffmpeg is new enough, avoids user complaints */
#if (LIBAVFORMAT_VERSION_MAJOR < 52) || \
((LIBAVFORMAT_VERSION_MAJOR == 52) && (LIBAVFORMAT_VERSION_MINOR <= 64))
# error "FFmpeg 0.7 or newer is needed, Upgrade your FFmpeg or disable it"
/* Check if our ffmpeg is new enough, avoids user complaints.
* Minimum supported version is currently 3.2.0 which mean the following library versions:
* libavutil > 55.30
* libavcodec > 57.60
* libavformat > 57.50
*
* We only check for one of these as they are usually updated in tandem.
*/
#if (LIBAVFORMAT_VERSION_MAJOR < 57) || \
((LIBAVFORMAT_VERSION_MAJOR == 57) && (LIBAVFORMAT_VERSION_MINOR <= 50))
# error "FFmpeg 3.2.0 or newer is needed, Upgrade your FFmpeg or disable it"
#endif
/* end sanity check */
@ -36,274 +43,6 @@
# define FFMPEG_INLINE static inline
#endif
#include <libavcodec/avcodec.h>
#include <libavutil/mathematics.h>
#include <libavutil/opt.h>
#include <libavutil/rational.h>
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
# define FFMPEG_HAVE_PARSE_UTILS 1
# include <libavutil/parseutils.h>
#endif
#include <libswscale/swscale.h>
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 105))
# define FFMPEG_HAVE_AVIO 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 53) || \
((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR > 1)) || \
((LIBAVCODEC_VERSION_MAJOR == 53) && (LIBAVCODEC_VERSION_MINOR == 1) && \
(LIBAVCODEC_VERSION_MICRO >= 1)) || \
((LIBAVCODEC_VERSION_MAJOR == 52) && (LIBAVCODEC_VERSION_MINOR >= 121))
# define FFMPEG_HAVE_DEFAULT_VAL_UNION 1
#endif
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 101))
# define FFMPEG_HAVE_AV_DUMP_FORMAT 1
#endif
#if (LIBAVFORMAT_VERSION_MAJOR > 52) || \
((LIBAVFORMAT_VERSION_MAJOR >= 52) && (LIBAVFORMAT_VERSION_MINOR >= 45))
# define FFMPEG_HAVE_AV_GUESS_FORMAT 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 52) || \
((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 23))
# define FFMPEG_HAVE_DECODE_AUDIO3 1
# define FFMPEG_HAVE_DECODE_VIDEO2 1
#endif
#if (LIBAVCODEC_VERSION_MAJOR > 52) || \
((LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 64))
# define FFMPEG_HAVE_AVMEDIA_TYPES 1
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 52) || \
(LIBAVCODEC_VERSION_MAJOR >= 52) && (LIBAVCODEC_VERSION_MINOR >= 29)) && \
((LIBSWSCALE_VERSION_MAJOR > 0) || \
(LIBSWSCALE_VERSION_MAJOR >= 0) && (LIBSWSCALE_VERSION_MINOR >= 10))
# define FFMPEG_SWSCALE_COLOR_SPACE_SUPPORT
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR > 14))
# define FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 53) || \
(LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 60))
# define FFMPEG_HAVE_ENCODE_AUDIO2
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 53) || \
(LIBAVCODEC_VERSION_MAJOR >= 53) && (LIBAVCODEC_VERSION_MINOR >= 42))
# define FFMPEG_HAVE_DECODE_AUDIO4
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
#endif
#if ((LIBAVUTIL_VERSION_MAJOR > 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR >= 21))
# define FFMPEG_FFV1_ALPHA_SUPPORTED
# define FFMPEG_SAMPLE_FMT_S16P_SUPPORTED
#else
FFMPEG_INLINE
int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt)
{
/* no planar formats in FFmpeg < 0.9 */
(void)sample_fmt;
return 0;
}
#endif
/* XXX TODO Probably fix to correct modern flags in code? Not sure how old FFMPEG we want to
* support though, so for now this will do. */
#ifndef FF_MIN_BUFFER_SIZE
# ifdef AV_INPUT_BUFFER_MIN_SIZE
# define FF_MIN_BUFFER_SIZE AV_INPUT_BUFFER_MIN_SIZE
# endif
#endif
#ifndef FF_INPUT_BUFFER_PADDING_SIZE
# ifdef AV_INPUT_BUFFER_PADDING_SIZE
# define FF_INPUT_BUFFER_PADDING_SIZE AV_INPUT_BUFFER_PADDING_SIZE
# endif
#endif
#ifndef CODEC_FLAG_GLOBAL_HEADER
# ifdef AV_CODEC_FLAG_GLOBAL_HEADER
# define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
# endif
#endif
#ifndef CODEC_FLAG_GLOBAL_HEADER
# ifdef AV_CODEC_FLAG_GLOBAL_HEADER
# define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER
# endif
#endif
#ifndef CODEC_FLAG_INTERLACED_DCT
# ifdef AV_CODEC_FLAG_INTERLACED_DCT
# define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT
# endif
#endif
#ifndef CODEC_FLAG_INTERLACED_ME
# ifdef AV_CODEC_FLAG_INTERLACED_ME
# define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME
# endif
#endif
/* FFmpeg upstream 1.0 is the first who added AV_ prefix. */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
# define AV_CODEC_ID_NONE CODEC_ID_NONE
# define AV_CODEC_ID_MPEG4 CODEC_ID_MPEG4
# define AV_CODEC_ID_MJPEG CODEC_ID_MJPEG
# define AV_CODEC_ID_DNXHD CODEC_ID_DNXHD
# define AV_CODEC_ID_MPEG2VIDEO CODEC_ID_MPEG2VIDEO
# define AV_CODEC_ID_MPEG1VIDEO CODEC_ID_MPEG1VIDEO
# define AV_CODEC_ID_DVVIDEO CODEC_ID_DVVIDEO
# define AV_CODEC_ID_THEORA CODEC_ID_THEORA
# define AV_CODEC_ID_PNG CODEC_ID_PNG
# define AV_CODEC_ID_QTRLE CODEC_ID_QTRLE
# define AV_CODEC_ID_FFV1 CODEC_ID_FFV1
# define AV_CODEC_ID_HUFFYUV CODEC_ID_HUFFYUV
# define AV_CODEC_ID_H264 CODEC_ID_H264
# define AV_CODEC_ID_FLV1 CODEC_ID_FLV1
# define AV_CODEC_ID_AAC CODEC_ID_AAC
# define AV_CODEC_ID_AC3 CODEC_ID_AC3
# define AV_CODEC_ID_MP3 CODEC_ID_MP3
# define AV_CODEC_ID_MP2 CODEC_ID_MP2
# define AV_CODEC_ID_FLAC CODEC_ID_FLAC
# define AV_CODEC_ID_PCM_U8 CODEC_ID_PCM_U8
# define AV_CODEC_ID_PCM_S16LE CODEC_ID_PCM_S16LE
# define AV_CODEC_ID_PCM_S24LE CODEC_ID_PCM_S24LE
# define AV_CODEC_ID_PCM_S32LE CODEC_ID_PCM_S32LE
# define AV_CODEC_ID_PCM_F32LE CODEC_ID_PCM_F32LE
# define AV_CODEC_ID_PCM_F64LE CODEC_ID_PCM_F64LE
# define AV_CODEC_ID_VORBIS CODEC_ID_VORBIS
#endif
FFMPEG_INLINE
int av_get_cropped_height_from_codec(AVCodecContext *pCodecCtx)
{
int y = pCodecCtx->height;
#ifndef FFMPEG_HAVE_CANON_H264_RESOLUTION_FIX
/* really bad hack to remove this dreadfull black bar at the bottom
with Canon footage and old ffmpeg versions.
(to fix this properly in older ffmpeg versions one has to write a new
demuxer...)
see the actual fix here for reference:
http://git.libav.org/?p=libav.git;a=commit;h=30f515091c323da59c0f1b533703dedca2f4b95d
We do our best to apply this only to matching footage.
*/
if (pCodecCtx->width == 1920 && pCodecCtx->height == 1088 &&
pCodecCtx->pix_fmt == PIX_FMT_YUVJ420P && pCodecCtx->codec_id == AV_CODEC_ID_H264) {
y = 1080;
}
#endif
return y;
}
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 22))
FFMPEG_INLINE
int av_opt_set(void *obj, const char *name, const char *val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
av_set_string3(obj, name, val, 1, &rv);
return rv != NULL;
}
FFMPEG_INLINE
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
rv = av_set_int(obj, name, val);
return rv != NULL;
}
FFMPEG_INLINE
int av_opt_set_double(void *obj, const char *name, double val, int search_flags)
{
const AVOption *rv = NULL;
(void)search_flags;
rv = av_set_double(obj, name, val);
return rv != NULL;
}
# define AV_OPT_TYPE_INT FF_OPT_TYPE_INT
# define AV_OPT_TYPE_INT64 FF_OPT_TYPE_INT64
# define AV_OPT_TYPE_STRING FF_OPT_TYPE_STRING
# define AV_OPT_TYPE_CONST FF_OPT_TYPE_CONST
# define AV_OPT_TYPE_DOUBLE FF_OPT_TYPE_DOUBLE
# define AV_OPT_TYPE_FLOAT FF_OPT_TYPE_FLOAT
#endif
#if ((LIBAVUTIL_VERSION_MAJOR < 51) || \
(LIBAVUTIL_VERSION_MAJOR == 51) && (LIBAVUTIL_VERSION_MINOR < 54))
FFMPEG_INLINE
enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt)
{
if (sample_fmt < 0 || sample_fmt >= AV_SAMPLE_FMT_NB)
return AV_SAMPLE_FMT_NONE;
return sample_fmt;
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR < 53) || \
(LIBAVCODEC_VERSION_MAJOR == 53 && LIBAVCODEC_VERSION_MINOR < 35))
FFMPEG_INLINE
int avcodec_open2(AVCodecContext *avctx, AVCodec *codec, AVDictionary **options)
{
/* TODO: no options are taking into account */
(void)options;
return avcodec_open(avctx, codec);
}
#endif
#if ((LIBAVFORMAT_VERSION_MAJOR < 53) || \
(LIBAVFORMAT_VERSION_MAJOR == 53 && LIBAVFORMAT_VERSION_MINOR < 21))
FFMPEG_INLINE
AVStream *avformat_new_stream(AVFormatContext *s, AVCodec *c)
{
/* TODO: no codec is taking into account */
(void)c;
return av_new_stream(s, 0);
}
FFMPEG_INLINE
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
{
/* TODO: no options are taking into account */
(void)options;
return av_find_stream_info(ic);
}
#endif
#if ((LIBAVFORMAT_VERSION_MAJOR > 53) || \
((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR > 32)) || \
((LIBAVFORMAT_VERSION_MAJOR == 53) && (LIBAVFORMAT_VERSION_MINOR == 24) && \
(LIBAVFORMAT_VERSION_MICRO >= 100)))
FFMPEG_INLINE
void my_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
{
@ -323,103 +62,12 @@ void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
{
my_update_cur_dts(s, ref_st, timestamp);
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR < 54) || \
(LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR < 28))
FFMPEG_INLINE
void avcodec_free_frame(AVFrame **frame)
{
/* don't need to do anything with old AVFrame
* since it does not have malloced members */
(void)frame;
}
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR >= 54) && (LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_AVFRAME_SAMPLE_RATE
#endif
#if ((LIBAVCODEC_VERSION_MAJOR > 54) || \
(LIBAVCODEC_VERSION_MAJOR == 54 && LIBAVCODEC_VERSION_MINOR >= 13))
# define FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
#endif
#ifndef FFMPEG_HAVE_AVIO
# define AVIO_FLAG_WRITE URL_WRONLY
# define avio_open url_fopen
# define avio_tell url_ftell
# define avio_close url_fclose
# define avio_size url_fsize
#endif
/* There are some version in between, which have avio_... functions but no
* AVIO_FLAG_... */
#ifndef AVIO_FLAG_WRITE
# define AVIO_FLAG_WRITE URL_WRONLY
#endif
#ifndef AV_PKT_FLAG_KEY
# define AV_PKT_FLAG_KEY PKT_FLAG_KEY
#endif
#ifndef FFMPEG_HAVE_AV_DUMP_FORMAT
# define av_dump_format dump_format
#endif
#ifndef FFMPEG_HAVE_AV_GUESS_FORMAT
# define av_guess_format guess_format
#endif
#ifndef FFMPEG_HAVE_PARSE_UTILS
# define av_parse_video_rate av_parse_video_frame_rate
#endif
#ifdef FFMPEG_HAVE_DEFAULT_VAL_UNION
# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val.i64
# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val.dbl
#else
# define FFMPEG_DEF_OPT_VAL_INT(OPT) OPT->default_val
# define FFMPEG_DEF_OPT_VAL_DOUBLE(OPT) OPT->default_val
#endif
#ifndef FFMPEG_HAVE_AVMEDIA_TYPES
# define AVMEDIA_TYPE_VIDEO CODEC_TYPE_VIDEO
# define AVMEDIA_TYPE_AUDIO CODEC_TYPE_AUDIO
#endif
#ifndef FFMPEG_HAVE_DECODE_AUDIO3
FFMPEG_INLINE
int avcodec_decode_audio3(AVCodecContext *avctx,
int16_t *samples,
int *frame_size_ptr,
AVPacket *avpkt)
{
return avcodec_decode_audio2(avctx, samples, frame_size_ptr, avpkt->data, avpkt->size);
}
#endif
#ifndef FFMPEG_HAVE_DECODE_VIDEO2
FFMPEG_INLINE
int avcodec_decode_video2(AVCodecContext *avctx,
AVFrame *picture,
int *got_picture_ptr,
AVPacket *avpkt)
{
return avcodec_decode_video(avctx, picture, got_picture_ptr, avpkt->data, avpkt->size);
}
#endif
FFMPEG_INLINE
int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame *picture)
{
int64_t pts;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 34, 100)
pts = picture->pts;
#else
pts = picture->pkt_pts;
#endif
if (pts == AV_NOPTS_VALUE) {
pts = picture->pkt_dts;
@ -432,124 +80,16 @@ int64_t av_get_pts_from_frame(AVFormatContext *avctx, AVFrame *picture)
return pts;
}
/* obsolete constant formerly defined in FFMpeg libavcodec/avcodec.h */
#ifndef AVCODEC_MAX_AUDIO_FRAME_SIZE
# define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 // 1 second of 48khz 32bit audio
#endif
/* -------------------------------------------------------------------- */
/** \name Deinterlace code block
*
* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL.
* \{ */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 1, 0)
FFMPEG_INLINE
int avcodec_encode_video2(AVCodecContext *avctx,
AVPacket *pkt,
const AVFrame *frame,
int *got_output)
{
int outsize, ret;
#define MAX_NEG_CROP 1024
ret = av_new_packet(pkt, avctx->width * avctx->height * 7 + 10000);
if (ret < 0)
return ret;
outsize = avcodec_encode_video(avctx, pkt->data, pkt->size, frame);
if (outsize <= 0) {
*got_output = 0;
av_free_packet(pkt);
}
else {
*got_output = 1;
av_shrink_packet(pkt, outsize);
if (avctx->coded_frame) {
pkt->pts = avctx->coded_frame->pts;
if (avctx->coded_frame->key_frame)
pkt->flags |= AV_PKT_FLAG_KEY;
}
}
return outsize >= 0 ? 0 : outsize;
}
#endif
#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 17, 0)
FFMPEG_INLINE
void avformat_close_input(AVFormatContext **ctx)
{
av_close_input_file(*ctx);
*ctx = NULL;
}
#endif
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 8, 0)
FFMPEG_INLINE
AVFrame *av_frame_alloc(void)
{
return avcodec_alloc_frame();
}
FFMPEG_INLINE
void av_frame_free(AVFrame **frame)
{
av_freep(frame);
}
#endif
FFMPEG_INLINE
const char *av_get_metadata_key_value(AVDictionary *metadata, const char *key)
{
if (metadata == NULL) {
return NULL;
}
AVDictionaryEntry *tag = NULL;
while ((tag = av_dict_get(metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
if (!strcmp(tag->key, key)) {
return tag->value;
}
}
return NULL;
}
FFMPEG_INLINE
bool av_check_encoded_with_ffmpeg(AVFormatContext *ctx)
{
const char *encoder = av_get_metadata_key_value(ctx->metadata, "ENCODER");
if (encoder != NULL && !strncmp(encoder, "Lavf", 4)) {
return true;
}
return false;
}
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 32, 0)
# define AV_OPT_SEARCH_FAKE_OBJ 0
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
# define FFMPEG_HAVE_DEPRECATED_FLAGS2
#endif
/* Since FFmpeg-1.1 this constant have AV_ prefix. */
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 3, 100)
# define AV_PIX_FMT_BGR32 PIX_FMT_BGR32
# define AV_PIX_FMT_YUV422P PIX_FMT_YUV422P
# define AV_PIX_FMT_BGRA PIX_FMT_BGRA
# define AV_PIX_FMT_ARGB PIX_FMT_ARGB
# define AV_PIX_FMT_RGBA PIX_FMT_RGBA
#endif
/* New API from FFmpeg-2.0 which soon became recommended one. */
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(52, 38, 100)
# define av_frame_alloc avcodec_alloc_frame
# define av_frame_free avcodec_free_frame
# define av_frame_unref avcodec_get_frame_defaults
#endif
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 24, 102)
/* NOTE: The code in this block are from FFmpeg 2.6.4, which is licensed by LGPL. */
# define MAX_NEG_CROP 1024
# define times4(x) x, x, x, x
# define times256(x) times4(times4(times4(times4(times4(x)))))
#define times4(x) x, x, x, x
#define times256(x) times4(times4(times4(times4(times4(x)))))
static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
times256(0x00), 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A,
@ -575,8 +115,8 @@ static const uint8_t ff_compat_crop_tab[256 + 2 * MAX_NEG_CROP] = {
0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
0xFB, 0xFC, 0xFD, 0xFE, 0xFF, times256(0xFF)};
# undef times4
# undef times256
#undef times4
#undef times256
/* filter parameters: [-1 4 2 4 -1] // 8 */
FFMPEG_INLINE
@ -668,8 +208,9 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int
uint8_t *src_m1, *src_0, *src_p1, *src_p2;
int y;
uint8_t *buf = (uint8_t *)av_malloc(width);
if (!buf)
if (!buf) {
return AVERROR(ENOMEM);
}
src_m1 = src1;
memcpy(buf, src_m1, width);
@ -689,24 +230,21 @@ int deinterlace_bottom_field_inplace(uint8_t *src1, int src_wrap, int width, int
return 0;
}
# ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
# endif
FFMPEG_INLINE
int avpicture_deinterlace(
AVPicture *dst, const AVPicture *src, enum AVPixelFormat pix_fmt, int width, int height)
int av_image_deinterlace(
AVFrame *dst, const AVFrame *src, enum AVPixelFormat pix_fmt, int width, int height)
{
int i, ret;
if (pix_fmt != AV_PIX_FMT_YUV420P && pix_fmt != AV_PIX_FMT_YUVJ420P &&
pix_fmt != AV_PIX_FMT_YUV422P && pix_fmt != AV_PIX_FMT_YUVJ422P &&
pix_fmt != AV_PIX_FMT_YUV444P && pix_fmt != AV_PIX_FMT_YUV411P &&
pix_fmt != AV_PIX_FMT_GRAY8)
pix_fmt != AV_PIX_FMT_GRAY8) {
return -1;
if ((width & 3) != 0 || (height & 3) != 0)
}
if ((width & 3) != 0 || (height & 3) != 0) {
return -1;
}
for (i = 0; i < 3; i++) {
if (i == 1) {
@ -732,8 +270,9 @@ int avpicture_deinterlace(
}
if (src == dst) {
ret = deinterlace_bottom_field_inplace(dst->data[i], dst->linesize[i], width, height);
if (ret < 0)
if (ret < 0) {
return ret;
}
}
else {
deinterlace_bottom_field(
@ -743,10 +282,6 @@ int avpicture_deinterlace(
return 0;
}
# ifdef __GNUC__
# pragma GCC diagnostic pop
# endif
#endif
/** \} Deinterlace code block */
#endif

View File

@ -112,8 +112,7 @@ GHOST_DropTargetX11::~GHOST_DropTargetX11()
}
}
/* based on a code from Saul Rennison
* http://stackoverflow.com/questions/2673207/c-c-url-decode-library */
/* Based on: https://stackoverflow.com/a/2766963/432509 */
typedef enum DecodeState_e {
STATE_SEARCH = 0, ///< searching for an ampersand to convert

View File

@ -1711,7 +1711,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr)
dx = [event scrollingDeltaX];
dy = [event scrollingDeltaY];
/* However, wacom tablet (intuos5) needs old deltas,
/* However, Wacom tablet (intuos5) needs old deltas,
* it then has momentum and phase at zero. */
if (phase == NSEventPhaseNone && momentumPhase == NSEventPhaseNone) {
dx = [event deltaX];

View File

@ -55,7 +55,6 @@ void *GHOST_XrContext::s_error_handler_customdata = nullptr;
/* -------------------------------------------------------------------- */
/** \name Create, Initialize and Destruct
*
* \{ */
GHOST_XrContext::GHOST_XrContext(const GHOST_XrContextCreateInfo *create_info)
@ -153,7 +152,6 @@ void GHOST_XrContext::storeInstanceProperties()
/* -------------------------------------------------------------------- */
/** \name Debug Printing
*
* \{ */
void GHOST_XrContext::printInstanceInfo()
@ -242,7 +240,6 @@ void GHOST_XrContext::initDebugMessenger()
/* -------------------------------------------------------------------- */
/** \name Error handling
*
* \{ */
void GHOST_XrContext::dispatchErrorMessage(const GHOST_XrException *exception) const
@ -273,7 +270,6 @@ void GHOST_XrContext::setErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *c
/* -------------------------------------------------------------------- */
/** \name OpenXR API-Layers and Extensions
*
* \{ */
/**
@ -564,7 +560,6 @@ bool GHOST_XrContext::needsUpsideDownDrawing() const
/* -------------------------------------------------------------------- */
/** \name Ghost Internal Accessors and Mutators
*
* \{ */
GHOST_TXrOpenXRRuntimeID GHOST_XrContext::getOpenXRRuntimeID() const

View File

@ -59,7 +59,6 @@ struct GHOST_XrDrawInfo {
/* -------------------------------------------------------------------- */
/** \name Create, Initialize and Destruct
*
* \{ */
GHOST_XrSession::GHOST_XrSession(GHOST_XrContext &xr_context)
@ -110,7 +109,6 @@ void GHOST_XrSession::initSystem()
/* -------------------------------------------------------------------- */
/** \name State Management
*
* \{ */
static void create_reference_spaces(OpenXRSessionData &oxr, const GHOST_XrPose &base_pose)
@ -245,7 +243,6 @@ GHOST_XrSession::LifeExpectancy GHOST_XrSession::handleStateChangeEvent(
/* -------------------------------------------------------------------- */
/** \name Drawing
*
* \{ */
void GHOST_XrSession::prepareDrawing()
@ -457,7 +454,6 @@ bool GHOST_XrSession::needsUpsideDownDrawing() const
/* -------------------------------------------------------------------- */
/** \name State Queries
*
* \{ */
bool GHOST_XrSession::isRunning() const

@ -1 +1 @@
Subproject commit d2d33a435d358fcd0ae7f3e2cd67bee2b500ec53
Subproject commit 5ab29b1331d2103dae634b987f121c4599459d7f

@ -1 +1 @@
Subproject commit eb3952fcd26e9897bcc0128eab925b070c0e7593
Subproject commit bb16aba5bd3873794eefe167497118b6063b9a85

View File

@ -305,7 +305,7 @@ url_manual_mapping = (
("bpy.types.geometrynodealignrotationtovector*", "modeling/geometry_nodes/point/align_rotation_to_vector.html#bpy-types-geometrynodealignrotationtovector"),
("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"),
("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-use-crease-override"),
("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"),
("bpy.types.rendersettings.preview_pixel_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-preview-pixel-size"),
("bpy.types.rendersettings.use_crop_to_border*", "render/output/properties/dimensions.html#bpy-types-rendersettings-use-crop-to-border"),
("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"),
@ -449,7 +449,7 @@ url_manual_mapping = (
("bpy.types.nodesocketinterface*.max_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-max-value"),
("bpy.types.nodesocketinterface*.min_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-min-value"),
("bpy.types.nodesocketinterface.hide_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-hide-value"),
("bpy.types.objectlineart.crease_threshold*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-crease-threshold"),
("bpy.types.objectlineart.crease_threshold*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-crease-threshold"),
("bpy.types.rendersettings.use_compositing*", "render/output/properties/post_processing.html#bpy-types-rendersettings-use-compositing"),
("bpy.types.rendersettings.use_placeholder*", "render/output/properties/output.html#bpy-types-rendersettings-use-placeholder"),
("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"),
@ -487,6 +487,7 @@ url_manual_mapping = (
("bpy.types.fluidflowsettings.temperature*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-temperature"),
("bpy.types.fluidflowsettings.use_texture*", "physics/fluid/type/flow.html#bpy-types-fluidflowsettings-use-texture"),
("bpy.types.fmodifierenvelopecontrolpoint*", "editors/graph_editor/fcurves/sidebar/modifiers.html#bpy-types-fmodifierenvelopecontrolpoint"),
("bpy.types.geometrynodeattributemaprange*", "modeling/geometry_nodes/attribute/attribute_map_range.html#bpy-types-geometrynodeattributemaprange"),
("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"),
("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"),
("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"),
@ -947,7 +948,7 @@ url_manual_mapping = (
("bpy.types.imagepaint.use_occlude*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-occlude"),
("bpy.types.imagesequence.use_flip*", "video_editing/sequencer/sidebar/strip.html#bpy-types-imagesequence-use-flip"),
("bpy.types.latticegpencilmodifier*", "grease_pencil/modifiers/deform/lattice.html#bpy-types-latticegpencilmodifier"),
("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/lineart.html#bpy-types-lineartgpencilmodifier"),
("bpy.types.lineartgpencilmodifier*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier"),
("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"),
("bpy.types.objectsolverconstraint*", "animation/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"),
("bpy.types.opacitygpencilmodifier*", "grease_pencil/modifiers/color/opacity.html#bpy-types-opacitygpencilmodifier"),
@ -1110,6 +1111,7 @@ url_manual_mapping = (
("bpy.types.ffmpegsettings.audio*", "render/output/properties/output.html#bpy-types-ffmpegsettings-audio"),
("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"),
("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"),
("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/bounding_box.html#bpy-types-geometrynodeboundbox"),
("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh_primitives/cone.html#bpy-types-geometrynodemeshcone"),
("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh_primitives/cube.html#bpy-types-geometrynodemeshcube"),
("bpy.types.geometrynodemeshgrid*", "modeling/geometry_nodes/mesh_primitives/grid.html#bpy-types-geometrynodemeshgrid"),
@ -1152,6 +1154,7 @@ url_manual_mapping = (
("bpy.ops.clip.set_scene_frames*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-set-scene-frames"),
("bpy.ops.curve.handle_type_set*", "modeling/curves/editing/control_points.html#bpy-ops-curve-handle-type-set"),
("bpy.ops.curve.spline_type_set*", "modeling/curves/editing/curve.html#bpy-ops-curve-spline-type-set"),
("bpy.ops.file.unpack_libraries*", "files/blend/packed_data.html#bpy-ops-file-unpack-libraries"),
("bpy.ops.gpencil.move_to_layer*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-move-to-layer"),
("bpy.ops.gpencil.stroke_sample*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-sample"),
("bpy.ops.gpencil.stroke_smooth*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-stroke-smooth"),
@ -1219,7 +1222,7 @@ url_manual_mapping = (
("bpy.types.mesh.use_paint_mask*", "sculpt_paint/brush/introduction.html#bpy-types-mesh-use-paint-mask"),
("bpy.types.movietrackingcamera*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera"),
("bpy.types.object.display_type*", "scene_layout/object/properties/display.html#bpy-types-object-display-type"),
("bpy.types.objectlineart.usage*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart-usage"),
("bpy.types.objectlineart.usage*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-usage"),
("bpy.types.particledupliweight*", "physics/particles/emitter/vertex_groups.html#bpy-types-particledupliweight"),
("bpy.types.poseboneconstraints*", "animation/armatures/posing/bone_constraints/index.html#bpy-types-poseboneconstraints"),
("bpy.types.rigidbodyconstraint*", "physics/rigid_body/constraints/index.html#bpy-types-rigidbodyconstraint"),
@ -1260,6 +1263,7 @@ url_manual_mapping = (
("bpy.ops.console.autocomplete*", "editors/python_console.html#bpy-ops-console-autocomplete"),
("bpy.ops.curve.dissolve_verts*", "modeling/curves/editing/curve.html#bpy-ops-curve-dissolve-verts"),
("bpy.ops.curve.duplicate_move*", "modeling/curves/editing/curve.html#bpy-ops-curve-duplicate-move"),
("bpy.ops.file.autopack_toggle*", "files/blend/packed_data.html#bpy-ops-file-autopack-toggle"),
("bpy.ops.fluid.bake_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-ops-fluid-bake-particles"),
("bpy.ops.fluid.free_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-ops-fluid-free-particles"),
("bpy.ops.gpencil.extrude_move*", "grease_pencil/modes/edit/point_menu.html#bpy-ops-gpencil-extrude-move"),
@ -1297,6 +1301,7 @@ url_manual_mapping = (
("bpy.types.alphaundersequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaundersequence"),
("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"),
("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"),
("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"),
("bpy.types.compositornodecomb*", "editors/texture_node/types/color/combine_separate.html#bpy-types-compositornodecomb"),
("bpy.types.compositornodecrop*", "compositing/types/distort/crop.html#bpy-types-compositornodecrop"),
("bpy.types.compositornodeflip*", "compositing/types/distort/flip.html#bpy-types-compositornodeflip"),
@ -1358,6 +1363,7 @@ url_manual_mapping = (
("bpy.ops.curve.primitive*add*", "modeling/curves/primitives.html#bpy-ops-curve-primitive-add"),
("bpy.ops.curve.smooth_radius*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-radius"),
("bpy.ops.curve.smooth_weight*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-weight"),
("bpy.ops.file.pack_libraries*", "files/blend/packed_data.html#bpy-ops-file-pack-libraries"),
("bpy.ops.font.change_spacing*", "modeling/texts/editing.html#bpy-ops-font-change-spacing"),
("bpy.ops.gpencil.stroke_flip*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-flip"),
("bpy.ops.gpencil.stroke_join*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-join"),
@ -1453,7 +1459,7 @@ url_manual_mapping = (
("bpy.types.viewlayer.use_sky*", "render/layers/introduction.html#bpy-types-viewlayer-use-sky"),
("bpy.types.wireframemodifier*", "modeling/modifiers/generate/wireframe.html#bpy-types-wireframemodifier"),
("bpy.types.worldmistsettings*", "render/cycles/world_settings.html#bpy-types-worldmistsettings"),
("bpy.ops.anim.channels_move*", "editors/nla/editing.html#bpy-ops-anim-channels-move"),
("bpy.ops.anim.channels_move*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-move"),
("bpy.ops.buttons.toggle_pin*", "editors/properties_editor.html#bpy-ops-buttons-toggle-pin"),
("bpy.ops.clip.filter_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-filter-tracks"),
("bpy.ops.clip.select_circle*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-circle"),
@ -1691,6 +1697,7 @@ url_manual_mapping = (
("bpy.ops.clip.set_origin*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-origin"),
("bpy.ops.curve.subdivide*", "modeling/curves/editing/segments.html#bpy-ops-curve-subdivide"),
("bpy.ops.ed.undo_history*", "interface/undo_redo.html#bpy-ops-ed-undo-history"),
("bpy.ops.file.unpack_all*", "files/blend/packed_data.html#bpy-ops-file-unpack-all"),
("bpy.ops.fluid.bake_data*", "physics/fluid/type/domain/settings.html#bpy-ops-fluid-bake-data"),
("bpy.ops.fluid.bake_mesh*", "physics/fluid/type/domain/liquid/mesh.html#bpy-ops-fluid-bake-mesh"),
("bpy.ops.fluid.free_data*", "physics/fluid/type/domain/settings.html#bpy-ops-fluid-free-data"),
@ -1749,7 +1756,7 @@ url_manual_mapping = (
("bpy.types.nlastrip.name*", "editors/nla/sidebar.html#bpy-types-nlastrip-name"),
("bpy.types.nodesmodifier*", "modeling/modifiers/generate/geometry_nodes.html#bpy-types-nodesmodifier"),
("bpy.types.object.parent*", "scene_layout/object/editing/parent.html#bpy-types-object-parent"),
("bpy.types.objectlineart*", "scene_layout/object/properties/lineart.html#bpy-types-objectlineart"),
("bpy.types.objectlineart*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart"),
("bpy.types.oceanmodifier*", "modeling/modifiers/physics/ocean.html#bpy-types-oceanmodifier"),
("bpy.types.particlebrush*", "physics/particles/mode.html#bpy-types-particlebrush"),
("bpy.types.scene.gravity*", "physics/forces/gravity.html#bpy-types-scene-gravity"),
@ -1845,6 +1852,7 @@ url_manual_mapping = (
("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"),
("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"),
("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"),
("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"),
("bpy.ops.gpencil.paste*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-paste"),
("bpy.ops.image.project*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-ops-image-project"),
("bpy.ops.material.copy*", "render/materials/assignment.html#bpy-ops-material-copy"),
@ -2115,9 +2123,4 @@ url_manual_mapping = (
("bpy.ops.ed*", "interface/undo_redo.html#bpy-ops-ed"),
("bpy.ops.ui*", "interface/index.html#bpy-ops-ui"),
("bpy.ops.wm*", "interface/index.html#bpy-ops-wm"),
("bpy.ops.file.pack_all", "blend/packed_data#pack-resources"),
("bpy.ops.file.unpack_all", "blend/packed_data#unpack-resources"),
("bpy.ops.file.autopack_toggle", "blend/packed_data#automatically-pack-resources"),
("bpy.ops.file.pack_libraries", "blend/packed_data#pack-linked-libraries"),
("bpy.ops.file.unpack_libraries", "blend/packed_data#unpack-linked-libraries"),
)

View File

@ -278,15 +278,11 @@ def _template_items_uv_select_mode(params):
else:
return [
*_template_items_editmode_mesh_select_mode(params),
# Hack to prevent fall-through, when sync select isn't enabled (and the island button isn't visible).
("mesh.select_mode", {"type": 'FOUR', "value": 'PRESS'}, None),
("wm.context_set_enum", {"type": 'ONE', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'VERTEX')]}),
("wm.context_set_enum", {"type": 'TWO', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'EDGE')]}),
("wm.context_set_enum", {"type": 'THREE', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'FACE')]}),
("wm.context_set_enum", {"type": 'FOUR', "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", 'ISLAND')]}),
*(("wm.context_set_enum", {"type": NUMBERS_1[i], "value": 'PRESS'},
{"properties": [("data_path", 'tool_settings.uv_select_mode'), ("value", ty)]})
for i, ty in enumerate(('VERTEX', 'EDGE', 'FACE', 'ISLAND')))
]
@ -2009,8 +2005,7 @@ def km_file_browser_main(params):
)
items.extend([
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
# Both .execute and .select are needed here. The former only works if
# there's a file operator (i.e. not in regular editor mode) but is
# needed to load files. The latter makes selection work if there's no
@ -3382,6 +3377,11 @@ def km_grease_pencil_stroke_paint_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Draw delete menu
op_menu("GPENCIL_MT_gpencil_draw_delete", {"type": 'X', "value": 'PRESS'}),
# Animation menu
@ -3549,6 +3549,11 @@ def km_grease_pencil_stroke_sculpt_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_sculpt_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Copy
("gpencil.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None),
# Display
@ -3763,6 +3768,11 @@ def km_grease_pencil_stroke_weight_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_weight_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Display
*_grease_pencil_display(),
# Keyframe menu
@ -3820,6 +3830,11 @@ def km_grease_pencil_stroke_vertex_mode(params):
# Brush size
("wm.radial_control", {"type": 'F', "value": 'PRESS'},
{"properties": [("data_path_primary", 'tool_settings.gpencil_vertex_paint.brush.size')]}),
# Increase/Decrease brush size
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
# Display
*_grease_pencil_display(),
# Tools

View File

@ -1263,8 +1263,7 @@ def km_file_browser_main(params):
)
items.extend([
("file.execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'},
{"properties": [("need_active", True)]}),
("file.mouse_execute", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.refresh", {"type": 'R', "value": 'PRESS', "ctrl": True}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'DOUBLE_CLICK'}, None),
("file.select", {"type": 'LEFTMOUSE', "value": 'CLICK'},

View File

@ -130,6 +130,7 @@ class PlayRenderedAnim(Operator):
"-s", str(frame_start),
"-e", str(frame_end),
"-j", str(scene.frame_step),
"-c", str(prefs.system.memory_cache_limit),
file,
]
cmd.extend(opts)

View File

@ -292,10 +292,15 @@ class BONE_PT_display_custom_shape(BoneButtonsPanel, Panel):
sub = col.column()
sub.active = bool(pchan and pchan.custom_shape)
sub.separator()
sub.prop(pchan, "custom_shape_scale", text="Scale")
sub.prop(pchan, "custom_shape_scale_xyz", text="Scale")
sub.prop(pchan, "custom_shape_translation", text="Translation")
sub.prop(pchan, "custom_shape_rotation_euler", text="Rotation")
sub.prop_search(pchan, "custom_shape_transform",
ob.pose, "bones", text="Override Transform")
sub.prop(pchan, "use_custom_shape_bone_size")
sub.separator()
sub.prop(bone, "show_wire", text="Wireframe")

View File

@ -113,7 +113,8 @@ class GPENCIL_MT_layer_context_menu(Menu):
layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_copy_layer")
layout.menu("VIEW3D_MT_gpencil_append_active_layer")
layout.menu("VIEW3D_MT_gpencil_append_all_layers")
class DATA_PT_gpencil_layers(DataButtonsPanel, Panel):

View File

@ -53,6 +53,10 @@ class GPENCIL_MT_material_context_menu(Menu):
layout.operator("gpencil.material_to_vertex_color", text="Convert Materials to Vertex Color")
layout.operator("gpencil.extract_palette_vertex", text="Extract Palette from Vertex Color")
layout.separator()
layout.menu("VIEW3D_MT_gpencil_append_active_material")
layout.menu("VIEW3D_MT_gpencil_append_all_materials")
class GPENCIL_UL_matslots(UIList):
def draw_item(self, _context, layout, _data, item, icon, _active_data, _active_propname, _index):

View File

@ -1289,7 +1289,7 @@ def brush_basic_gpencil_paint_settings(layout, context, brush, *, compact=False)
row = layout.row(align=True)
row.prop(gp_settings, "fill_factor")
row = layout.row(align=True)
row.prop(gp_settings, "dilate_pixels")
row.prop(gp_settings, "dilate")
row = layout.row(align=True)
row.prop(brush, "size", text="Thickness")
layout.use_property_split = use_property_split_prev

View File

@ -300,6 +300,8 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel):
col.label(text="New Keyframe Type")
col.prop(tool_settings, "keyframe_type", text="")
layout.prop(tool_settings, "use_keyframe_cycle_aware")
class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
bl_label = "Auto Keyframing"
@ -327,8 +329,6 @@ class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel):
if not prefs.edit.use_keyframe_insert_available:
col.prop(tool_settings, "use_record_with_nla", text="Layered Recording")
col.prop(tool_settings, "use_keyframe_cycle_aware")
###################################

View File

@ -4956,26 +4956,73 @@ class VIEW3D_MT_assign_material(Menu):
icon='LAYER_ACTIVE' if mat == mat_active else 'BLANK1').material = mat.name
class VIEW3D_MT_gpencil_copy_layer(Menu):
bl_label = "Copy Layer to Object"
def gpencil_layer_append_menu_items(context, layout, only_active):
done = False
view_layer = context.view_layer
obact = context.active_object
gpl = context.active_gpencil_layer
done = False
if gpl is not None:
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
op = layout.operator("gpencil.layer_duplicate_object", text=ob.name)
op.object = ob.name
op.only_active = only_active
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
else:
layout.label(text="No layer to copy", icon='ERROR')
class VIEW3D_MT_gpencil_append_active_layer(Menu):
bl_label = "Append Active Layer to Object"
def draw(self, context):
layout = self.layout
view_layer = context.view_layer
obact = context.active_object
gpl = context.active_gpencil_layer
gpencil_layer_append_menu_items(context, layout, True)
done = False
if gpl is not None:
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
layout.operator("gpencil.layer_duplicate_object", text=ob.name).object = ob.name
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
else:
layout.label(text="No layer to copy", icon='ERROR')
class VIEW3D_MT_gpencil_append_all_layers(Menu):
bl_label = "Append All Layers to Object"
def draw(self, context):
layout = self.layout
gpencil_layer_append_menu_items(context, layout, False)
def gpencil_material_menu_items(context, layout, only_selected):
done = False
view_layer = context.view_layer
obact = context.active_object
for ob in view_layer.objects:
if ob.type == 'GPENCIL' and ob != obact:
op = layout.operator("gpencil.materials_append_to_object", text=ob.name)
op.object = ob.name
op.only_selected = only_selected
done = True
if done is False:
layout.label(text="No destination object", icon='ERROR')
class VIEW3D_MT_gpencil_append_active_material(Menu):
bl_label = "Append Active Material to Object"
def draw(self, context):
layout = self.layout
gpencil_material_menu_items(context, layout, True)
class VIEW3D_MT_gpencil_append_all_materials(Menu):
bl_label = "Append All Materials to Object"
def draw(self, context):
layout = self.layout
gpencil_material_menu_items(context, layout, False)
class VIEW3D_MT_edit_gpencil(Menu):
@ -6191,10 +6238,7 @@ class VIEW3D_PT_overlay_geometry(Panel):
sub.prop(overlay, "wireframe_opacity", text="Opacity")
row = col.row(align=True)
if context.mode not in {
'EDIT_ARMATURE', 'POSE', 'OBJECT',
'PAINT_GPENCIL', 'VERTEX_GPENCIL', 'WEIGHT_GPENCIL', 'SCULPT_GPENCIL', 'EDIT_GPENCIL',
}:
if context.mode != 'OBJECT':
row.prop(overlay, "show_fade_inactive", text="")
sub = row.row()
sub.active = overlay.show_fade_inactive
@ -7645,7 +7689,10 @@ classes = (
VIEW3D_MT_weight_gpencil,
VIEW3D_MT_gpencil_animation,
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_gpencil_copy_layer,
VIEW3D_MT_gpencil_append_active_layer,
VIEW3D_MT_gpencil_append_all_layers,
VIEW3D_MT_gpencil_append_active_material,
VIEW3D_MT_gpencil_append_all_materials,
VIEW3D_MT_gpencil_autoweights,
VIEW3D_MT_gpencil_edit_context_menu,
VIEW3D_MT_edit_curve,

View File

@ -488,11 +488,13 @@ geometry_node_categories = [
NodeItem("GeometryNodeAttributeClamp"),
NodeItem("GeometryNodeAttributeCompare"),
NodeItem("GeometryNodeAttributeConvert"),
NodeItem("GeometryNodeAttributeCurveMap"),
NodeItem("GeometryNodeAttributeFill"),
NodeItem("GeometryNodeAttributeMix"),
NodeItem("GeometryNodeAttributeProximity"),
NodeItem("GeometryNodeAttributeColorRamp"),
NodeItem("GeometryNodeAttributeVectorMath"),
NodeItem("GeometryNodeAttributeVectorRotate"),
NodeItem("GeometryNodeAttributeSampleTexture"),
NodeItem("GeometryNodeAttributeCombineXYZ"),
NodeItem("GeometryNodeAttributeSeparateXYZ"),
@ -507,6 +509,7 @@ geometry_node_categories = [
]),
GeometryNodeCategory("GEO_CURVE", "Curve", items=[
NodeItem("GeometryNodeCurveToMesh"),
NodeItem("GeometryNodeCurveResample"),
]),
GeometryNodeCategory("GEO_GEOMETRY", "Geometry", items=[
NodeItem("GeometryNodeBoundBox"),

View File

@ -597,6 +597,7 @@ class InstancesComponent : public GeometryComponent {
void clear();
void reserve(int min_capacity);
void resize(int capacity);
int add_reference(InstanceReference reference);
void add_instance(int instance_handle, const blender::float4x4 &transform, const int id = -1);
@ -604,6 +605,7 @@ class InstancesComponent : public GeometryComponent {
blender::Span<InstanceReference> references() const;
blender::Span<int> instance_reference_handles() const;
blender::MutableSpan<int> instance_reference_handles();
blender::MutableSpan<blender::float4x4> instance_transforms();
blender::Span<blender::float4x4> instance_transforms() const;
blender::MutableSpan<int> instance_ids();

View File

@ -85,10 +85,12 @@ bool BKE_lib_override_library_resync(struct Main *bmain,
struct ID *id_root,
struct Collection *override_resync_residual_storage,
const bool do_hierarchy_enforce,
const bool do_post_process);
const bool do_post_process,
struct ReportList *reports);
void BKE_lib_override_library_main_resync(struct Main *bmain,
struct Scene *scene,
struct ViewLayer *view_layer);
struct ViewLayer *view_layer,
struct ReportList *reports);
void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root);

View File

@ -446,8 +446,8 @@ bool BKE_modifier_is_preview(struct ModifierData *md);
void BKE_modifiers_foreach_ID_link(struct Object *ob, IDWalkFunc walk, void *userData);
void BKE_modifiers_foreach_tex_link(struct Object *ob, TexWalkFunc walk, void *userData);
struct ModifierData *BKE_modifiers_findby_type(struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(struct Object *ob, const char *name);
struct ModifierData *BKE_modifiers_findby_type(const struct Object *ob, ModifierType type);
struct ModifierData *BKE_modifiers_findby_name(const struct Object *ob, const char *name);
void BKE_modifiers_clear_errors(struct Object *ob);
int BKE_modifiers_get_cage_index(const struct Scene *scene,
struct Object *ob,

View File

@ -1419,6 +1419,9 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_SWITCH 1043
#define GEO_NODE_ATTRIBUTE_TRANSFER 1044
#define GEO_NODE_CURVE_TO_MESH 1045
#define GEO_NODE_ATTRIBUTE_CURVE_MAP 1046
#define GEO_NODE_CURVE_RESAMPLE 1047
#define GEO_NODE_ATTRIBUTE_VECTOR_ROTATE 1048
/** \} */

View File

@ -1,153 +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.
*/
#pragma once
/** \file
* \ingroup bke
*
* A PersistentDataHandle is a weak reference to some data in a Blender file. The handle itself is
* just a number. A PersistentDataHandleMap is used to convert between handles and the actual data.
*/
#include "BLI_map.hh"
#include "DNA_ID.h"
struct Collection;
struct Object;
namespace blender::bke {
class PersistentDataHandleMap;
class PersistentDataHandle {
private:
/* Negative values indicate that the handle is "empty". */
int32_t handle_;
friend PersistentDataHandleMap;
protected:
PersistentDataHandle(int handle) : handle_(handle)
{
}
public:
PersistentDataHandle() : handle_(-1)
{
}
friend bool operator==(const PersistentDataHandle &a, const PersistentDataHandle &b)
{
return a.handle_ == b.handle_;
}
friend bool operator!=(const PersistentDataHandle &a, const PersistentDataHandle &b)
{
return !(a == b);
}
friend std::ostream &operator<<(std::ostream &stream, const PersistentDataHandle &a)
{
stream << a.handle_;
return stream;
}
uint64_t hash() const
{
return static_cast<uint64_t>(handle_);
}
};
class PersistentIDHandle : public PersistentDataHandle {
friend PersistentDataHandleMap;
using PersistentDataHandle::PersistentDataHandle;
};
class PersistentObjectHandle : public PersistentIDHandle {
friend PersistentDataHandleMap;
using PersistentIDHandle::PersistentIDHandle;
};
class PersistentCollectionHandle : public PersistentIDHandle {
friend PersistentDataHandleMap;
using PersistentIDHandle::PersistentIDHandle;
};
class PersistentDataHandleMap {
private:
Map<int32_t, ID *> id_by_handle_;
Map<ID *, int32_t> handle_by_id_;
public:
void add(int32_t handle, ID &id)
{
BLI_assert(handle >= 0);
handle_by_id_.add(&id, handle);
id_by_handle_.add(handle, &id);
}
PersistentIDHandle lookup(ID *id) const
{
const int handle = handle_by_id_.lookup_default(id, -1);
return PersistentIDHandle(handle);
}
PersistentObjectHandle lookup(Object *object) const
{
const int handle = handle_by_id_.lookup_default((ID *)object, -1);
return PersistentObjectHandle(handle);
}
PersistentCollectionHandle lookup(Collection *collection) const
{
const int handle = handle_by_id_.lookup_default((ID *)collection, -1);
return PersistentCollectionHandle(handle);
}
ID *lookup(const PersistentIDHandle &handle) const
{
ID *id = id_by_handle_.lookup_default(handle.handle_, nullptr);
return id;
}
Object *lookup(const PersistentObjectHandle &handle) const
{
ID *id = this->lookup((const PersistentIDHandle &)handle);
if (id == nullptr) {
return nullptr;
}
if (GS(id->name) != ID_OB) {
return nullptr;
}
return (Object *)id;
}
Collection *lookup(const PersistentCollectionHandle &handle) const
{
ID *id = this->lookup((const PersistentIDHandle &)handle);
if (id == nullptr) {
return nullptr;
}
if (GS(id->name) != ID_GR) {
return nullptr;
}
return (Collection *)id;
}
};
} // namespace blender::bke

View File

@ -47,7 +47,7 @@ typedef struct BodyPoint {
} BodyPoint;
/* allocates and initializes general main data */
extern struct SoftBody *sbNew(struct Scene *scene);
extern struct SoftBody *sbNew(void);
/* frees internal data and soft-body itself */
extern void sbFree(struct Object *ob);

View File

@ -113,6 +113,7 @@ class Spline {
bool is_cyclic() const;
void set_cyclic(const bool value);
virtual void resize(const int size) = 0;
virtual blender::MutableSpan<blender::float3> positions() = 0;
virtual blender::Span<blender::float3> positions() const = 0;
virtual blender::MutableSpan<float> radii() = 0;
@ -163,6 +164,9 @@ class Spline {
LookupResult lookup_evaluated_factor(const float factor) const;
LookupResult lookup_evaluated_length(const float length) const;
blender::Array<float> sample_uniform_index_factors(const int samples_size) const;
LookupResult lookup_data_from_index_factor(const float index_factor) const;
/**
* Interpolate a virtual array of data with the size of the number of control points to the
* evaluated points. For poly splines, the lifetime of the returned virtual array must not
@ -194,15 +198,17 @@ class BezierSpline final : public Spline {
};
private:
blender::Vector<HandleType> handle_types_left_;
blender::Vector<blender::float3> handle_positions_left_;
blender::Vector<blender::float3> positions_;
blender::Vector<HandleType> handle_types_right_;
blender::Vector<blender::float3> handle_positions_right_;
blender::Vector<float> radii_;
blender::Vector<float> tilts_;
int resolution_;
blender::Vector<HandleType> handle_types_left_;
blender::Vector<HandleType> handle_types_right_;
blender::Vector<blender::float3> handle_positions_left_;
blender::Vector<blender::float3> handle_positions_right_;
/** Start index in evaluated points array for every control point. */
mutable blender::Vector<int> offset_cache_;
mutable std::mutex offset_cache_mutex_;
@ -225,14 +231,14 @@ class BezierSpline final : public Spline {
}
BezierSpline(const BezierSpline &other)
: Spline((Spline &)other),
handle_types_left_(other.handle_types_left_),
handle_positions_left_(other.handle_positions_left_),
positions_(other.positions_),
handle_types_right_(other.handle_types_right_),
handle_positions_right_(other.handle_positions_right_),
radii_(other.radii_),
tilts_(other.tilts_),
resolution_(other.resolution_)
resolution_(other.resolution_),
handle_types_left_(other.handle_types_left_),
handle_types_right_(other.handle_types_right_),
handle_positions_left_(other.handle_positions_left_),
handle_positions_right_(other.handle_positions_right_)
{
}
@ -248,6 +254,7 @@ class BezierSpline final : public Spline {
const float radius,
const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@ -286,7 +293,7 @@ class BezierSpline final : public Spline {
InterpolationData interpolation_data_from_index_factor(const float index_factor) const;
virtual blender::fn::GVArrayPtr interpolate_to_evaluated_points(
const blender::fn::GVArray &source_data) const;
const blender::fn::GVArray &source_data) const override;
private:
void correct_end_tangents() const final;
@ -294,7 +301,6 @@ class BezierSpline final : public Spline {
void evaluate_bezier_segment(const int index,
const int next_index,
blender::MutableSpan<blender::float3> positions) const;
blender::Array<int> evaluated_point_offsets() const;
};
/**
@ -387,6 +393,7 @@ class NURBSpline final : public Spline {
bool check_valid_size_and_order() const;
int knots_size() const;
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;
@ -441,6 +448,7 @@ class PolySpline final : public Spline {
void add_point(const blender::float3 position, const float radius, const float tilt);
void resize(const int size) final;
blender::MutableSpan<blender::float3> positions() final;
blender::Span<blender::float3> positions() const final;
blender::MutableSpan<float> radii() final;

View File

@ -112,7 +112,7 @@ set(SRC
intern/curve_convert.c
intern/curve_decimate.c
intern/curve_deform.c
intern/curve_eval.cc
intern/curve_eval.cc
intern/curveprofile.c
intern/customdata.c
intern/customdata_file.c
@ -407,7 +407,6 @@ set(SRC
BKE_paint.h
BKE_particle.h
BKE_pbvh.h
BKE_persistent_data_handle.hh
BKE_pointcache.h
BKE_pointcloud.h
BKE_preferences.h
@ -593,10 +592,6 @@ if(WITH_CODEC_FFMPEG)
${FFMPEG_LIBRARIES}
)
add_definitions(-DWITH_FFMPEG)
remove_strict_c_flags_file(
intern/writeffmpeg.c
)
endif()
if(WITH_PYTHON)

View File

@ -1861,7 +1861,7 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph,
/* Ensure normals calculation below is correct (normal settings have transferred properly).
* However, nodes modifiers might create meshes from scratch or transfer meshes from other
* objects with different settings, and in general it doesn't make sense to guarentee that
* objects with different settings, and in general it doesn't make sense to guarantee that
* the settings are the same as the original mesh. If necessary, this could become a modifier
* type flag. */
BLI_assert(mesh_input->smoothresh == mesh_cage->smoothresh);

View File

@ -656,7 +656,9 @@ bPoseChannel *BKE_pose_channel_ensure(bPose *pose, const char *name)
BLI_strncpy(chan->name, name, sizeof(chan->name));
chan->custom_scale = 1.0f;
copy_v3_fl(chan->custom_scale_xyz, 1.0f);
zero_v3(chan->custom_translation);
zero_v3(chan->custom_rotation_euler);
/* init vars to prevent math errors */
unit_qt(chan->quat);
@ -1235,8 +1237,10 @@ void BKE_pose_channel_copy_data(bPoseChannel *pchan, const bPoseChannel *pchan_f
if (pchan->custom) {
id_us_plus(&pchan->custom->id);
}
copy_v3_v3(pchan->custom_scale_xyz, pchan_from->custom_scale_xyz);
copy_v3_v3(pchan->custom_translation, pchan_from->custom_translation);
copy_v3_v3(pchan->custom_rotation_euler, pchan_from->custom_rotation_euler);
pchan->custom_scale = pchan_from->custom_scale;
pchan->drawflag = pchan_from->drawflag;
}

View File

@ -2881,7 +2881,8 @@ bool BKE_pose_minmax(Object *ob, float r_min[3], float r_max[3], bool use_hidden
NULL;
if (bb_custom) {
float mat[4][4], smat[4][4];
scale_m4_fl(smat, PCHAN_CUSTOM_DRAW_SIZE(pchan));
scale_m4_fl(smat, PCHAN_CUSTOM_BONE_LENGTH(pchan));
mul_m4_v3(smat, pchan->custom_scale_xyz);
mul_m4_series(mat, ob->obmat, pchan_tx->pose_mat, smat);
BKE_boundbox_minmax(bb_custom, mat, r_min, r_max);
}

View File

@ -340,13 +340,22 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
float isect_1[3], isect_2[3];
/* Calculate the intersection point. */
isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
int ret = isect_line_sphere_v3(prev_bp->vec, bp->vec, head_pos, sphere_radius, isect_1, isect_2);
/* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
* intersection point we want. And it will always intersect as we go from inside to outside
* of the sphere.
*/
copy_v3_v3(r_tail_pos, isect_1);
if (ret > 0) {
/* Because of how `isect_line_sphere_v3` works, we know that `isect_1` contains the
* intersection point we want. And it will always intersect as we go from inside to outside
* of the sphere.
*/
copy_v3_v3(r_tail_pos, isect_1);
}
else {
/* Couldn't find an intersection point. This means that the floating point
* values are too small and thus the intersection check fails.
* So assume that the distance is so small that tail_pos == head_pos.
*/
copy_v3_v3(r_tail_pos, head_pos);
}
cur_seg_idx = bp_idx - 2;
float prev_seg_len = 0;
@ -360,7 +369,7 @@ static int position_tail_on_spline(bSplineIKConstraint *ik_data,
}
/* Convert the point back into the 0-1 interpolation range. */
const float isect_seg_len = len_v3v3(prev_bp->vec, isect_1);
const float isect_seg_len = len_v3v3(prev_bp->vec, r_tail_pos);
const float frac = isect_seg_len / len_v3v3(prev_bp->vec, bp->vec);
*r_new_curve_pos = (prev_seg_len + isect_seg_len) / spline_len;
@ -380,7 +389,7 @@ static void splineik_evaluate_bone(
{
bSplineIKConstraint *ik_data = tree->ik_data;
if (pchan->bone->length == 0.0f) {
if (pchan->bone->length < FLT_EPSILON) {
/* Only move the bone position with zero length bones. */
float bone_pos[4], dir[3], rad;
BKE_where_on_path(ik_data->tar, state->curve_position, bone_pos, dir, NULL, &rad, NULL);
@ -516,6 +525,25 @@ static void splineik_evaluate_bone(
*/
cross_v3_v3v3(raxis, rmat[1], spline_vec);
/* Check if the old and new bone direction is parallel to each other.
* If they are, then 'raxis' should be near zero and we will have to get the rotation axis in
* some other way.
*/
float norm = normalize_v3(raxis);
if (norm < FLT_EPSILON) {
/* Can't use cross product! */
int order[3] = {0, 1, 2};
float tmp_axis[3];
zero_v3(tmp_axis);
axis_sort_v3(spline_vec, order);
/* Use the second largest axis as the basis for the rotation axis. */
tmp_axis[order[1]] = 1.0f;
cross_v3_v3v3(raxis, tmp_axis, spline_vec);
}
rangle = dot_v3v3(rmat[1], spline_vec);
CLAMP(rangle, -1.0f, 1.0f);
rangle = acosf(rangle);

View File

@ -399,7 +399,8 @@ static void setup_app_data(bContext *C,
BKE_lib_override_library_main_resync(
bmain,
curscene,
bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene));
bfd->cur_view_layer ? bfd->cur_view_layer : BKE_view_layer_default_view(curscene),
reports);
/* We need to rebuild some of the deleted override rules (for UI feedback purpose). */
BKE_lib_override_library_main_operations_create(bmain, true);
}

View File

@ -1702,7 +1702,7 @@ static void dynamicPaint_setInitialColor(const Scene *scene, DynamicPaintSurface
}
for (int i = 0; i < totloop; i++) {
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[mloop[i].v].r);
rgba_uchar_to_float(pPoint[mloop[i].v].color, (const unsigned char *)&col[i].r);
}
}
else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) {

View File

@ -115,7 +115,7 @@ void CurveComponent::ensure_owns_direct_data()
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Access
/** \name Attribute Access Helper Functions
* \{ */
int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
@ -136,12 +136,33 @@ int CurveComponent::attribute_domain_size(const AttributeDomain domain) const
return 0;
}
static CurveEval *get_curve_from_component_for_write(GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
return curve_component.get_for_write();
}
static const CurveEval *get_curve_from_component_for_read(const GeometryComponent &component)
{
BLI_assert(component.type() == GEO_COMPONENT_TYPE_CURVE);
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
return curve_component.get_for_read();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Builtin Spline Attributes
*
* Attributes with a value for every spline, stored contiguously or in every spline separately.
* \{ */
namespace blender::bke {
class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data);
using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data);
using UpdateOnWrite = void (*)(Spline &spline);
const AsReadAttribute as_read_attribute_;
const AsWriteAttribute as_write_attribute_;
@ -164,12 +185,10 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
GVArrayPtr try_get_for_read(const GeometryComponent &component) const final
{
const CurveComponent &curve_component = static_cast<const CurveComponent &>(component);
const CurveEval *curve = curve_component.get_for_read();
const CurveEval *curve = get_curve_from_component_for_read(component);
if (curve == nullptr) {
return {};
}
return as_read_attribute_(*curve);
}
@ -178,12 +197,10 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider {
if (writable_ != Writable) {
return {};
}
CurveComponent &curve_component = static_cast<CurveComponent &>(component);
CurveEval *curve = curve_component.get_for_write();
CurveEval *curve = get_curve_from_component_for_write(component);
if (curve == nullptr) {
return {};
}
return as_write_attribute_(*curve);
}
@ -266,6 +283,12 @@ static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve)
curve.splines.as_mutable_span());
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Attribute Provider Declaration
* \{ */
/**
* In this function all the attribute providers for a curve component are created. Most data
* in this function is statically allocated, because it does not change over time.

View File

@ -56,6 +56,19 @@ void InstancesComponent::reserve(int min_capacity)
instance_ids_.reserve(min_capacity);
}
/**
* Resize the transform, handles, and ID vectors to the specified capacity.
*
* \note This function should be used carefully, only when it's guaranteed
* that the data will be filled.
*/
void InstancesComponent::resize(int capacity)
{
instance_reference_handles_.resize(capacity);
instance_transforms_.resize(capacity);
instance_ids_.resize(capacity);
}
void InstancesComponent::clear()
{
instance_reference_handles_.clear();
@ -81,6 +94,11 @@ blender::Span<int> InstancesComponent::instance_reference_handles() const
return instance_reference_handles_;
}
blender::MutableSpan<int> InstancesComponent::instance_reference_handles()
{
return instance_reference_handles_;
}
blender::MutableSpan<blender::float4x4> InstancesComponent::instance_transforms()
{
return instance_transforms_;

View File

@ -503,7 +503,7 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src)
void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen)
{
LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) {
LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &dest->data.group) {
const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name);
if (prop_src != NULL) {
/* check of we should replace? */

View File

@ -719,8 +719,19 @@ static void lib_override_library_create_post_process(Main *bmain,
if (BLI_gset_lookup(all_objects_in_scene, ob_new) == NULL) {
if (id_root != NULL && default_instantiating_collection == NULL) {
switch (GS(id_root->name)) {
ID *id_ref = id_root->newid != NULL ? id_root->newid : id_root;
switch (GS(id_ref->name)) {
case ID_GR: {
/* Adding the object to a specific collection outside of the root overridden one is a
* fairly bad idea (it breaks the override hierarchy concept). But there is no other
* way to do this currently (we cannot add new collections to overridden root one,
* this is not currently supported).
* Since that will be fairly annoying and noisy, only do that in case the override
* object is not part of any existing collection (i.e. its user count is 0). In
* practice this should never happen I think. */
if (ID_REAL_USERS(ob_new) != 0) {
continue;
}
default_instantiating_collection = BKE_collection_add(
bmain, (Collection *)id_root, "OVERRIDE_HIDDEN");
/* Hide the collection from viewport and render. */
@ -731,9 +742,9 @@ static void lib_override_library_create_post_process(Main *bmain,
case ID_OB: {
/* Add the other objects to one of the collections instantiating the
* root object, or scene's master collection if none found. */
Object *ob_root = (Object *)id_root;
Object *ob_ref = (Object *)id_ref;
LISTBASE_FOREACH (Collection *, collection, &bmain->collections) {
if (BKE_collection_has_object(collection, ob_root) &&
if (BKE_collection_has_object(collection, ob_ref) &&
BKE_view_layer_has_collection(view_layer, collection) &&
!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection)) {
default_instantiating_collection = collection;
@ -867,7 +878,8 @@ bool BKE_lib_override_library_resync(Main *bmain,
ID *id_root,
Collection *override_resync_residual_storage,
const bool do_hierarchy_enforce,
const bool do_post_process)
const bool do_post_process,
ReportList *reports)
{
BLI_assert(ID_IS_OVERRIDE_LIBRARY_REAL(id_root));
BLI_assert(!ID_IS_LINKED(id_root));
@ -891,6 +903,19 @@ bool BKE_lib_override_library_resync(Main *bmain,
BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__);
ID *id;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
/* IDs that get fully removed from linked data remain as local overrides (using place-holder
* linked IDs as reference), but they are often not reachable from any current valid local
* override hierarchy anymore. This will ensure they get properly deleted at the end of this
* function. */
if (!ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id) &&
(id->override_library->reference->tag & LIB_TAG_MISSING) != 0 &&
/* Unfortunately deleting obdata means deleting their objects too. Since there is no
* guarantee that a valid override object using an obsolete override obdata gets properly
* updated, we ignore those here for now. In practice this should not be a big issue. */
!OB_DATA_SUPPORT_ID(GS(id->name))) {
id->tag |= LIB_TAG_MISSING;
}
if (id->tag & LIB_TAG_DOIT && !ID_IS_LINKED(id) && ID_IS_OVERRIDE_LIBRARY_REAL(id)) {
/* While this should not happen in typical cases (and won't be properly supported here), user
* is free to do all kind of very bad things, including having different local overrides of a
@ -1033,6 +1058,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
/* Delete old override IDs.
* Note that we have to use tagged group deletion here, since ID deletion also uses LIB_TAG_DOIT.
* This improves performances anyway, so everything is fine. */
int user_edited_overrides_deletion_count = 0;
FOREACH_MAIN_ID_BEGIN (bmain, id) {
if (id->tag & LIB_TAG_DOIT) {
/* Note that this works because linked IDs are always after local ones (including overrides),
@ -1057,6 +1083,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
id->tag &= ~LIB_TAG_MISSING;
CLOG_INFO(&LOG, 2, "Old override %s is being deleted", id->name);
}
#if 0
else {
/* Otherwise, keep them, user needs to decide whether what to do with them. */
BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
@ -1064,6 +1091,17 @@ bool BKE_lib_override_library_resync(Main *bmain,
id->flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
CLOG_INFO(&LOG, 2, "Old override %s is being kept around as it was user-edited", id->name);
}
#else
else {
/* Delete them nevertheless, with fat warning, user needs to decide whether they want to
* save that version of the file (and accept the loss), or not. */
id->tag |= LIB_TAG_DOIT;
id->tag &= ~LIB_TAG_MISSING;
CLOG_WARN(
&LOG, "Old override %s is being deleted even though it was user-edited", id->name);
user_edited_overrides_deletion_count++;
}
#endif
}
}
FOREACH_MAIN_ID_END;
@ -1074,6 +1112,15 @@ bool BKE_lib_override_library_resync(Main *bmain,
*/
id_root = id_root_reference->newid;
if (user_edited_overrides_deletion_count > 0) {
BKE_reportf(reports,
RPT_WARNING,
"During resync of data-block %s, %d obsolete overrides were deleted, that had "
"local changes defined by user",
id_root->name + 2,
user_edited_overrides_deletion_count);
}
if (do_post_process) {
/* Essentially ensures that potentially new overrides of new objects will be instantiated. */
/* Note: Here 'reference' collection and 'newly added' collection are the same, which is fine
@ -1112,7 +1159,10 @@ bool BKE_lib_override_library_resync(Main *bmain,
* Then it will handle the resync of necessary IDs (through calls to
* #BKE_lib_override_library_resync).
*/
void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *view_layer)
void BKE_lib_override_library_main_resync(Main *bmain,
Scene *scene,
ViewLayer *view_layer,
ReportList *reports)
{
/* We use a specific collection to gather/store all 'orphaned' override collections and objects
* generated by re-sync-process. This avoids putting them in scene's master collection. */
@ -1228,7 +1278,7 @@ void BKE_lib_override_library_main_resync(Main *bmain, Scene *scene, ViewLayer *
CLOG_INFO(&LOG, 2, "Resyncing %s...", id->name);
const bool success = BKE_lib_override_library_resync(
bmain, scene, view_layer, id, override_resync_residual_storage, false, false);
bmain, scene, view_layer, id, override_resync_residual_storage, false, false, reports);
CLOG_INFO(&LOG, 2, "\tSuccess: %d", success);
break;
}

View File

@ -56,7 +56,7 @@ typedef struct LibraryForeachIDData {
*/
ID *self_id;
/** Flags controlling the bahaviour of the 'foreach id' looping code. */
/** Flags controlling the behavior of the 'foreach id' looping code. */
int flag;
/** Generic flags to be passed to all callback calls for current processed data. */
int cb_flag;

View File

@ -281,7 +281,7 @@ bool BKE_modifier_is_preview(ModifierData *md)
return false;
}
ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type)
ModifierData *BKE_modifiers_findby_type(const Object *ob, ModifierType type)
{
LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) {
if (md->type == type) {
@ -291,7 +291,7 @@ ModifierData *BKE_modifiers_findby_type(Object *ob, ModifierType type)
return NULL;
}
ModifierData *BKE_modifiers_findby_name(Object *ob, const char *name)
ModifierData *BKE_modifiers_findby_name(const Object *ob, const char *name)
{
return BLI_findstring(&(ob->modifiers), name, offsetof(ModifierData, name));
}

View File

@ -501,6 +501,12 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree)
ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) {
BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage);
}
else if ((ntree->type == NTREE_GEOMETRY) && (node->type == GEO_NODE_ATTRIBUTE_CURVE_MAP)) {
BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage);
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
BKE_curvemapping_blend_write(writer, (const CurveMapping *)data->curve_vec);
BKE_curvemapping_blend_write(writer, (const CurveMapping *)data->curve_rgb);
}
else if (ntree->type == NTREE_SHADER && (node->type == SH_NODE_SCRIPT)) {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
if (nss->bytecode) {
@ -676,6 +682,18 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree)
BKE_curvemapping_blend_read(reader, (CurveMapping *)node->storage);
break;
}
case GEO_NODE_ATTRIBUTE_CURVE_MAP: {
NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage;
BLO_read_data_address(reader, &data->curve_vec);
if (data->curve_vec) {
BKE_curvemapping_blend_read(reader, data->curve_vec);
}
BLO_read_data_address(reader, &data->curve_rgb);
if (data->curve_rgb) {
BKE_curvemapping_blend_read(reader, data->curve_rgb);
}
break;
}
case SH_NODE_SCRIPT: {
NodeShaderScript *nss = (NodeShaderScript *)node->storage;
BLO_read_data_address(reader, &nss->bytecode);
@ -4934,6 +4952,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_combine_xyz();
register_node_type_geo_attribute_compare();
register_node_type_geo_attribute_convert();
register_node_type_geo_attribute_curve_map();
register_node_type_geo_attribute_fill();
register_node_type_geo_attribute_map_range();
register_node_type_geo_attribute_math();
@ -4943,11 +4962,13 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_separate_xyz();
register_node_type_geo_attribute_transfer();
register_node_type_geo_attribute_vector_math();
register_node_type_geo_attribute_vector_rotate();
register_node_type_geo_attribute_remove();
register_node_type_geo_boolean();
register_node_type_geo_bounding_box();
register_node_type_geo_collection_info();
register_node_type_geo_curve_to_mesh();
register_node_type_geo_curve_resample();
register_node_type_geo_edge_split();
register_node_type_geo_is_viewport();
register_node_type_geo_join_geometry();

View File

@ -829,13 +829,13 @@ static void calculate_collision_balls(Object *ob)
}
/* creates new softbody if didn't exist yet, makes new points and springs arrays */
static void renew_softbody(Scene *scene, Object *ob, int totpoint, int totspring)
static void renew_softbody(Object *ob, int totpoint, int totspring)
{
SoftBody *sb;
int i;
short softflag;
if (ob->soft == NULL) {
ob->soft = sbNew(scene);
ob->soft = sbNew();
}
else {
free_softbody_intern(ob->soft);
@ -2679,7 +2679,7 @@ static void springs_from_mesh(Object *ob)
}
/* makes totally fresh start situation */
static void mesh_to_softbody(Scene *scene, Object *ob)
static void mesh_to_softbody(Object *ob)
{
SoftBody *sb;
Mesh *me = ob->data;
@ -2697,7 +2697,7 @@ static void mesh_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, me->totvert, totedge);
renew_softbody(ob, me->totvert, totedge);
/* we always make body points */
sb = ob->soft;
@ -2909,7 +2909,7 @@ static void makelatticesprings(Lattice *lt, BodySpring *bs, int dostiff, Object
}
/* makes totally fresh start situation */
static void lattice_to_softbody(Scene *scene, Object *ob)
static void lattice_to_softbody(Object *ob)
{
Lattice *lt = ob->data;
SoftBody *sb;
@ -2929,7 +2929,7 @@ static void lattice_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, totvert, totspring);
renew_softbody(ob, totvert, totspring);
sb = ob->soft; /* can be created in renew_softbody() */
bp = sb->bpoint;
@ -2972,7 +2972,7 @@ static void lattice_to_softbody(Scene *scene, Object *ob)
}
/* makes totally fresh start situation */
static void curve_surf_to_softbody(Scene *scene, Object *ob)
static void curve_surf_to_softbody(Object *ob)
{
Curve *cu = ob->data;
SoftBody *sb;
@ -2993,7 +2993,7 @@ static void curve_surf_to_softbody(Scene *scene, Object *ob)
}
/* renew ends with ob->soft with points and edges, also checks & makes ob->soft */
renew_softbody(scene, ob, totvert, totspring);
renew_softbody(ob, totvert, totspring);
sb = ob->soft; /* can be created in renew_softbody() */
/* set vars now */
@ -3117,7 +3117,7 @@ static void sb_new_scratch(SoftBody *sb)
/* ************ Object level, exported functions *************** */
/* allocates and initializes general main data */
SoftBody *sbNew(Scene *scene)
SoftBody *sbNew(void)
{
SoftBody *sb;
@ -3140,12 +3140,6 @@ SoftBody *sbNew(Scene *scene)
/*todo backward file compat should copy inspring to inpush while reading old files*/
sb->inpush = 0.5f;
sb->interval = 10;
if (scene != NULL) {
sb->sfra = scene->r.sfra;
sb->efra = scene->r.efra;
}
sb->colball = 0.49f;
sb->balldamp = 0.50f;
sb->ballstiff = 1.0f;
@ -3577,17 +3571,17 @@ void sbObjectStep(struct Depsgraph *depsgraph,
switch (ob->type) {
case OB_MESH:
mesh_to_softbody(scene, ob);
mesh_to_softbody(ob);
break;
case OB_LATTICE:
lattice_to_softbody(scene, ob);
lattice_to_softbody(ob);
break;
case OB_CURVE:
case OB_SURF:
curve_surf_to_softbody(scene, ob);
curve_surf_to_softbody(ob);
break;
default:
renew_softbody(scene, ob, numVerts, 0);
renew_softbody(ob, numVerts, 0);
break;
}

View File

@ -16,11 +16,13 @@
#include "BLI_array.hh"
#include "BLI_span.hh"
#include "FN_generic_virtual_array.hh"
#include "BLI_timeit.hh"
#include "BKE_spline.hh"
#include "FN_generic_virtual_array.hh"
using blender::Array;
using blender::float3;
using blender::IndexRange;
using blender::MutableSpan;
@ -59,7 +61,8 @@ int Spline::evaluated_edges_size() const
float Spline::length() const
{
return this->evaluated_lengths().last();
Span<float> lengths = this->evaluated_lengths();
return (lengths.size() == 0) ? 0 : this->evaluated_lengths().last();
}
int Spline::segments_size() const
@ -265,6 +268,72 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const
return LookupResult{index, next_index, factor};
}
/**
* Return an array of evenly spaced samples along the length of the spline. The samples are indices
* and factors to the next index encoded in floats. The logic for converting from the float values
* to interpolation data is in #lookup_data_from_index_factor.
*/
Array<float> Spline::sample_uniform_index_factors(const int samples_size) const
{
const Span<float> lengths = this->evaluated_lengths();
BLI_assert(samples_size > 0);
Array<float> samples(samples_size);
samples[0] = 0.0f;
if (samples_size == 1) {
return samples;
}
const float total_length = this->length();
const float sample_length = total_length / (samples_size - (is_cyclic_ ? 0 : 1));
/* Store the length at the previous evaluated point in a variable so it can
* start out at zero (the lengths array doesn't contain 0 for the first point). */
float prev_length = 0.0f;
int i_sample = 1;
for (const int i_evaluated : IndexRange(this->evaluated_edges_size())) {
const float length = lengths[i_evaluated];
/* Add every sample that fits in this evaluated edge. */
while ((sample_length * i_sample) < length && i_sample < samples_size) {
const float factor = (sample_length * i_sample - prev_length) / (length - prev_length);
samples[i_sample] = i_evaluated + factor;
i_sample++;
}
prev_length = length;
}
if (!is_cyclic_) {
/* In rare cases this can prevent overflow of the stored index. */
samples.last() = lengths.size();
}
return samples;
}
Spline::LookupResult Spline::lookup_data_from_index_factor(const float index_factor) const
{
const int points_len = this->evaluated_points_size();
if (is_cyclic_) {
if (index_factor < points_len) {
const int index = std::floor(index_factor);
const int next_index = (index < points_len - 1) ? index + 1 : 0;
return LookupResult{index, next_index, index_factor - index};
}
return LookupResult{points_len - 1, 0, 1.0f};
}
if (index_factor < points_len - 1) {
const int index = std::floor(index_factor);
const int next_index = index + 1;
return LookupResult{index, next_index, index_factor - index};
}
return LookupResult{points_len - 2, points_len - 1, 1.0f};
}
void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const
{
Span<float3> positions = use_evaluated ? this->evaluated_positions() : this->positions();

View File

@ -73,6 +73,18 @@ void BezierSpline::add_point(const float3 position,
this->mark_cache_invalid();
}
void BezierSpline::resize(const int size)
{
handle_types_left_.resize(size);
handle_positions_left_.resize(size);
positions_.resize(size);
handle_types_right_.resize(size);
handle_positions_right_.resize(size);
radii_.resize(size);
tilts_.resize(size);
this->mark_cache_invalid();
}
MutableSpan<float3> BezierSpline::positions()
{
return positions_;
@ -192,7 +204,7 @@ int BezierSpline::evaluated_points_size() const
const int last_offset = this->control_point_offsets().last();
if (is_cyclic_ && points_len > 1) {
return last_offset + (this->segment_is_vector(points_len - 1) ? 0 : resolution_);
return last_offset + (this->segment_is_vector(points_len - 1) ? 1 : resolution_);
}
return last_offset + 1;
@ -398,7 +410,7 @@ Span<float3> BezierSpline::evaluated_positions() const
this->evaluate_bezier_segment(i_last, 0, positions.slice(offsets.last(), resolution_));
}
else {
/* Since evualating the bezier segment doesn't add the final point,
/* Since evaluating the bezier segment doesn't add the final point,
* it must be added manually in the non-cyclic case. */
positions.last() = positions_.last();
}

View File

@ -78,6 +78,15 @@ void NURBSpline::add_point(const float3 position,
this->mark_cache_invalid();
}
void NURBSpline::resize(const int size)
{
positions_.resize(size);
radii_.resize(size);
tilts_.resize(size);
weights_.resize(size);
this->mark_cache_invalid();
}
MutableSpan<float3> NURBSpline::positions()
{
return positions_;

View File

@ -44,6 +44,14 @@ void PolySpline::add_point(const float3 position, const float radius, const floa
this->mark_cache_invalid();
}
void PolySpline::resize(const int size)
{
positions_.resize(size);
radii_.resize(size);
tilts_.resize(size);
this->mark_cache_invalid();
}
MutableSpan<float3> PolySpline::positions()
{
return positions_;

View File

@ -56,6 +56,7 @@
# include <libavcodec/avcodec.h>
# include <libavformat/avformat.h>
# include <libavutil/imgutils.h>
# include <libavutil/opt.h>
# include <libavutil/rational.h>
# include <libavutil/samplefmt.h>
# include <libswscale/swscale.h>
@ -80,6 +81,8 @@ typedef struct FFMpegContext {
int ffmpeg_preset; /* see eFFMpegPreset */
AVFormatContext *outfile;
AVCodecContext *video_codec;
AVCodecContext *audio_codec;
AVStream *video_stream;
AVStream *audio_stream;
AVFrame *current_frame; /* Image frame in output pixel format. */
@ -91,10 +94,6 @@ typedef struct FFMpegContext {
uint8_t *audio_input_buffer;
uint8_t *audio_deinterleave_buffer;
int audio_input_samples;
# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
uint8_t *audio_output_buffer;
int audio_outbuf_size;
# endif
double audio_time;
bool audio_deinterleave;
int audio_sample_size;
@ -141,32 +140,22 @@ static int request_float_audio_buffer(int codec_id)
}
# ifdef WITH_AUDASPACE
static int write_audio_frame(FFMpegContext *context)
{
AVCodecContext *c = NULL;
AVPacket pkt;
AVFrame *frame = NULL;
int got_output = 0;
c = context->audio_stream->codec;
av_init_packet(&pkt);
pkt.size = 0;
pkt.data = NULL;
AVCodecContext *c = context->audio_codec;
AUD_Device_read(
context->audio_mixdown_device, context->audio_input_buffer, context->audio_input_samples);
context->audio_time += (double)context->audio_input_samples / (double)c->sample_rate;
# ifdef FFMPEG_HAVE_ENCODE_AUDIO2
frame = av_frame_alloc();
av_frame_unref(frame);
frame->pts = context->audio_time / av_q2d(c->time_base);
frame->nb_samples = context->audio_input_samples;
frame->format = c->sample_fmt;
# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
frame->channels = c->channels;
frame->channel_layout = c->channel_layout;
# endif
if (context->audio_deinterleave) {
int channel, i;
@ -194,61 +183,49 @@ static int write_audio_frame(FFMpegContext *context)
context->audio_input_samples * c->channels * context->audio_sample_size,
1);
if (avcodec_encode_audio2(c, &pkt, frame, &got_output) < 0) {
// XXX error("Error writing audio packet");
return -1;
int success = 0;
int ret = avcodec_send_frame(c, frame);
if (ret < 0) {
/* Can't send frame to encoder. This shouldn't happen. */
fprintf(stderr, "Can't send audio frame: %s\n", av_err2str(ret));
success = -1;
}
if (!got_output) {
av_frame_free(&frame);
return 0;
}
# else
pkt.size = avcodec_encode_audio(c,
context->audio_output_buffer,
context->audio_outbuf_size,
(short *)context->audio_input_buffer);
AVPacket *pkt = av_packet_alloc();
if (pkt.size < 0) {
// XXX error("Error writing audio packet");
return -1;
}
while (ret >= 0) {
pkt.data = context->audio_output_buffer;
got_output = 1;
# endif
if (got_output) {
if (pkt.pts != AV_NOPTS_VALUE) {
pkt.pts = av_rescale_q(pkt.pts, c->time_base, context->audio_stream->time_base);
ret = avcodec_receive_packet(c, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
break;
}
if (pkt.dts != AV_NOPTS_VALUE) {
pkt.dts = av_rescale_q(pkt.dts, c->time_base, context->audio_stream->time_base);
}
if (pkt.duration > 0) {
pkt.duration = av_rescale_q(pkt.duration, c->time_base, context->audio_stream->time_base);
if (ret < 0) {
fprintf(stderr, "Error encoding audio frame: %s\n", av_err2str(ret));
success = -1;
}
pkt.stream_index = context->audio_stream->index;
pkt.flags |= AV_PKT_FLAG_KEY;
if (av_interleaved_write_frame(context->outfile, &pkt) != 0) {
fprintf(stderr, "Error writing audio packet!\n");
if (frame) {
av_frame_free(&frame);
}
return -1;
av_packet_rescale_ts(pkt, c->time_base, context->audio_stream->time_base);
if (pkt->duration > 0) {
pkt->duration = av_rescale_q(pkt->duration, c->time_base, context->audio_stream->time_base);
}
av_free_packet(&pkt);
pkt->stream_index = context->audio_stream->index;
pkt->flags |= AV_PKT_FLAG_KEY;
int write_ret = av_interleaved_write_frame(context->outfile, pkt);
if (write_ret != 0) {
fprintf(stderr, "Error writing audio packet: %s\n", av_err2str(write_ret));
success = -1;
break;
}
}
if (frame) {
av_frame_free(&frame);
}
av_packet_free(&pkt);
av_frame_free(&frame);
return 0;
return success;
}
# endif /* #ifdef WITH_AUDASPACE */
@ -264,14 +241,15 @@ static AVFrame *alloc_picture(int pix_fmt, int width, int height)
if (!f) {
return NULL;
}
size = avpicture_get_size(pix_fmt, width, height);
size = av_image_get_buffer_size(pix_fmt, width, height, 1);
/* allocate the actual picture buffer */
buf = MEM_mallocN(size, "AVFrame buffer");
if (!buf) {
free(f);
return NULL;
}
avpicture_fill((AVPicture *)f, buf, pix_fmt, width, height);
av_image_fill_arrays(f->data, f->linesize, buf, pix_fmt, width, height, 1);
f->format = pix_fmt;
f->width = width;
f->height = height;
@ -341,58 +319,57 @@ static const char **get_file_extensions(int format)
}
/* Write a frame to the output file */
static int write_video_frame(
FFMpegContext *context, const RenderData *rd, int cfra, AVFrame *frame, ReportList *reports)
static int write_video_frame(FFMpegContext *context, int cfra, AVFrame *frame, ReportList *reports)
{
int got_output;
int ret, success = 1;
AVCodecContext *c = context->video_stream->codec;
AVPacket packet = {0};
AVPacket *packet = av_packet_alloc();
av_init_packet(&packet);
AVCodecContext *c = context->video_codec;
frame->pts = cfra;
ret = avcodec_encode_video2(c, &packet, frame, &got_output);
if (ret >= 0 && got_output) {
if (packet.pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
packet.stream_index = context->video_stream->index;
ret = av_interleaved_write_frame(context->outfile, &packet);
success = (ret == 0);
ret = avcodec_send_frame(c, frame);
if (ret < 0) {
/* Can't send frame to encoder. This shouldn't happen. */
fprintf(stderr, "Can't send video frame: %s\n", av_err2str(ret));
success = -1;
}
else if (ret < 0) {
success = 0;
while (ret >= 0) {
ret = avcodec_receive_packet(c, packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
/* No more packets available. */
break;
}
if (ret < 0) {
fprintf(stderr, "Error encoding frame: %s\n", av_err2str(ret));
break;
}
packet->stream_index = context->video_stream->index;
av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
if (av_interleaved_write_frame(context->outfile, packet) != 0) {
success = -1;
break;
}
}
if (!success) {
BKE_report(reports, RPT_ERROR, "Error writing frame");
PRINT("Error writing frame: %s\n", av_err2str(ret));
}
av_packet_free(&packet);
return success;
}
/* read and encode a frame of audio from the buffer */
static AVFrame *generate_video_frame(FFMpegContext *context,
const uint8_t *pixels,
ReportList *reports)
static AVFrame *generate_video_frame(FFMpegContext *context, const uint8_t *pixels)
{
AVCodecContext *c = context->video_stream->codec;
int height = c->height;
AVCodecParameters *codec = context->video_stream->codecpar;
int height = codec->height;
AVFrame *rgb_frame;
if (context->img_convert_frame != NULL) {
@ -437,7 +414,7 @@ static AVFrame *generate_video_frame(FFMpegContext *context,
(const uint8_t *const *)rgb_frame->data,
rgb_frame->linesize,
0,
c->height,
codec->height,
context->current_frame->data,
context->current_frame->linesize);
}
@ -445,9 +422,7 @@ static AVFrame *generate_video_frame(FFMpegContext *context,
return context->current_frame;
}
static void set_ffmpeg_property_option(AVCodecContext *c,
IDProperty *prop,
AVDictionary **dictionary)
static void set_ffmpeg_property_option(IDProperty *prop, AVDictionary **dictionary)
{
char name[128];
char *param;
@ -535,7 +510,7 @@ static void set_ffmpeg_properties(RenderData *rd,
for (curr = prop->data.group.first; curr; curr = curr->next) {
if (ffmpeg_proprty_valid(c, prop_name, curr)) {
set_ffmpeg_property_option(c, curr, dictionary);
set_ffmpeg_property_option(curr, dictionary);
}
}
}
@ -552,7 +527,6 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
int error_size)
{
AVStream *st;
AVCodecContext *c;
AVCodec *codec;
AVDictionary *opts = NULL;
@ -566,7 +540,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* Set up the codec context */
c = st->codec;
context->video_codec = avcodec_alloc_context3(NULL);
AVCodecContext *c = context->video_codec;
c->codec_id = codec_id;
c->codec_type = AVMEDIA_TYPE_VIDEO;
@ -649,11 +624,9 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
}
}
/* Deprecated and not doing anything since July 2015, deleted in recent ffmpeg */
// c->me_method = ME_EPZS;
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
avcodec_free_context(&c);
return NULL;
}
@ -713,7 +686,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
if ((of->oformat->flags & AVFMT_GLOBALHEADER)) {
PRINT("Using global header\n");
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
/* xasp & yasp got float lately... */
@ -741,6 +714,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
if (avcodec_open2(c, codec, &opts) < 0) {
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
avcodec_free_context(&c);
return NULL;
}
av_dict_free(&opts);
@ -768,6 +742,8 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
NULL);
}
avcodec_parameters_from_context(st->codecpar, c);
return st;
}
@ -779,7 +755,6 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
int error_size)
{
AVStream *st;
AVCodecContext *c;
AVCodec *codec;
AVDictionary *opts = NULL;
@ -791,7 +766,8 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
}
st->id = 1;
c = st->codec;
context->audio_codec = avcodec_alloc_context3(NULL);
AVCodecContext *c = context->audio_codec;
c->thread_count = BLI_system_thread_count();
c->thread_type = FF_THREAD_SLICE;
@ -803,7 +779,6 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
c->sample_fmt = AV_SAMPLE_FMT_S16;
c->channels = rd->ffcodecdata.audio_channels;
# ifdef FFMPEG_HAVE_FRAME_CHANNEL_LAYOUT
switch (rd->ffcodecdata.audio_channels) {
case FFM_CHANNELS_MONO:
c->channel_layout = AV_CH_LAYOUT_MONO;
@ -821,7 +796,6 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
c->channel_layout = AV_CH_LAYOUT_7POINT1;
break;
}
# endif
if (request_float_audio_buffer(codec_id)) {
/* mainly for AAC codec which is experimental */
@ -832,6 +806,7 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
// XXX error("Couldn't find a valid audio codec");
avcodec_free_context(&c);
return NULL;
}
@ -843,13 +818,13 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
* Float samples in particular are not always supported. */
const enum AVSampleFormat *p = codec->sample_fmts;
for (; *p != -1; p++) {
if (*p == st->codec->sample_fmt) {
if (*p == c->sample_fmt) {
break;
}
}
if (*p == -1) {
/* sample format incompatible with codec. Defaulting to a format known to work */
st->codec->sample_fmt = codec->sample_fmts[0];
c->sample_fmt = codec->sample_fmts[0];
}
}
@ -858,18 +833,18 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
int best = 0;
int best_dist = INT_MAX;
for (; *p; p++) {
int dist = abs(st->codec->sample_rate - *p);
int dist = abs(c->sample_rate - *p);
if (dist < best_dist) {
best_dist = dist;
best = *p;
}
}
/* best is the closest supported sample rate (same as selected if best_dist == 0) */
st->codec->sample_rate = best;
c->sample_rate = best;
}
if (of->oformat->flags & AVFMT_GLOBALHEADER) {
c->flags |= CODEC_FLAG_GLOBAL_HEADER;
c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
set_ffmpeg_properties(rd, c, "audio", &opts);
@ -878,32 +853,25 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
// XXX error("Couldn't initialize audio codec");
BLI_strncpy(error, IMB_ffmpeg_last_error(), error_size);
av_dict_free(&opts);
avcodec_free_context(&c);
return NULL;
}
av_dict_free(&opts);
/* need to prevent floating point exception when using vorbis audio codec,
* initialize this value in the same way as it's done in FFmpeg itself (sergey) */
st->codec->time_base.num = 1;
st->codec->time_base.den = st->codec->sample_rate;
# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
context->audio_outbuf_size = FF_MIN_BUFFER_SIZE;
# endif
c->time_base.num = 1;
c->time_base.den = c->sample_rate;
if (c->frame_size == 0) {
/* Used to be if ((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
* not sure if that is needed anymore, so let's try out if there are any
* complaints regarding some FFmpeg versions users might have. */
context->audio_input_samples = FF_MIN_BUFFER_SIZE * 8 / c->bits_per_coded_sample / c->channels;
context->audio_input_samples = AV_INPUT_BUFFER_MIN_SIZE * 8 / c->bits_per_coded_sample /
c->channels;
}
else {
context->audio_input_samples = c->frame_size;
# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
if (c->frame_size * c->channels * sizeof(int16_t) * 4 > context->audio_outbuf_size) {
context->audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
}
# endif
}
context->audio_deinterleave = av_sample_fmt_is_planar(c->sample_fmt);
@ -912,10 +880,6 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
context->audio_input_buffer = (uint8_t *)av_malloc(context->audio_input_samples * c->channels *
context->audio_sample_size);
# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
context->audio_output_buffer = (uint8_t *)av_malloc(context->audio_outbuf_size);
# endif
if (context->audio_deinterleave) {
context->audio_deinterleave_buffer = (uint8_t *)av_malloc(
context->audio_input_samples * c->channels * context->audio_sample_size);
@ -923,6 +887,8 @@ static AVStream *alloc_audio_stream(FFMpegContext *context,
context->audio_time = 0.0f;
avcodec_parameters_from_context(st->codecpar, c);
return st;
}
/* essential functions -- start, append, end */
@ -948,7 +914,7 @@ static void ffmpeg_dict_set_float(AVDictionary **dict, const char *key, float va
static void ffmpeg_add_metadata_callback(void *data,
const char *propname,
char *propvalue,
int len)
int UNUSED(len))
{
AVDictionary **metadata = (AVDictionary **)data;
av_dict_set(metadata, propname, propvalue, 0);
@ -1039,7 +1005,7 @@ static int start_ffmpeg_impl(FFMpegContext *context,
fmt->audio_codec = context->ffmpeg_audio_codec;
BLI_strncpy(of->filename, name, sizeof(of->filename));
of->url = av_strdup(name);
/* set the codec to the user's selection */
switch (context->ffmpeg_type) {
case FFMPEG_AVI:
@ -1104,9 +1070,11 @@ static int start_ffmpeg_impl(FFMpegContext *context,
if (!context->video_stream) {
if (error[0]) {
BKE_report(reports, RPT_ERROR, error);
PRINT("Video stream error: %s\n", error);
}
else {
BKE_report(reports, RPT_ERROR, "Error initializing video stream");
PRINT("Error initializing video stream");
}
goto fail;
}
@ -1118,9 +1086,11 @@ static int start_ffmpeg_impl(FFMpegContext *context,
if (!context->audio_stream) {
if (error[0]) {
BKE_report(reports, RPT_ERROR, error);
PRINT("Audio stream error: %s\n", error);
}
else {
BKE_report(reports, RPT_ERROR, "Error initializing audio stream");
PRINT("Error initializing audio stream");
}
goto fail;
}
@ -1128,6 +1098,7 @@ static int start_ffmpeg_impl(FFMpegContext *context,
if (!(fmt->flags & AVFMT_NOFILE)) {
if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
BKE_report(reports, RPT_ERROR, "Could not open file for writing");
PRINT("Could not open file for writing\n");
goto fail;
}
}
@ -1137,10 +1108,12 @@ static int start_ffmpeg_impl(FFMpegContext *context,
&of->metadata, context->stamp_data, ffmpeg_add_metadata_callback, false);
}
if (avformat_write_header(of, NULL) < 0) {
int ret = avformat_write_header(of, NULL);
if (ret < 0) {
BKE_report(reports,
RPT_ERROR,
"Could not initialize streams, probably unsupported codec combination");
PRINT("Could not write media header: %s\n", av_err2str(ret));
goto fail;
}
@ -1155,13 +1128,11 @@ fail:
avio_close(of->pb);
}
if (context->video_stream && context->video_stream->codec) {
avcodec_close(context->video_stream->codec);
if (context->video_stream) {
context->video_stream = NULL;
}
if (context->audio_stream && context->audio_stream->codec) {
avcodec_close(context->audio_stream->codec);
if (context->audio_stream) {
context->audio_stream = NULL;
}
@ -1189,46 +1160,36 @@ fail:
*/
static void flush_ffmpeg(FFMpegContext *context)
{
int ret = 0;
AVCodecContext *c = context->video_codec;
AVPacket *packet = av_packet_alloc();
AVCodecContext *c = context->video_stream->codec;
/* get the delayed frames */
while (1) {
int got_output;
AVPacket packet = {0};
av_init_packet(&packet);
avcodec_send_frame(c, NULL);
ret = avcodec_encode_video2(c, &packet, NULL, &got_output);
/* Get the packets frames. */
int ret = 1;
while (ret >= 0) {
ret = avcodec_receive_packet(c, packet);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
/* No more packets to flush. */
break;
}
if (ret < 0) {
fprintf(stderr, "Error encoding delayed frame %d\n", ret);
fprintf(stderr, "Error encoding delayed frame: %s\n", av_err2str(ret));
break;
}
if (!got_output) {
break;
}
if (packet.pts != AV_NOPTS_VALUE) {
packet.pts = av_rescale_q(packet.pts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame PTS: %d\n", (int)packet.pts);
}
else {
PRINT("Video Frame PTS: not set\n");
}
if (packet.dts != AV_NOPTS_VALUE) {
packet.dts = av_rescale_q(packet.dts, c->time_base, context->video_stream->time_base);
PRINT("Video Frame DTS: %d\n", (int)packet.dts);
}
else {
PRINT("Video Frame DTS: not set\n");
}
packet.stream_index = context->video_stream->index;
ret = av_interleaved_write_frame(context->outfile, &packet);
if (ret != 0) {
fprintf(stderr, "Error writing delayed frame %d\n", ret);
packet->stream_index = context->video_stream->index;
av_packet_rescale_ts(packet, c->time_base, context->video_stream->time_base);
int write_ret = av_interleaved_write_frame(context->outfile, packet);
if (write_ret != 0) {
fprintf(stderr, "Error writing delayed frame: %s\n", av_err2str(write_ret));
break;
}
}
avcodec_flush_buffers(context->video_stream->codec);
av_packet_free(&packet);
}
/* **********************************************************************
@ -1326,7 +1287,8 @@ int BKE_ffmpeg_start(void *context_v,
success = start_ffmpeg_impl(context, rd, rectx, recty, suffix, reports);
# ifdef WITH_AUDASPACE
if (context->audio_stream) {
AVCodecContext *c = context->audio_stream->codec;
AVCodecContext *c = context->audio_codec;
AUD_DeviceSpecs specs;
specs.channels = c->channels;
@ -1353,10 +1315,6 @@ int BKE_ffmpeg_start(void *context_v,
specs.rate = rd->ffcodecdata.audio_mixrate;
context->audio_mixdown_device = BKE_sound_mixdown(
scene, specs, preview ? rd->psfra : rd->sfra, rd->ffcodecdata.audio_volume);
# ifdef FFMPEG_CODEC_TIME_BASE
c->time_base.den = specs.rate;
c->time_base.num = 1;
# endif
}
# endif
return success;
@ -1397,8 +1355,8 @@ int BKE_ffmpeg_append(void *context_v,
// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
if (context->video_stream) {
avframe = generate_video_frame(context, (unsigned char *)pixels, reports);
success = (avframe && write_video_frame(context, rd, frame - start_frame, avframe, reports));
avframe = generate_video_frame(context, (unsigned char *)pixels);
success = (avframe && write_video_frame(context, frame - start_frame, avframe, reports));
if (context->ffmpeg_autosplit) {
if (avio_tell(context->outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
@ -1427,9 +1385,11 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
context->audio_mixdown_device = NULL;
}
}
# else
UNUSED_VARS(is_autosplit);
# endif
if (context->video_stream && context->video_stream->codec) {
if (context->video_stream) {
PRINT("Flushing delayed frames...\n");
flush_ffmpeg(context);
}
@ -1440,14 +1400,12 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
/* Close the video codec */
if (context->video_stream != NULL && context->video_stream->codec != NULL) {
avcodec_close(context->video_stream->codec);
if (context->video_stream != NULL) {
PRINT("zero video stream %p\n", context->video_stream);
context->video_stream = NULL;
}
if (context->audio_stream != NULL && context->audio_stream->codec != NULL) {
avcodec_close(context->audio_stream->codec);
if (context->audio_stream != NULL) {
context->audio_stream = NULL;
}
@ -1466,6 +1424,16 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
avio_close(context->outfile->pb);
}
}
if (context->video_codec != NULL) {
avcodec_free_context(&context->video_codec);
context->video_codec = NULL;
}
if (context->audio_codec != NULL) {
avcodec_free_context(&context->audio_codec);
context->audio_codec = NULL;
}
if (context->outfile != NULL) {
avformat_free_context(context->outfile);
context->outfile = NULL;
@ -1474,12 +1442,6 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit)
av_free(context->audio_input_buffer);
context->audio_input_buffer = NULL;
}
# ifndef FFMPEG_HAVE_ENCODE_AUDIO2
if (context->audio_output_buffer != NULL) {
av_free(context->audio_output_buffer);
context->audio_output_buffer = NULL;
}
# endif
if (context->audio_deinterleave_buffer != NULL) {
av_free(context->audio_deinterleave_buffer);
@ -1559,12 +1521,12 @@ static IDProperty *BKE_ffmpeg_property_add(RenderData *rd,
switch (o->type) {
case AV_OPT_TYPE_INT:
case AV_OPT_TYPE_INT64:
val.i = FFMPEG_DEF_OPT_VAL_INT(o);
val.i = o->default_val.i64;
idp_type = IDP_INT;
break;
case AV_OPT_TYPE_DOUBLE:
case AV_OPT_TYPE_FLOAT:
val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o);
val.f = o->default_val.dbl;
idp_type = IDP_FLOAT;
break;
case AV_OPT_TYPE_STRING:
@ -1706,16 +1668,9 @@ static void ffmpeg_set_expert_options(RenderData *rd)
BKE_ffmpeg_property_add_string(rd, "video", "trellis:0");
BKE_ffmpeg_property_add_string(rd, "video", "weightb:1");
# ifdef FFMPEG_HAVE_DEPRECATED_FLAGS2
BKE_ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
BKE_ffmpeg_property_add_string(rd, "video", "directpred:3");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
BKE_ffmpeg_property_add_string(rd, "video", "flags2:wpred");
# else
BKE_ffmpeg_property_add_string(rd, "video", "8x8dct:1");
BKE_ffmpeg_property_add_string(rd, "video", "fast-pskip:1");
BKE_ffmpeg_property_add_string(rd, "video", "wpredp:2");
# endif
}
else if (codec_id == AV_CODEC_ID_DNXHD) {
if (rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT) {
@ -1870,14 +1825,12 @@ bool BKE_ffmpeg_alpha_channel_is_supported(const RenderData *rd)
{
int codec = rd->ffcodecdata.codec;
# ifdef FFMPEG_FFV1_ALPHA_SUPPORTED
/* Visual Studio 2019 doesn't like #ifdef within ELEM(). */
if (codec == AV_CODEC_ID_FFV1) {
return true;
}
# endif
return ELEM(codec, AV_CODEC_ID_QTRLE, AV_CODEC_ID_PNG, AV_CODEC_ID_VP9, AV_CODEC_ID_HUFFYUV);
return ELEM(codec,
AV_CODEC_ID_FFV1,
AV_CODEC_ID_QTRLE,
AV_CODEC_ID_PNG,
AV_CODEC_ID_VP9,
AV_CODEC_ID_HUFFYUV);
}
void *BKE_ffmpeg_context_create(void)

View File

@ -78,7 +78,7 @@ float BLI_dial_angle(Dial *dial, const float current_position[2])
cosval = dot_v2v2(current_direction, dial->initial_direction);
sinval = cross_v2v2(current_direction, dial->initial_direction);
/* clamp to avoid nans in #acos */
/* Clamp to avoid NAN's in #acos */
angle = atan2f(sinval, cosval);
/* change of sign, we passed the 180 degree threshold. This means we need to add a turn.

View File

@ -111,6 +111,7 @@
#include "SEQ_iterator.h"
#include "SEQ_modifier.h"
#include "SEQ_sequencer.h"
#include "SEQ_utils.h"
#include "readfile.h"
@ -2696,7 +2697,7 @@ static int lib_link_seq_clipboard_cb(Sequence *seq, void *arg_pt)
static void lib_link_clipboard_restore(struct IDNameLib_Map *id_map)
{
/* update IDs stored in sequencer clipboard */
SEQ_iterator_seqbase_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
SEQ_seqbase_recursive_apply(&seqbase_clipboard, lib_link_seq_clipboard_cb, id_map);
}
static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data)

View File

@ -21,6 +21,7 @@
#define DNA_DEPRECATED_ALLOW
#include "BLI_listbase.h"
#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#include "DNA_brush_types.h"
@ -95,5 +96,15 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain)
*/
{
/* Keep this block, even when empty. */
if (!DNA_struct_elem_find(fd->filesdna, "bPoseChannel", "float", "custom_scale_xyz[3]")) {
LISTBASE_FOREACH (Object *, ob, &bmain->objects) {
if (ob->pose == NULL) {
continue;
}
LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
copy_v3_fl(pchan->custom_scale_xyz, pchan->custom_scale);
}
}
}
}
}

View File

@ -1278,12 +1278,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
if (ob->soft->physics_speed == 0.0f) {
ob->soft->physics_speed = 1.0f;
}
if (ob->soft->interval == 0) {
ob->soft->interval = 2;
ob->soft->sfra = 1;
ob->soft->efra = 100;
}
}
if (ob->soft && ob->soft->vertgroup == 0) {
bDeformGroup *locGroup = BKE_object_defgroup_find_name(ob, "SOFTGOAL");

View File

@ -25,29 +25,49 @@ namespace blender::compositor {
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, const rcti &rect, MemoryBufferState state)
{
m_rect = rect;
this->m_is_a_single_elem = false;
this->m_memoryProxy = memoryProxy;
this->m_num_channels = COM_data_type_num_channels(memoryProxy->getDataType());
this->m_buffer = (float *)MEM_mallocN_aligned(
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
this->m_state = state;
this->m_datatype = memoryProxy->getDataType();
set_strides();
}
MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect)
MemoryBuffer::MemoryBuffer(DataType dataType, const rcti &rect, bool is_a_single_elem)
{
m_rect = rect;
this->m_is_a_single_elem = is_a_single_elem;
this->m_memoryProxy = nullptr;
this->m_num_channels = COM_data_type_num_channels(dataType);
this->m_buffer = (float *)MEM_mallocN_aligned(
sizeof(float) * buffer_len() * this->m_num_channels, 16, "COM_MemoryBuffer");
this->m_state = MemoryBufferState::Temporary;
this->m_datatype = dataType;
set_strides();
}
MemoryBuffer::MemoryBuffer(const MemoryBuffer &src)
: MemoryBuffer(src.m_memoryProxy, src.m_rect, MemoryBufferState::Temporary)
: MemoryBuffer(src.m_datatype, src.m_rect, false)
{
memcpy(m_buffer, src.m_buffer, buffer_len() * m_num_channels * sizeof(float));
m_memoryProxy = src.m_memoryProxy;
/* src may be single elem buffer */
fill_from(src);
}
void MemoryBuffer::set_strides()
{
if (m_is_a_single_elem) {
this->elem_stride = 0;
this->row_stride = 0;
}
else {
this->elem_stride = m_num_channels;
this->row_stride = getWidth() * m_num_channels;
}
}
void MemoryBuffer::clear()
@ -100,6 +120,8 @@ MemoryBuffer::~MemoryBuffer()
void MemoryBuffer::fill_from(const MemoryBuffer &src)
{
BLI_assert(!this->is_a_single_elem());
unsigned int otherY;
unsigned int minX = MAX2(this->m_rect.xmin, src.m_rect.xmin);
unsigned int maxX = MIN2(this->m_rect.xmax, src.m_rect.xmax);
@ -109,10 +131,8 @@ void MemoryBuffer::fill_from(const MemoryBuffer &src)
int otherOffset;
for (otherY = minY; otherY < maxY; otherY++) {
otherOffset = ((otherY - src.m_rect.ymin) * src.getWidth() + minX - src.m_rect.xmin) *
this->m_num_channels;
offset = ((otherY - this->m_rect.ymin) * getWidth() + minX - this->m_rect.xmin) *
this->m_num_channels;
otherOffset = src.get_coords_offset(minX, otherY);
offset = this->get_coords_offset(minX, otherY);
memcpy(&this->m_buffer[offset],
&src.m_buffer[otherOffset],
(maxX - minX) * this->m_num_channels * sizeof(float));
@ -123,8 +143,7 @@ void MemoryBuffer::writePixel(int x, int y, const float color[4])
{
if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
y < this->m_rect.ymax) {
const int offset = (getWidth() * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
this->m_num_channels;
const int offset = get_coords_offset(x, y);
memcpy(&this->m_buffer[offset], color, sizeof(float) * this->m_num_channels);
}
}
@ -133,8 +152,7 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4])
{
if (x >= this->m_rect.xmin && x < this->m_rect.xmax && y >= this->m_rect.ymin &&
y < this->m_rect.ymax) {
const int offset = (getWidth() * (y - this->m_rect.ymin) + x - this->m_rect.xmin) *
this->m_num_channels;
const int offset = get_coords_offset(x, y);
float *dst = &this->m_buffer[offset];
const float *src = color;
for (int i = 0; i < this->m_num_channels; i++, dst++, src++) {
@ -151,26 +169,31 @@ static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]
void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2])
{
BLI_assert(this->m_datatype == DataType::Color);
float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
/* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
* but compositor uses pixel space. For now let's just divide the values and
* switch compositor to normalized space for EWA later.
*/
float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height};
float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height};
float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height};
if (m_is_a_single_elem) {
memcpy(result, m_buffer, sizeof(float) * this->m_num_channels);
}
else {
BLI_assert(this->m_datatype == DataType::Color);
float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
/* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
* but compositor uses pixel space. For now let's just divide the values and
* switch compositor to normalized space for EWA later.
*/
float uv_normal[2] = {uv[0] * inv_width, uv[1] * inv_height};
float du_normal[2] = {derivatives[0][0] * inv_width, derivatives[0][1] * inv_height};
float dv_normal[2] = {derivatives[1][0] * inv_width, derivatives[1][1] * inv_height};
BLI_ewa_filter(this->getWidth(),
this->getHeight(),
false,
true,
uv_normal,
du_normal,
dv_normal,
read_ewa_pixel_sampled,
this,
result);
BLI_ewa_filter(this->getWidth(),
this->getHeight(),
false,
true,
uv_normal,
du_normal,
dv_normal,
read_ewa_pixel_sampled,
this,
result);
}
}
} // namespace blender::compositor

View File

@ -50,6 +50,25 @@ class MemoryProxy;
* \brief a MemoryBuffer contains access to the data of a chunk
*/
class MemoryBuffer {
public:
/**
* Offset between elements.
*
* Should always be used for the x dimension when calculating buffer offsets.
* It will be 0 when is_a_single_elem=true.
* e.g: buffer_index = y * buffer.row_stride + x * buffer.elem_stride
*/
int elem_stride;
/**
* Offset between rows.
*
* Should always be used for the y dimension when calculating buffer offsets.
* It will be 0 when is_a_single_elem=true.
* e.g: buffer_index = y * buffer.row_stride + x * buffer.elem_stride
*/
int row_stride;
private:
/**
* \brief proxy of the memory (same for all chunks in the same buffer)
@ -82,6 +101,11 @@ class MemoryBuffer {
*/
uint8_t m_num_channels;
/**
* Whether buffer is a single element in memory.
*/
bool m_is_a_single_elem;
public:
/**
* \brief construct new temporarily MemoryBuffer for an area
@ -91,7 +115,7 @@ class MemoryBuffer {
/**
* \brief construct new temporarily MemoryBuffer for an area
*/
MemoryBuffer(DataType datatype, const rcti &rect);
MemoryBuffer(DataType datatype, const rcti &rect, bool is_a_single_elem = false);
/**
* Copy constructor
@ -103,6 +127,102 @@ class MemoryBuffer {
*/
~MemoryBuffer();
/**
* Whether buffer is a single element in memory independently of its resolution. True for set
* operations buffers.
*/
bool is_a_single_elem() const
{
return m_is_a_single_elem;
}
float &operator[](int index)
{
BLI_assert(m_is_a_single_elem ? index < m_num_channels :
index < get_coords_offset(getWidth(), getHeight()));
return m_buffer[index];
}
const float &operator[](int index) const
{
BLI_assert(m_is_a_single_elem ? index < m_num_channels :
index < get_coords_offset(getWidth(), getHeight()));
return m_buffer[index];
}
/**
* Get offset needed to jump from buffer start to given coordinates.
*/
int get_coords_offset(int x, int y) const
{
return (y - m_rect.ymin) * row_stride + (x - m_rect.xmin) * elem_stride;
}
/**
* Get buffer element at given coordinates.
*/
float *get_elem(int x, int y)
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax);
return m_buffer + get_coords_offset(x, y);
}
/**
* Get buffer element at given coordinates.
*/
const float *get_elem(int x, int y) const
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax);
return m_buffer + get_coords_offset(x, y);
}
/**
* Get channel value at given coordinates.
*/
float &get_value(int x, int y, int channel)
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax &&
channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel];
}
/**
* Get channel value at given coordinates.
*/
const float &get_value(int x, int y, int channel) const
{
BLI_assert(x >= m_rect.xmin && x < m_rect.xmax && y >= m_rect.ymin && y < m_rect.ymax &&
channel >= 0 && channel < m_num_channels);
return m_buffer[get_coords_offset(x, y) + channel];
}
/**
* Get the buffer row end.
*/
const float *get_row_end(int y) const
{
BLI_assert(y >= 0 && y < getHeight());
return m_buffer + (is_a_single_elem() ? m_num_channels : get_coords_offset(getWidth(), y));
}
/**
* Get the number of elements in memory for a row. For single element buffers it will always
* be 1.
*/
int get_memory_width() const
{
return is_a_single_elem() ? 1 : getWidth();
}
/**
* Get number of elements in memory for a column. For single element buffers it will
* always be 1.
*/
int get_memory_height() const
{
return is_a_single_elem() ? 1 : getHeight();
}
uint8_t get_num_channels()
{
return this->m_num_channels;
@ -216,7 +336,7 @@ class MemoryBuffer {
int u = x;
int v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
const int offset = (getWidth() * y + x) * this->m_num_channels;
const int offset = get_coords_offset(u, v);
float *buffer = &this->m_buffer[offset];
memcpy(result, buffer, sizeof(float) * this->m_num_channels);
}
@ -232,7 +352,7 @@ class MemoryBuffer {
int v = y;
this->wrap_pixel(u, v, extend_x, extend_y);
const int offset = (getWidth() * v + u) * this->m_num_channels;
const int offset = get_coords_offset(u, v);
BLI_assert(offset >= 0);
BLI_assert(offset < this->buffer_len() * this->m_num_channels);
@ -258,15 +378,20 @@ class MemoryBuffer {
copy_vn_fl(result, this->m_num_channels, 0.0f);
return;
}
BLI_bilinear_interpolation_wrap_fl(this->m_buffer,
result,
getWidth(),
getHeight(),
this->m_num_channels,
u,
v,
extend_x == MemoryBufferExtend::Repeat,
extend_y == MemoryBufferExtend::Repeat);
if (m_is_a_single_elem) {
memcpy(result, m_buffer, sizeof(float) * this->m_num_channels);
}
else {
BLI_bilinear_interpolation_wrap_fl(this->m_buffer,
result,
getWidth(),
getHeight(),
this->m_num_channels,
u,
v,
extend_x == MemoryBufferExtend::Repeat,
extend_y == MemoryBufferExtend::Repeat);
}
}
void readEWA(float *result, const float uv[2], const float derivatives[2][2]);
@ -321,9 +446,10 @@ class MemoryBuffer {
float get_max_value(const rcti &rect) const;
private:
void set_strides();
const int buffer_len() const
{
return getWidth() * getHeight();
return get_memory_width() * get_memory_height();
}
#ifdef WITH_CXX_GUARDEDALLOC

View File

@ -121,7 +121,7 @@ void EEVEE_cryptomatte_renderpasses_init(EEVEE_Data *vedata)
ViewLayer *view_layer = draw_ctx->view_layer;
/* Cryptomatte is only rendered for final image renders */
if (!DRW_state_is_image_render()) {
if (!DRW_state_is_scene_render()) {
return;
}
const eViewLayerCryptomatteFlags active_layers = eevee_cryptomatte_active_layers(view_layer);
@ -158,9 +158,9 @@ void EEVEE_cryptomatte_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
const ViewLayer *view_layer = draw_ctx->view_layer;
const int num_cryptomatte_layers = eevee_cryptomatte_layers_count(view_layer);
eGPUTextureFormat format = (num_cryptomatte_layers == 1) ?
GPU_R32F :
(num_cryptomatte_layers == 2) ? GPU_RG32F : GPU_RGBA32F;
eGPUTextureFormat format = (num_cryptomatte_layers == 1) ? GPU_R32F :
(num_cryptomatte_layers == 2) ? GPU_RG32F :
GPU_RGBA32F;
const float *viewport_size = DRW_viewport_size_get();
const int buffer_size = viewport_size[0] * viewport_size[1];

View File

@ -623,6 +623,11 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata,
/* This GPUShader has already been used by another material.
* Add new shading group just after to avoid shader switching cost. */
grp = DRW_shgroup_create_sub(*grp_p);
/* Per material uniforms. */
if (use_ssrefract) {
DRW_shgroup_uniform_float_copy(grp, "refractionDepth", ma->refract_depth);
}
}
else {
*grp_p = grp = DRW_shgroup_create(sh, shading_pass);
@ -961,22 +966,9 @@ void EEVEE_material_renderpasses_init(EEVEE_Data *vedata)
}
}
static void material_renderpass_init(EEVEE_FramebufferList *fbl,
GPUTexture **output_tx,
const eGPUTextureFormat format,
const bool do_clear)
static void material_renderpass_init(GPUTexture **output_tx, const eGPUTextureFormat format)
{
DRW_texture_ensure_fullscreen_2d(output_tx, format, 0);
/* Clear texture. */
if (do_clear) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* TODO(fclem): replace by GPU_texture_clear once it is fast. */
GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0);
GPU_framebuffer_bind(fbl->material_accum_fb);
GPU_framebuffer_clear_color(fbl->material_accum_fb, clear);
GPU_framebuffer_bind(fbl->main_fb);
GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx);
}
}
void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples)
@ -991,33 +983,32 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
/* Should be enough precision for many samples. */
const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F;
const bool do_clear = (effects->taa_current_sample == 1);
/* Create FrameBuffer. */
GPU_framebuffer_ensure_config(&fbl->material_accum_fb,
{GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE});
if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear);
material_renderpass_init(&txl->env_accum, texture_format);
}
if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear);
material_renderpass_init(&txl->emit_accum, texture_format);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear);
material_renderpass_init(&txl->diff_color_accum, texture_format);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear);
material_renderpass_init(&txl->diff_light_accum, texture_format);
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) {
material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear);
material_renderpass_init(&txl->spec_color_accum, texture_format);
}
if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear);
material_renderpass_init(&txl->aov_surface_accum[aov_index], texture_format);
}
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear);
material_renderpass_init(&txl->spec_light_accum, texture_format);
if (effects->enabled_effects & EFFECT_SSR) {
EEVEE_reflection_output_init(sldata, vedata, tot_samples);
@ -1025,7 +1016,8 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
}
}
static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
static void material_renderpass_accumulate(EEVEE_EffectsInfo *effects,
EEVEE_FramebufferList *fbl,
DRWPass *renderpass,
DRWPass *renderpass2,
EEVEE_PrivateData *pd,
@ -1035,6 +1027,11 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl,
GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0);
GPU_framebuffer_bind(fbl->material_accum_fb);
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->material_accum_fb, clear);
}
pd->renderpass_ubo = renderpass_option_ubo;
DRW_draw_pass(renderpass);
if (renderpass2) {
@ -1056,15 +1053,21 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRWPass *material_accum_ps = psl->material_accum_ps;
DRWPass *background_accum_ps = psl->background_accum_ps;
if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) {
material_renderpass_accumulate(
fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment);
material_renderpass_accumulate(effects,
fbl,
background_accum_ps,
NULL,
pd,
txl->env_accum,
sldata->renderpass_ubo.environment);
}
if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) {
material_renderpass_accumulate(
fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
effects, fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) {
material_renderpass_accumulate(fbl,
material_renderpass_accumulate(effects,
fbl,
material_accum_ps,
NULL,
pd,
@ -1072,7 +1075,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
sldata->renderpass_ubo.diff_color);
}
if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) {
material_renderpass_accumulate(fbl,
material_renderpass_accumulate(effects,
fbl,
material_accum_ps,
NULL,
pd,
@ -1090,7 +1094,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
sldata->common_data.ssr_toggle = false;
GPU_uniformbuf_update(sldata->common_ubo, &sldata->common_data);
}
material_renderpass_accumulate(fbl,
material_renderpass_accumulate(effects,
fbl,
material_accum_ps,
NULL,
pd,
@ -1102,7 +1107,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
}
}
if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) {
material_renderpass_accumulate(fbl,
material_renderpass_accumulate(effects,
fbl,
material_accum_ps,
NULL,
pd,
@ -1115,7 +1121,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
}
if (pd->render_passes & EEVEE_RENDER_PASS_AOV) {
for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) {
material_renderpass_accumulate(fbl,
material_renderpass_accumulate(effects,
fbl,
material_accum_ps,
background_accum_ps,
pd,

View File

@ -40,12 +40,9 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = stl->effects;
EEVEE_PrivateData *g_data = stl->g_data;
Scene *scene = draw_ctx->scene;
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Create FrameBuffer. */
/* Should be enough precision for many samples. */
DRW_texture_ensure_fullscreen_2d(&txl->mist_accum, GPU_R32F, 0);
@ -53,12 +50,6 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
GPU_framebuffer_ensure_config(&fbl->mist_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)});
/* Clear texture. */
if (effects->taa_current_sample == 1) {
GPU_framebuffer_bind(fbl->mist_accum_fb);
GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear);
}
/* Mist settings. */
if (scene && scene->world) {
g_data->mist_start = scene->world->miststa;
@ -103,9 +94,17 @@ void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (fbl->mist_accum_fb != NULL) {
GPU_framebuffer_bind(fbl->mist_accum_fb);
/* Clear texture. */
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear);
}
DRW_draw_pass(psl->mist_accum_ps);
/* Restore */

View File

@ -120,7 +120,6 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_R32F : GPU_R16F;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Should be enough precision for many samples. */
DRW_texture_ensure_fullscreen_2d(&txl->ao_accum, texture_format, 0);
@ -128,12 +127,6 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata
GPU_framebuffer_ensure_config(&fbl->ao_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)});
/* Clear texture. */
if (effects->taa_current_sample == 1) {
GPU_framebuffer_bind(fbl->ao_accum_fb);
GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);
}
/* Accumulation pass */
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD;
DRW_PASS_CREATE(psl->ao_accum_ps, state);
@ -246,6 +239,7 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (fbl->ao_accum_fb != NULL) {
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
@ -255,6 +249,13 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *
EEVEE_occlusion_compute(sldata, vedata);
GPU_framebuffer_bind(fbl->ao_accum_fb);
/* Clear texture. */
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear);
}
DRW_draw_pass(psl->ao_accum_ps);
/* Restore */

View File

@ -234,10 +234,6 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Create FrameBuffer. */
const eGPUTextureFormat texture_format = (tot_samples > 256) ? GPU_RGBA32F : GPU_RGBA16F;
@ -245,12 +241,6 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata),
GPU_framebuffer_ensure_config(&fbl->ssr_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)});
/* Clear texture. */
if (effects->taa_current_sample == 1) {
GPU_framebuffer_bind(fbl->ssr_accum_fb);
GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear);
}
}
void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata)
@ -258,9 +248,17 @@ void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEV
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (stl->g_data->valid_double_buffer) {
GPU_framebuffer_bind(fbl->ssr_accum_fb);
/* Clear texture. */
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear);
}
DRW_draw_pass(psl->ssr_resolve);
}
}

View File

@ -361,12 +361,8 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata,
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_TextureList *txl = vedata->txl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_StorageList *stl = vedata->stl;
EEVEE_EffectsInfo *effects = stl->effects;
DefaultTextureList *dtxl = DRW_viewport_texture_list_get();
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Create FrameBuffer. */
const eGPUTextureFormat texture_format = GPU_R32F;
DRW_texture_ensure_fullscreen_2d(&txl->shadow_accum, texture_format, 0);
@ -374,12 +370,6 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata,
GPU_framebuffer_ensure_config(&fbl->shadow_accum_fb,
{GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)});
/* Clear texture. */
if (effects->taa_current_sample == 1) {
GPU_framebuffer_bind(fbl->shadow_accum_fb);
GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear);
}
/* Create Pass and shgroup. */
DRW_PASS_CREATE(psl->shadow_accum_pass,
DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ADD_FULL);
@ -404,9 +394,17 @@ void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_D
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (fbl->shadow_accum_fb != NULL) {
GPU_framebuffer_bind(fbl->shadow_accum_fb);
/* Clear texture. */
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear);
}
DRW_draw_pass(psl->shadow_accum_pass);
/* Restore */

View File

@ -800,8 +800,6 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = stl->effects;
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
/* Create FrameBuffer. */
/* Should be enough precision for many samples. */
@ -814,12 +812,6 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata,
GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_accum),
GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)});
/* Clear texture. */
if (effects->taa_current_sample == 1) {
GPU_framebuffer_bind(fbl->volumetric_accum_fb);
GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear);
}
/* Create Pass and shgroup. */
DRW_PASS_CREATE(psl->volumetric_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL);
DRWShadingGroup *grp = NULL;
@ -843,10 +835,18 @@ void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_
{
EEVEE_FramebufferList *fbl = vedata->fbl;
EEVEE_PassList *psl = vedata->psl;
EEVEE_EffectsInfo *effects = vedata->stl->effects;
if (fbl->volumetric_accum_fb != NULL) {
/* Accum pass */
GPU_framebuffer_bind(fbl->volumetric_accum_fb);
/* Clear texture. */
if (effects->taa_current_sample == 1) {
const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f};
GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear);
}
DRW_draw_pass(psl->volumetric_accum_ps);
/* Restore */

View File

@ -183,16 +183,70 @@ vec3 light_translucent(LightData ld, vec3 P, vec3 N, vec4 l_vector, vec2 rand, f
#undef scube
#undef scsmd
/* Similar to https://atyuwen.github.io/posts/normal-reconstruction/.
* This samples the depth buffer 4 time for each direction to get the most correct
* implicit normal reconstruction out of the depth buffer. */
vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float depth_center)
{
vec2 uv1 = uvs - ofs * 2.0;
vec2 uv2 = uvs - ofs;
vec2 uv3 = uvs + ofs;
vec2 uv4 = uvs + ofs * 2.0;
vec4 H;
H.x = textureLod(depthBuffer, uv1, 0.0).r;
H.y = textureLod(depthBuffer, uv2, 0.0).r;
H.z = textureLod(depthBuffer, uv3, 0.0).r;
H.w = textureLod(depthBuffer, uv4, 0.0).r;
/* Fix issue with depth precision. Take even larger diff. */
vec4 diff = abs(vec4(depth_center, H.yzw) - H.x);
if (max_v4(diff) < 2.4e-7 && all(lessThan(diff.xyz, diff.www))) {
return 0.25 * (get_view_space_from_depth(uv3, H.w) - get_view_space_from_depth(uv1, H.x));
}
/* Simplified (H.xw + 2.0 * (H.yz - H.xw)) - depth_center */
vec2 deltas = abs((2.0 * H.yz - H.xw) - depth_center);
if (deltas.x < deltas.y) {
return vP - get_view_space_from_depth(uv2, H.y);
}
else {
return get_view_space_from_depth(uv3, H.z) - vP;
}
}
/* TODO(fclem) port to a common place for other effects to use. */
bool reconstruct_view_position_and_normal_from_depth(vec2 uvs, out vec3 vP, out vec3 vNg)
{
vec2 texel_size = vec2(abs(dFdx(uvs.x)), abs(dFdy(uvs.y)));
float depth_center = textureLod(depthBuffer, uvs, 0.0).r;
vP = get_view_space_from_depth(uvs, depth_center);
vec3 dPdx = view_position_derivative_from_depth(uvs, texel_size * vec2(1, 0), vP, depth_center);
vec3 dPdy = view_position_derivative_from_depth(uvs, texel_size * vec2(0, 1), vP, depth_center);
vNg = safe_normalize(cross(dPdx, dPdy));
/* Background case. */
if (depth_center == 1.0) {
return false;
}
return true;
}
void main(void)
{
vec2 uvs = uvcoordsvar.xy;
float sss_scale = texture(sssRadius, uvs).r;
vec3 P = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r);
vec3 N = normalize(cross(dFdx(P), dFdy(P)));
vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
rand.xy *= fast_sqrt(rand.z);
vec3 vP, vNg;
reconstruct_view_position_and_normal_from_depth(uvs, vP, vNg);
vec3 P = point_view_to_world(vP);
vec3 Ng = normal_view_to_world(vNg);
vec3 accum = vec3(0.0);
for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
LightData ld = lights_data[i];
@ -211,7 +265,7 @@ void main(void)
continue;
}
accum += att * ld.l_color * light_translucent(ld, P, -N, l_vector, rand.xy, sss_scale);
accum += att * ld.l_color * light_translucent(ld, P, -Ng, l_vector, rand.xy, sss_scale);
}
FragColor = vec4(accum, 1.0);

View File

@ -1031,7 +1031,7 @@ static void pchan_draw_data_init(bPoseChannel *pchan)
static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *pchan)
{
float ebmat[4][4];
float length;
float bone_scale[3];
float(*bone_mat)[4];
float(*disp_mat)[4];
float(*disp_tail_mat)[4];
@ -1040,23 +1040,23 @@ static void draw_bone_update_disp_matrix_default(EditBone *eBone, bPoseChannel *
* and not be tight to the draw pass creation.
* This would refresh armature without invalidating the draw cache */
if (pchan) {
length = pchan->bone->length;
bone_mat = pchan->pose_mat;
disp_mat = pchan->disp_mat;
disp_tail_mat = pchan->disp_tail_mat;
mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, pchan->bone->length);
}
else {
eBone->length = len_v3v3(eBone->tail, eBone->head);
ED_armature_ebone_to_mat4(eBone, ebmat);
length = eBone->length;
copy_v3_fl(bone_scale, eBone->length);
bone_mat = ebmat;
disp_mat = eBone->disp_mat;
disp_tail_mat = eBone->disp_tail_mat;
}
copy_m4_m4(disp_mat, bone_mat);
rescale_m4(disp_mat, (float[3]){length, length, length});
rescale_m4(disp_mat, bone_scale);
copy_m4_m4(disp_tail_mat, disp_mat);
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
}
@ -1255,19 +1255,27 @@ static void draw_bone_update_disp_matrix_bbone(EditBone *eBone, bPoseChannel *pc
static void draw_bone_update_disp_matrix_custom(bPoseChannel *pchan)
{
float length;
float bone_scale[3];
float(*bone_mat)[4];
float(*disp_mat)[4];
float(*disp_tail_mat)[4];
float rot_mat[3][3];
/* See TODO above */
length = PCHAN_CUSTOM_DRAW_SIZE(pchan);
mul_v3_v3fl(bone_scale, pchan->custom_scale_xyz, PCHAN_CUSTOM_BONE_LENGTH(pchan));
bone_mat = pchan->custom_tx ? pchan->custom_tx->pose_mat : pchan->pose_mat;
disp_mat = pchan->disp_mat;
disp_tail_mat = pchan->disp_tail_mat;
eulO_to_mat3(rot_mat, pchan->custom_rotation_euler, ROT_MODE_XYZ);
copy_m4_m4(disp_mat, bone_mat);
rescale_m4(disp_mat, (float[3]){length, length, length});
translate_m4(disp_mat,
pchan->custom_translation[0],
pchan->custom_translation[1],
pchan->custom_translation[2]);
mul_m4_m4m3(disp_mat, disp_mat, rot_mat);
rescale_m4(disp_mat, bone_scale);
copy_m4_m4(disp_tail_mat, disp_mat);
translate_m4(disp_tail_mat, 0.0f, 1.0f, 0.0f);
}

View File

@ -285,10 +285,6 @@ static bool overlay_should_fade_object(Object *ob, Object *active_object)
return false;
}
if (ob->base_flag & BASE_FROM_DUPLI) {
return false;
}
return true;
}

View File

@ -557,6 +557,7 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
if (name[0] == '\0') {
return OPERATOR_CANCELLED;
}
const bool only_active = RNA_boolean_get(op->ptr, "only_active");
Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
@ -564,10 +565,10 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
Object *ob_src = CTX_data_active_object(C);
bGPdata *gpd_src = (bGPdata *)ob_src->data;
bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd_src);
bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd_src);
/* Sanity checks. */
if (ELEM(NULL, gpd_src, gpl_src, ob_dst)) {
if (ELEM(NULL, gpd_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
/* Cannot copy itself and check destination type. */
@ -576,47 +577,55 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
}
bGPdata *gpd_dst = (bGPdata *)ob_dst->data;
/* Create new layer. */
bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
/* Need to copy some variables (not all). */
gpl_dst->onion_flag = gpl_src->onion_flag;
gpl_dst->thickness = gpl_src->thickness;
gpl_dst->line_change = gpl_src->line_change;
copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
gpl_dst->opacity = gpl_src->opacity;
/* Create all frames. */
LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
/* Create new frame. */
bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
/* Copy strokes. */
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
/* Check if material is in destination object,
* otherwise add the slot with the material. */
Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1);
if (ma_src != NULL) {
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
/* Reassign the stroke material to the right slot in destination object. */
gps_dst->mat_nr = idx;
}
/* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
/* Disable destination active layer to keep order. */
LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_dst->layers) {
gpl->flag &= ~GP_LAYER_ACTIVE;
}
LISTBASE_FOREACH (bGPDlayer *, gpl_src, &gpd_src->layers) {
if ((only_active) && (gpl_src != gpl_active)) {
continue;
}
/* Create new layer. */
bGPDlayer *gpl_dst = BKE_gpencil_layer_addnew(gpd_dst, gpl_src->info, true);
/* Need to copy some variables (not all). */
gpl_dst->onion_flag = gpl_src->onion_flag;
gpl_dst->thickness = gpl_src->thickness;
gpl_dst->line_change = gpl_src->line_change;
copy_v4_v4(gpl_dst->tintcolor, gpl_src->tintcolor);
gpl_dst->opacity = gpl_src->opacity;
/* Create all frames. */
LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) {
if ((mode == GP_LAYER_COPY_OBJECT_ACT_FRAME) && (gpf_src != gpl_src->actframe)) {
continue;
}
/* Create new frame. */
bGPDframe *gpf_dst = BKE_gpencil_frame_addnew(gpl_dst, gpf_src->framenum);
/* Copy strokes. */
LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) {
/* Make copy of source stroke. */
bGPDstroke *gps_dst = BKE_gpencil_stroke_duplicate(gps_src, true, true);
/* Check if material is in destination object,
* otherwise add the slot with the material. */
Material *ma_src = BKE_object_material_get(ob_src, gps_src->mat_nr + 1);
if (ma_src != NULL) {
int idx = BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
/* Reassign the stroke material to the right slot in destination object. */
gps_dst->mat_nr = idx;
}
/* Add new stroke to frame. */
BLI_addtail(&gpf_dst->strokes, gps_dst);
}
}
}
/* notifiers */
DEG_id_tag_update(&gpd_dst->id,
ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
@ -628,6 +637,8 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op)
void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
{
PropertyRNA *prop;
static const EnumPropertyItem copy_mode[] = {
{GP_LAYER_COPY_OBJECT_ALL_FRAME, "ALL", 0, "All Frames", ""},
{GP_LAYER_COPY_OBJECT_ACT_FRAME, "ACTIVE", 0, "Active Frame", ""},
@ -651,6 +662,13 @@ void GPENCIL_OT_layer_duplicate_object(wmOperatorType *ot)
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
RNA_def_enum(ot->srna, "mode", copy_mode, GP_LAYER_COPY_OBJECT_ALL_FRAME, "Mode", "");
prop = RNA_def_boolean(ot->srna,
"only_active",
true,
"Only Active",
"Append only active Layer, uncheck to append all layers");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* ********************* Duplicate Frame ************************** */
@ -3589,6 +3607,101 @@ void GPENCIL_OT_set_active_material(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ********************* Append Materials in a new object ************************** */
static bool gpencil_materials_append_to_object_poll(bContext *C)
{
ViewLayer *view_layer = CTX_data_view_layer(C);
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
return false;
}
short *totcolp = BKE_object_material_len_p(ob);
if (*totcolp == 0) {
return false;
}
/* check there are more grease pencil objects */
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if ((base->object != ob) && (base->object->type == OB_GPENCIL)) {
return true;
}
}
return false;
}
static int gpencil_materials_append_to_object_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
char name[MAX_ID_NAME - 2];
RNA_string_get(op->ptr, "object", name);
if (name[0] == '\0') {
return OPERATOR_CANCELLED;
}
const bool only_selected = RNA_boolean_get(op->ptr, "only_selected");
Object *ob_dst = (Object *)BKE_scene_object_find_by_name(scene, name);
Object *ob_src = CTX_data_active_object(C);
Material *ma_active = BKE_gpencil_material(ob_src, ob_src->actcol);
/* Sanity checks. */
if (ELEM(NULL, ob_src, ob_dst)) {
return OPERATOR_CANCELLED;
}
/* Cannot copy itself and check destination type. */
if ((ob_src == ob_dst) || (ob_dst->type != OB_GPENCIL)) {
return OPERATOR_CANCELLED;
}
/* Duplicate materials. */
for (int i = 0; i < ob_src->totcol; i++) {
Material *ma_src = BKE_object_material_get(ob_src, i + 1);
if (only_selected && ma_src != ma_active) {
continue;
}
if (ma_src != NULL) {
BKE_gpencil_object_material_ensure(bmain, ob_dst, ma_src);
}
}
/* notifiers */
DEG_id_tag_update(&ob_dst->id, ID_RECALC_COPY_ON_WRITE);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
void GPENCIL_OT_materials_append_to_object(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Append Materials to New Object";
ot->idname = "GPENCIL_OT_materials_append_to_object";
ot->description = "Append Materials of the active Grease Pencil to other object";
/* callbacks */
ot->exec = gpencil_materials_append_to_object_exec;
ot->poll = gpencil_materials_append_to_object_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
ot->prop = RNA_def_string(
ot->srna, "object", NULL, MAX_ID_NAME - 2, "Object", "Name of the destination object");
RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"only_selected",
true,
"Only Selected",
"Append only selected material, uncheck to append all materials");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* Parent GPencil object to Lattice */
bool ED_gpencil_add_lattice_modifier(const bContext *C,
ReportList *reports,

View File

@ -538,6 +538,7 @@ void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot);
void GPENCIL_OT_material_select(struct wmOperatorType *ot);
void GPENCIL_OT_material_set(struct wmOperatorType *ot);
void GPENCIL_OT_set_active_material(struct wmOperatorType *ot);
void GPENCIL_OT_materials_append_to_object(struct wmOperatorType *ot);
/* convert old 2.7 files to 2.8 */
void GPENCIL_OT_convert_old_files(struct wmOperatorType *ot);

View File

@ -651,6 +651,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_material_to_vertex_color);
WM_operatortype_append(GPENCIL_OT_extract_palette_vertex);
WM_operatortype_append(GPENCIL_OT_materials_append_to_object);
WM_operatortype_append(GPENCIL_OT_transform_fill);
WM_operatortype_append(GPENCIL_OT_reset_transform_fill);

View File

@ -3677,14 +3677,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* is essential for ensuring that they can quickly return to that view
*/
}
else if ((event->type == EVT_BKEY) && (event->val == KM_RELEASE)) {
/* Add Blank Frame
* - Since this operator is non-modal, we can just call it here, and keep going...
* - This operator is especially useful when animating
*/
WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL);
estate = OPERATOR_RUNNING_MODAL;
}
else if ((!ELEM(p->paintmode, GP_PAINTMODE_ERASER, GP_PAINTMODE_SET_CP))) {
gpencil_guide_event_handling(C, op, event, p);
estate = OPERATOR_RUNNING_MODAL;

View File

@ -247,6 +247,7 @@ void ED_object_texture_paint_mode_enter(struct bContext *C);
void ED_object_texture_paint_mode_exit_ex(struct Main *bmain, struct Scene *scene, Object *ob);
void ED_object_texture_paint_mode_exit(struct bContext *C);
bool ED_object_particle_edit_mode_supported(const Object *ob);
void ED_object_particle_edit_mode_enter_ex(struct Depsgraph *depsgraph,
struct Scene *scene,
Object *ob);

View File

@ -477,6 +477,7 @@ static bool ui_do_but_extra_operator_icon(bContext *C,
static void ui_do_but_extra_operator_icons_mousemove(uiBut *but,
uiHandleButtonData *data,
const wmEvent *event);
static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data);
#ifdef USE_DRAG_MULTINUM
static void ui_multibut_restore(bContext *C, uiHandleButtonData *data, uiBlock *block);
@ -3361,6 +3362,8 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
if (is_num_but) {
BLI_assert(data->is_str_dynamic == false);
ui_but_convert_to_unit_alt_name(but, data->str, data->maxlen);
ui_numedit_begin_set_values(but, data);
}
/* won't change from now on */
@ -3897,6 +3900,14 @@ static void ui_do_but_textedit_select(
/** \name Button Number Editing (various types)
* \{ */
static void ui_numedit_begin_set_values(uiBut *but, uiHandleButtonData *data)
{
data->startvalue = ui_but_value_get(but);
data->origvalue = data->startvalue;
data->value = data->origvalue;
but->editval = &data->value;
}
static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
{
if (but->type == UI_BTYPE_CURVE) {
@ -3922,16 +3933,11 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
but->editvec = data->vec;
}
else {
float softrange, softmin, softmax;
ui_numedit_begin_set_values(but, data);
data->startvalue = ui_but_value_get(but);
data->origvalue = data->startvalue;
data->value = data->origvalue;
but->editval = &data->value;
softmin = but->softmin;
softmax = but->softmax;
softrange = softmax - softmin;
float softmin = but->softmin;
float softmax = but->softmax;
float softrange = softmax - softmin;
if ((but->type == UI_BTYPE_NUM) && (ui_but_is_cursor_warp(but) == false)) {
uiButNumber *number_but = (uiButNumber *)but;

View File

@ -2547,6 +2547,7 @@ bool EDBM_selectmode_set_multi(bContext *C, const short selectmode)
changed = true;
}
}
MEM_freeN(objects);
if (changed) {
WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, NULL);

View File

@ -860,8 +860,9 @@ static int effector_add_exec(bContext *C, wmOperator *op)
float mat[4][4];
ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
mul_mat3_m4_fl(mat, dia);
BLI_addtail(&cu->editnurb->nurbs,
ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia));
ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1));
if (!enter_editmode) {
ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA);
}
@ -1310,6 +1311,8 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? ob->data : NULL;
const int type = RNA_enum_get(op->ptr, "type");
const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front");
const int stroke_depth_order = RNA_enum_get(op->ptr, "stroke_depth_order");
ushort local_view_bits;
float loc[3], rot[3];
@ -1337,6 +1340,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
break;
}
case GP_LRT_OBJECT:
case GP_LRT_SCENE:
case GP_LRT_COLLECTION: {
ob_name = "Line Art";
break;
@ -1429,7 +1433,15 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
}
/* Stroke object is drawn in front of meshes by default. */
ob->dtx |= OB_DRAW_IN_FRONT;
if (use_in_front) {
ob->dtx |= OB_DRAW_IN_FRONT;
}
else {
if (stroke_depth_order == GP_DRAWMODE_3D) {
gpd->draw_mode = GP_DRAWMODE_3D;
}
}
break;
}
default:
@ -1448,6 +1460,38 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static void object_add_ui(bContext *UNUSED(C), wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayoutSetPropSep(layout, true);
uiItemR(layout, op->ptr, "radius", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "align", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "location", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "rotation", 0, NULL, ICON_NONE);
uiItemR(layout, op->ptr, "type", 0, NULL, ICON_NONE);
int type = RNA_enum_get(op->ptr, "type");
if (type == GP_LRT_COLLECTION || type == GP_LRT_OBJECT || type == GP_LRT_SCENE) {
uiItemR(layout, op->ptr, "use_in_front", 0, NULL, ICON_NONE);
bool in_front = RNA_boolean_get(op->ptr, "use_in_front");
uiLayout *row = uiLayoutRow(layout, false);
uiLayoutSetActive(row, !in_front);
uiItemR(row, op->ptr, "stroke_depth_order", 0, NULL, ICON_NONE);
}
}
static EnumPropertyItem rna_enum_gpencil_add_stroke_depth_order_items[] = {
{GP_DRAWMODE_2D,
"2D",
0,
"2D Layers",
"Display strokes using grease pencil layers to define order"},
{GP_DRAWMODE_3D, "3D", 0, "3D Location", "Display strokes using real 3D position in 3D space"},
{0, NULL, 0, NULL, NULL},
};
void OBJECT_OT_gpencil_add(wmOperatorType *ot)
{
/* identifiers */
@ -1463,11 +1507,26 @@ void OBJECT_OT_gpencil_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* ui */
ot->ui = object_add_ui;
/* properties */
ED_object_add_unit_props_radius(ot);
ED_object_add_generic_props(ot, false);
ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_object_gpencil_type_items, 0, "Type", "");
RNA_def_boolean(ot->srna,
"use_in_front",
false,
"In Front",
"Show line art grease pencil in front of everything");
RNA_def_enum(
ot->srna,
"stroke_depth_order",
rna_enum_gpencil_add_stroke_depth_order_items,
GP_DRAWMODE_3D,
"Stroke Depth Order",
"Defines how the strokes are ordered in 3D space for objects not displayed 'In Front'");
}
/** \} */

View File

@ -1590,30 +1590,10 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C,
return rna_enum_object_mode_items;
}
Object *ob = CTX_data_active_object(C);
const Object *ob = CTX_data_active_object(C);
if (ob) {
const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) ||
(ob->soft != NULL) ||
(BKE_modifiers_findby_type(ob, eModifierType_Cloth) !=
NULL);
while (input->identifier) {
if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) ||
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
(ELEM(input->value,
OB_MODE_SCULPT,
OB_MODE_VERTEX_PAINT,
OB_MODE_WEIGHT_PAINT,
OB_MODE_TEXTURE_PAINT) &&
(ob->type == OB_MESH)) ||
(ELEM(input->value,
OB_MODE_EDIT_GPENCIL,
OB_MODE_PAINT_GPENCIL,
OB_MODE_SCULPT_GPENCIL,
OB_MODE_WEIGHT_GPENCIL,
OB_MODE_VERTEX_GPENCIL) &&
(ob->type == OB_GPENCIL)) ||
(input->value == OB_MODE_OBJECT)) {
if (ED_object_mode_compat_test(ob, input->value)) {
RNA_enum_item_add(&item, &totitem, input);
}
input++;

View File

@ -115,43 +115,46 @@ static const char *object_mode_op_string(eObjectMode mode)
*/
bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode)
{
if (ob) {
if (mode == OB_MODE_OBJECT) {
return true;
}
if (mode == OB_MODE_OBJECT) {
return true;
}
switch (ob->type) {
case OB_MESH:
if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT |
OB_MODE_TEXTURE_PAINT | OB_MODE_PARTICLE_EDIT)) {
switch (ob->type) {
case OB_MESH:
if (mode & (OB_MODE_EDIT | OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT |
OB_MODE_TEXTURE_PAINT)) {
return true;
}
if (mode & OB_MODE_PARTICLE_EDIT) {
if (ED_object_particle_edit_mode_supported(ob)) {
return true;
}
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
case OB_MBALL:
if (mode & OB_MODE_EDIT) {
return true;
}
break;
case OB_LATTICE:
if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) {
return true;
}
break;
case OB_ARMATURE:
if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) {
return true;
}
break;
case OB_GPENCIL:
if (mode & (OB_MODE_EDIT | OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL |
OB_MODE_SCULPT_GPENCIL | OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)) {
return true;
}
break;
}
}
break;
case OB_CURVE:
case OB_SURF:
case OB_FONT:
case OB_MBALL:
if (mode & OB_MODE_EDIT) {
return true;
}
break;
case OB_LATTICE:
if (mode & (OB_MODE_EDIT | OB_MODE_WEIGHT_PAINT)) {
return true;
}
break;
case OB_ARMATURE:
if (mode & (OB_MODE_EDIT | OB_MODE_POSE)) {
return true;
}
break;
case OB_GPENCIL:
if (mode & (OB_MODE_EDIT_GPENCIL | OB_MODE_PAINT_GPENCIL | OB_MODE_SCULPT_GPENCIL |
OB_MODE_WEIGHT_GPENCIL | OB_MODE_VERTEX_GPENCIL)) {
return true;
}
break;
}
return false;

View File

@ -210,7 +210,7 @@ ModifierData *ED_object_modifier_add(
/* special cases */
if (type == eModifierType_Softbody) {
if (!ob->soft) {
ob->soft = sbNew(scene);
ob->soft = sbNew();
ob->softflag |= OB_SB_GOAL | OB_SB_EDGES;
}
}

View File

@ -5375,8 +5375,7 @@ static bool particle_edit_toggle_poll(bContext *C)
return 0;
}
return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) ||
BKE_modifiers_findby_type(ob, eModifierType_Softbody));
return ED_object_particle_edit_mode_supported(ob);
}
static void free_all_psys_edit(Object *object)
@ -5391,6 +5390,12 @@ static void free_all_psys_edit(Object *object)
}
}
bool ED_object_particle_edit_mode_supported(const Object *ob)
{
return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) ||
BKE_modifiers_findby_type(ob, eModifierType_Softbody));
}
void ED_object_particle_edit_mode_enter_ex(Depsgraph *depsgraph, Scene *scene, Object *ob)
{
/* Needed so #ParticleSystemModifierData.mesh_final is set. */

View File

@ -139,13 +139,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
const bool is_gpencil = (brush && brush->gpencil_settings != NULL);
// Object *ob = CTX_data_active_object(C);
float scalar = RNA_float_get(op->ptr, "scalar");
if (brush) {
/* pixel radius */
{
const int old_size = BKE_brush_size_get(scene, brush);
const int old_size = (!is_gpencil) ? BKE_brush_size_get(scene, brush) : brush->size;
int size = (int)(scalar * old_size);
if (abs(old_size - size) < U.pixelsize) {
@ -156,6 +157,12 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
size -= U.pixelsize;
}
}
/* Grease Pencil does not use unified size. */
if (is_gpencil) {
brush->size = max_ii(size, 1);
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
return OPERATOR_FINISHED;
}
BKE_brush_size_set(scene, brush, size);
}

View File

@ -1931,13 +1931,22 @@ static int sculpt_expand_modal(bContext *C, wmOperator *op, const wmEvent *event
* The faces that were using the `delete_id` Face Set are filled
* using the content from their neighbors.
*/
static void sculpt_expand_delete_face_set_id(
int *r_face_sets, Mesh *mesh, MeshElemMap *pmap, const int totface, const int delete_id)
static void sculpt_expand_delete_face_set_id(int *r_face_sets,
SculptSession *ss,
ExpandCache *expand_cache,
Mesh *mesh,
const int delete_id)
{
const int totface = ss->totvert;
MeshElemMap *pmap = ss->pmap;
/* Check that all the face sets IDs in the mesh are not equal to `delete_id`
* before attempting to delete it. */
bool all_same_id = true;
for (int i = 0; i < totface; i++) {
if (!sculpt_expand_is_face_in_active_component(ss, expand_cache, i)) {
continue;
}
if (r_face_sets[i] != delete_id) {
all_same_id = false;
break;
@ -2109,9 +2118,9 @@ static int sculpt_expand_invoke(bContext *C, wmOperator *op, const wmEvent *even
if (ss->expand_cache->modify_active_face_set) {
sculpt_expand_delete_face_set_id(ss->expand_cache->initial_face_sets,
ss,
ss->expand_cache,
ob->data,
ss->pmap,
ss->totfaces,
ss->expand_cache->next_face_set);
}

View File

@ -52,6 +52,7 @@
#include "RNA_enum_types.h"
#include "SEQ_iterator.h"
#include "SEQ_utils.h"
#include "UI_interface.h"
@ -258,7 +259,7 @@ static void sound_update_animation_flags(Scene *scene)
scene->id.tag |= LIB_TAG_DOIT;
SEQ_ALL_BEGIN (scene->ed, seq) {
SEQ_iterator_recursive_apply(seq, sound_update_animation_flags_fn, scene);
SEQ_recursive_apply(seq, sound_update_animation_flags_fn, scene);
}
SEQ_ALL_END;

View File

@ -24,8 +24,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BLT_translation.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
@ -398,6 +401,28 @@ static int track_markers_modal(bContext *C, wmOperator *UNUSED(op), const wmEven
return OPERATOR_PASS_THROUGH;
}
static char *track_markers_desc(bContext *UNUSED(C), wmOperatorType *UNUSED(op), PointerRNA *ptr)
{
const bool backwards = RNA_boolean_get(ptr, "backwards");
const bool sequence = RNA_boolean_get(ptr, "sequence");
if (backwards && sequence) {
return BLI_strdup(TIP_("Track the selected markers backward for the entire clip"));
}
if (backwards && !sequence) {
return BLI_strdup(TIP_("Track the selected markers backward by one frame"));
}
if (!backwards && sequence) {
return BLI_strdup(TIP_("Track the selected markers forward for the entire clip"));
}
if (!backwards && !sequence) {
return BLI_strdup(TIP_("Track the selected markers forward by one frame"));
}
/* Use default description. */
return NULL;
}
void CLIP_OT_track_markers(wmOperatorType *ot)
{
/* identifiers */
@ -410,6 +435,7 @@ void CLIP_OT_track_markers(wmOperatorType *ot)
ot->invoke = track_markers_invoke;
ot->modal = track_markers_modal;
ot->poll = ED_space_clip_tracking_poll;
ot->get_description = track_markers_desc;
/* flags */
ot->flag = OPTYPE_UNDO;

View File

@ -63,6 +63,7 @@ void FILE_OT_bookmark_move(struct wmOperatorType *ot);
void FILE_OT_reset_recent(wmOperatorType *ot);
void FILE_OT_hidedot(struct wmOperatorType *ot);
void FILE_OT_execute(struct wmOperatorType *ot);
void FILE_OT_mouse_execute(struct wmOperatorType *ot);
void FILE_OT_cancel(struct wmOperatorType *ot);
void FILE_OT_parent(struct wmOperatorType *ot);
void FILE_OT_directory_new(struct wmOperatorType *ot);

View File

@ -536,6 +536,14 @@ void FILE_OT_select_box(wmOperatorType *ot)
/** \name Select Pick Operator
* \{ */
static rcti file_select_mval_to_select_rect(const int mval[2])
{
rcti rect;
rect.xmin = rect.xmax = mval[0];
rect.ymin = rect.ymax = mval[1];
return rect;
}
static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
@ -551,8 +559,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
rect.xmin = rect.xmax = event->mval[0];
rect.ymin = rect.ymax = event->mval[1];
rect = file_select_mval_to_select_rect(event->mval);
if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &region->v2d, rect.xmin, rect.ymin)) {
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
@ -1711,14 +1718,14 @@ bool file_draw_check_exists(SpaceFile *sfile)
/** \name Execute File Window Operator
* \{ */
static int file_exec(bContext *C, wmOperator *exec_op)
/**
* Execute the active file, as set in the file select params.
*/
static bool file_execute(bContext *C, SpaceFile *sfile)
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
SpaceFile *sfile = CTX_wm_space_file(C);
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
struct FileDirEntry *file = filelist_file(sfile->files, params->active_file);
char filepath[FILE_MAX];
FileDirEntry *file = filelist_file(sfile->files, params->active_file);
if (file && file->redirection_path) {
/* redirection_path is an absolute path that takes precedence
@ -1753,22 +1760,7 @@ static int file_exec(bContext *C, wmOperator *exec_op)
/* opening file - sends events now, so things get handled on windowqueue level */
else if (sfile->op) {
wmOperator *op = sfile->op;
/* When used as a macro, for double-click, to prevent closing when double-clicking on item. */
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
const int numfiles = filelist_files_ensure(sfile->files);
int i, active = 0;
for (i = 0; i < numfiles; i++) {
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
active = 1;
break;
}
}
if (active == 0) {
return OPERATOR_CANCELLED;
}
}
char filepath[FILE_MAX];
sfile->op = NULL;
@ -1788,13 +1780,53 @@ static int file_exec(bContext *C, wmOperator *exec_op)
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), filepath);
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
WM_event_fileselect_event(CTX_wm_manager(C), op, EVT_FILESELECT_EXEC);
}
return OPERATOR_FINISHED;
}
static int file_exec_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int file_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceFile *sfile = CTX_wm_space_file(C);
if (!file_execute(C, sfile)) {
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED;
}
void FILE_OT_execute(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Execute File Window";
ot->description = "Execute selected file";
ot->idname = "FILE_OT_execute";
/* api callbacks */
ot->exec = file_exec;
/* Important since handler is on window level.
*
* Avoid using #file_operator_poll since this is also used for entering directories
* which is used even when the file manager doesn't have an operator. */
ot->poll = ED_operator_file_active;
}
/**
* \returns false if the mouse doesn't hover a selectable item.
*/
static bool file_ensure_hovered_is_active(bContext *C, const wmEvent *event)
{
rcti rect = file_select_mval_to_select_rect(event->mval);
if (file_select(C, &rect, FILE_SEL_ADD, false, false) == FILE_SELECT_NOTHING) {
return false;
}
return true;
}
static int file_execute_mouse_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
ARegion *region = CTX_wm_region(C);
SpaceFile *sfile = CTX_wm_space_file(C);
@ -1804,34 +1836,38 @@ static int file_exec_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
return file_exec(C, op);
/* Note that this isn't needed practically, because the keymap already activates the hovered item
* on mouse-press. This execute operator is called afterwards on the double-click event then.
* However relying on this would be fragile and could break with keymap changes, so better to
* have this mouse-execute operator that makes sure once more that the hovered file is active. */
if (!file_ensure_hovered_is_active(C, event)) {
return OPERATOR_CANCELLED;
}
if (!file_execute(C, sfile)) {
return OPERATOR_CANCELLED;
}
return OPERATOR_FINISHED;
}
void FILE_OT_execute(struct wmOperatorType *ot)
/**
* Variation of #FILE_OT_execute that accounts for some mouse specific handling. Otherwise calls
* the same logic.
*/
void FILE_OT_mouse_execute(wmOperatorType *ot)
{
PropertyRNA *prop;
/* identifiers */
ot->name = "Execute File Window";
ot->description = "Execute selected file";
ot->idname = "FILE_OT_execute";
ot->name = "Execute File";
ot->description =
"Perform the current execute action for the file under the cursor (e.g. open the file)";
ot->idname = "FILE_OT_mouse_execute";
/* api callbacks */
ot->invoke = file_exec_invoke;
ot->exec = file_exec;
/* Important since handler is on window level.
*
* Avoid using #file_operator_poll since this is also used for entering directories
* which is used even when the file manager doesn't have an operator. */
ot->invoke = file_execute_mouse_invoke;
ot->poll = ED_operator_file_active;
/* properties */
prop = RNA_def_boolean(ot->srna,
"need_active",
0,
"Need Active",
"Only execute if there's an active selected file in the file list");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
ot->flag = OPTYPE_INTERNAL;
}
/** \} */

View File

@ -663,6 +663,7 @@ static void file_operatortypes(void)
WM_operatortype_append(FILE_OT_highlight);
WM_operatortype_append(FILE_OT_sort_column_ui_context);
WM_operatortype_append(FILE_OT_execute);
WM_operatortype_append(FILE_OT_mouse_execute);
WM_operatortype_append(FILE_OT_cancel);
WM_operatortype_append(FILE_OT_parent);
WM_operatortype_append(FILE_OT_previous);

View File

@ -456,7 +456,9 @@ static void node_draw_frame(const bContext *C,
}
/* label */
node_draw_frame_label(ntree, node, snode->runtime->aspect);
if (node->label[0] != '\0') {
node_draw_frame_label(ntree, node, snode->runtime->aspect);
}
UI_block_end(C, node->block);
UI_block_draw(C, node->block);

View File

@ -902,7 +902,7 @@ static void id_override_library_reset_fn(bContext *C,
}
static void id_override_library_resync_fn(bContext *C,
ReportList *UNUSED(reports),
ReportList *reports,
Scene *scene,
TreeElement *te,
TreeStoreElem *UNUSED(tsep),
@ -931,7 +931,7 @@ static void id_override_library_resync_fn(bContext *C,
}
BKE_lib_override_library_resync(
bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true);
bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true, reports);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}

View File

@ -95,7 +95,7 @@ typedef struct SequencerAddData {
#define SEQPROP_NOPATHS (1 << 2)
#define SEQPROP_NOCHAN (1 << 3)
#define SEQPROP_FIT_METHOD (1 << 4)
#define SEQPROP_VIEW_TRANSFORM (1 << 4)
#define SEQPROP_VIEW_TRANSFORM (1 << 5)
static const EnumPropertyItem scale_fit_methods[] = {
{SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"},

View File

@ -1522,10 +1522,10 @@ static void *sequencer_OCIO_transform_ibuf(const bContext *C,
ImBuf *ibuf,
bool *r_glsl_used,
eGPUTextureFormat *r_format,
eGPUDataFormat *r_data)
eGPUDataFormat *r_data,
void **r_buffer_cache_handle)
{
void *display_buffer;
void *cache_handle = NULL;
bool force_fallback = false;
*r_glsl_used = false;
force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL);
@ -1578,13 +1578,10 @@ static void *sequencer_OCIO_transform_ibuf(const bContext *C,
/* There is data to be displayed, but GLSL is not initialized
* properly, in this case we fallback to CPU-based display transform. */
if ((ibuf->rect || ibuf->rect_float) && !*r_glsl_used) {
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, &cache_handle);
display_buffer = IMB_display_buffer_acquire_ctx(C, ibuf, r_buffer_cache_handle);
*r_format = GPU_RGBA8;
*r_data = GPU_DATA_UBYTE;
}
if (cache_handle) {
IMB_display_buffer_release(cache_handle);
}
return display_buffer;
}
@ -1658,6 +1655,7 @@ static void sequencer_draw_display_buffer(const bContext *C,
bool draw_backdrop)
{
void *display_buffer;
void *buffer_cache_handle = NULL;
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) {
GPU_blend(GPU_BLEND_ALPHA);
@ -1685,7 +1683,8 @@ static void sequencer_draw_display_buffer(const bContext *C,
data = GPU_DATA_UBYTE;
}
else {
display_buffer = sequencer_OCIO_transform_ibuf(C, ibuf, &glsl_used, &format, &data);
display_buffer = sequencer_OCIO_transform_ibuf(
C, ibuf, &glsl_used, &format, &data, &buffer_cache_handle);
}
if (draw_backdrop) {
@ -1745,6 +1744,10 @@ static void sequencer_draw_display_buffer(const bContext *C,
IMB_colormanagement_finish_glsl_draw();
}
if (buffer_cache_handle) {
IMB_display_buffer_release(buffer_cache_handle);
}
if (sseq->mainb == SEQ_DRAW_IMG_IMBUF && sseq->flag & SEQ_USE_ALPHA) {
GPU_blend(GPU_BLEND_NONE);
}

View File

@ -1608,7 +1608,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (; seq; seq = seq->next) {
SEQ_iterator_recursive_apply(seq, apply_unique_name_fn, scene);
SEQ_recursive_apply(seq, apply_unique_name_fn, scene);
}
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@ -2465,7 +2465,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
for (iseq = iseq_first; iseq; iseq = iseq->next) {
/* Make sure, that pasted strips have unique names. */
SEQ_iterator_recursive_apply(iseq, apply_unique_name_fn, scene);
SEQ_recursive_apply(iseq, apply_unique_name_fn, scene);
/* Translate after name has been changed, otherwise this will affect animdata of original
* strip. */
SEQ_transform_translate_sequence(scene, iseq, ofs);

View File

@ -26,7 +26,6 @@
#include <string.h>
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@ -1622,64 +1621,78 @@ static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
return changed;
}
static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
/* Query all effect strips that are directly or indirectly connected to seq_reference. */
static void query_strip_effect_chain(Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
bool changed = false;
const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq));
int startdisp = actseq->startdisp;
int enddisp = actseq->enddisp;
int machine = actseq->machine;
SeqIterator iter;
LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
seq->tmp = NULL;
if (!SEQ_collection_append_strip(seq_reference, collection)) {
return; /* Strip is already in set, so all effects connected to it are as well. */
}
actseq->tmp = POINTER_FROM_INT(true);
Sequence *seq = NULL;
for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) {
seq = iter.seq;
/* Ignore all seqs already selected. */
/* Ignore all seqs not sharing some time with active one. */
/* Ignore all seqs of incompatible types (audio vs video). */
if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
(seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) ||
(is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) {
continue;
/* Find all strips that seq_reference is connected to. */
if (seq_reference->type & SEQ_TYPE_EFFECT) {
if (seq_reference->seq1) {
query_strip_effect_chain(seq_reference->seq1, seqbase, collection);
}
/* If the seq is an effect one, we need extra checking. */
if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
(seq->seq3 && seq->seq3->tmp))) {
if (startdisp > seq->startdisp) {
startdisp = seq->startdisp;
}
if (enddisp < seq->enddisp) {
enddisp = seq->enddisp;
}
if (machine < seq->machine) {
machine = seq->machine;
}
seq->tmp = POINTER_FROM_INT(true);
seq->flag |= SELECT;
changed = true;
/* Unfortunately, we must restart checks from the beginning. */
SEQ_iterator_end(&iter);
SEQ_iterator_begin(ed, &iter, true);
if (seq_reference->seq2) {
query_strip_effect_chain(seq_reference->seq2, seqbase, collection);
}
/* Video strips below active one, or any strip for audio (order doesn't matter here). */
else if (seq->machine < machine || is_audio) {
seq->flag |= SELECT;
changed = true;
if (seq_reference->seq3) {
query_strip_effect_chain(seq_reference->seq3, seqbase, collection);
}
}
SEQ_iterator_end(&iter);
/* Find all strips connected to seq_reference. */
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
if (seq_test->seq1 == seq_reference || seq_test->seq2 == seq_reference ||
seq_test->seq3 == seq_reference) {
query_strip_effect_chain(seq_test, seqbase, collection);
}
}
}
/* Query strips that are in lower channel and intersect in time with seq_reference. */
static void query_lower_channel_strips(Sequence *seq_reference,
ListBase *seqbase,
SeqCollection *collection)
{
LISTBASE_FOREACH (Sequence *, seq_test, seqbase) {
if (seq_test->machine > seq_reference->machine) {
continue; /* Not lower channel. */
}
if (seq_test->enddisp <= seq_reference->startdisp ||
seq_test->startdisp >= seq_reference->enddisp) {
continue; /* Not intersecting in time. */
}
SEQ_collection_append_strip(seq_test, collection);
}
}
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
static bool select_grouped_effect_link(Editing *ed,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
ListBase *seqbase = SEQ_active_seqbase_get(ed);
/* Get collection of strips. */
SeqCollection *collection = SEQ_query_selected_strips(seqbase);
const int selected_strip_count = BLI_gset_len(collection->set);
SEQ_collection_expand(seqbase, collection, query_lower_channel_strips);
SEQ_collection_expand(seqbase, collection, query_strip_effect_chain);
/* Check if other strips will be affected. */
const bool changed = BLI_gset_len(collection->set) > selected_strip_count;
/* Actual logic. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
seq->flag |= SELECT;
}
SEQ_collection_free(collection);
return changed;
}

View File

@ -1288,6 +1288,11 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y
name_array[name_array_len++] = IFACE_(" (Local)");
}
/* Indicate that clipping region is enabled. */
if (rv3d->rflag & RV3D_CLIPPING) {
name_array[name_array_len++] = IFACE_(" (Clipped)");
}
if (name_array_len > 1) {
BLI_string_join_array(tmpstr, sizeof(tmpstr), name_array, name_array_len);
name = tmpstr;

View File

@ -135,6 +135,9 @@ class GVArray {
this->get_internal_single(r_value);
}
void materialize(void *dst) const;
void materialize(const IndexMask mask, void *dst) const;
void materialize_to_uninitialized(void *dst) const;
void materialize_to_uninitialized(const IndexMask mask, void *dst) const;
@ -162,6 +165,7 @@ class GVArray {
virtual bool is_single_impl() const;
virtual void get_internal_single_impl(void *UNUSED(r_value)) const;
virtual void materialize_impl(const IndexMask mask, void *dst) const;
virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const;
virtual const void *try_get_internal_varray_impl() const;
@ -370,6 +374,11 @@ template<typename T> class GVArray_For_VArray : public GVArray {
*(T *)r_value = varray_->get_internal_single();
}
void materialize_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
@ -545,6 +554,16 @@ template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableAr
varray_->set(index, std::move(value_));
}
void materialize_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override
{
varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size()));
}
const void *try_get_internal_varray_impl() const override
{
return (const VArray<T> *)varray_;

View File

@ -53,6 +53,24 @@ class GVArray_For_ShallowCopy : public GVArray {
* GVArray.
*/
void GVArray::materialize(void *dst) const
{
this->materialize(IndexMask(size_), dst);
}
void GVArray::materialize(const IndexMask mask, void *dst) const
{
this->materialize_impl(mask, dst);
}
void GVArray::materialize_impl(const IndexMask mask, void *dst) const
{
for (const int64_t i : mask) {
void *elem_dst = POINTER_OFFSET(dst, type_->size() * i);
this->get(i, elem_dst);
}
}
void GVArray::materialize_to_uninitialized(void *dst) const
{
this->materialize_to_uninitialized(IndexMask(size_), dst);

View File

@ -24,7 +24,7 @@
* Use these instead of glGenBuffers & its friends
* - alloc must be called from a thread that is bound
* to the context that will be used for drawing with
* this vao.
* this VAO.
* - free can be called from any thread
*/

View File

@ -543,7 +543,7 @@ bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc,
&precalc->dims.zmax);
if (isinf(precalc->dims.zmax)) {
/* We cannot retrieve the actual value of the clip_end.
* Use `FLT_MAX` to avoid nans. */
* Use `FLT_MAX` to avoid NAN's. */
precalc->dims.zmax = FLT_MAX;
}
for (int i = 0; i < 4; i++) {

View File

@ -286,9 +286,10 @@ static void detect_workarounds()
strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") ||
strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") ||
strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") ||
strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") ||
strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") ||
strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) {
strstr(renderer, " RX 580X ") || strstr(renderer, " RX 590 ") ||
strstr(renderer, " RX550/550 ") || strstr(renderer, " (TM) 520 ") ||
strstr(renderer, " (TM) 530 ") || strstr(renderer, " R5 ") || strstr(renderer, " R7 ") ||
strstr(renderer, " R9 ")) {
GCaps.use_hq_normals_workaround = true;
}
}

View File

@ -44,7 +44,7 @@
using namespace blender::gpu;
/* -------------------------------------------------------------------- */
/** \name Vao cache
/** \name VAO Cache
*
* Each #GLBatch has a small cache of VAO objects that are used to avoid VAO reconfiguration.
* TODO(fclem): Could be revisited to avoid so much cross references.

View File

@ -43,7 +43,7 @@ class GLShaderInterface;
#define GPU_VAO_STATIC_LEN 3
/* Vao management: remembers all geometry state (vertex attribute bindings & element buffer)
/* VAO management: remembers all geometry state (vertex attribute bindings & element buffer)
* for each shader interface. Start with a static number of vaos and fallback to dynamic count
* if necessary. Once a batch goes dynamic it does not go back. */
class GLVaoCache {

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