Geometry Nodes: add simulation support #104924

Closed
Hans Goudey wants to merge 211 commits from geometry-nodes-simulation into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
36 changed files with 857 additions and 525 deletions
Showing only changes of commit efc2345c70 - Show all commits

View File

@ -383,7 +383,8 @@ bool BKE_image_is_filename_tokenized(char *filepath);
* Ensures that `filename` contains a UDIM token if we find a supported format pattern.
* \note This must only be the name component (without slashes).
*/
void BKE_image_ensure_tile_token(char *filename);
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy);
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy);
/**
* When provided with an absolute virtual `filepath`, check to see if at least

View File

@ -531,7 +531,7 @@ static bool absolute_convert_foreach_path_cb(BPathForeachPathData *bpath_data,
return false; /* Already absolute. */
}
BLI_strncpy(path_dst, path_src, FILENAME_MAX);
BLI_strncpy(path_dst, path_src, FILE_MAX);
BLI_path_abs(path_dst, data->basedir);
if (BLI_path_is_rel(path_dst) == false) {
data->count_changed++;

View File

@ -3112,8 +3112,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
}
else {
/* When changing to UDIM, attempt to tokenize the filepath. */
char *filename = (char *)BLI_path_basename(ima->filepath);
BKE_image_ensure_tile_token(filename);
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
}
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
@ -3304,7 +3303,7 @@ bool BKE_image_get_tile_info(char *filepath, ListBase *tiles, int *r_tile_start,
BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename));
if (!BKE_image_is_filename_tokenized(filename)) {
BKE_image_ensure_tile_token(filename);
BKE_image_ensure_tile_token_filename_only(filename, sizeof(filename));
}
eUDIM_TILE_FORMAT tile_format;
@ -3494,7 +3493,7 @@ bool BKE_image_is_filename_tokenized(char *filepath)
return strstr(filename, "<UDIM>") != nullptr || strstr(filename, "<UVTILE>") != nullptr;
}
void BKE_image_ensure_tile_token(char *filename)
void BKE_image_ensure_tile_token_filename_only(char *filename, size_t filename_maxncpy)
{
BLI_assert_msg(BLI_path_slash_find(filename) == nullptr,
"Only the file-name component should be used!");
@ -3511,18 +3510,24 @@ void BKE_image_ensure_tile_token(char *filename)
* 1000 through 2000 to provide better detection. */
std::regex pattern(R"((.*[._-])([12]\d{3})([._-].*))");
if (std::regex_search(path, match, pattern)) {
BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), FILE_MAX);
BLI_strncpy(filename, match.format("$1<UDIM>$3").c_str(), filename_maxncpy);
return;
}
/* General `u##_v###` `uvtile` pattern. */
pattern = std::regex(R"((.*)(u\d{1,2}_v\d{1,3})(\D.*))");
if (std::regex_search(path, match, pattern)) {
BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), FILE_MAX);
BLI_strncpy(filename, match.format("$1<UVTILE>$3").c_str(), filename_maxncpy);
return;
}
}
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
{
char *filename = (char *)BLI_path_basename(filepath);
BKE_image_ensure_tile_token_filename_only(filename, filepath_maxncpy - (filename - filepath));
}
bool BKE_image_tile_filepath_exists(const char *filepath)
{
BLI_assert(!BLI_path_is_rel(filepath));
@ -5136,8 +5141,8 @@ void BKE_image_user_file_path_ex(const Main *bmain,
int index;
if (ima->source == IMA_SRC_SEQUENCE) {
index = iuser ? iuser->framenr : ima->lastframe;
BLI_path_sequence_decode(filepath, head, tail, &numlen);
BLI_path_sequence_encode(filepath, head, tail, numlen, index);
BLI_path_sequence_decode(filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
BLI_path_sequence_encode(filepath, FILE_MAX, head, tail, numlen, index);
}
else if (resolve_udim) {
index = image_get_tile_number_from_iuser(ima, iuser);
@ -5277,7 +5282,7 @@ float *BKE_image_get_float_pixels_for_frame(struct Image *image, int frame, int
int BKE_image_sequence_guess_offset(Image *image)
{
return BLI_path_sequence_decode(image->filepath, nullptr, nullptr, nullptr);
return BLI_path_sequence_decode(image->filepath, nullptr, 0, nullptr, 0, nullptr);
}
bool BKE_image_has_anim(Image *ima)

View File

@ -18,7 +18,7 @@ TEST(udim, image_ensure_tile_token)
char result[FILE_MAX];
BLI_strncpy(result, original, sizeof(result));
BKE_image_ensure_tile_token(result);
BKE_image_ensure_tile_token_filename_only(result, sizeof(result));
EXPECT_STREQ(result, expected);
};

View File

@ -332,6 +332,14 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
result_corner_edges[i] += src_edges_num;
}
if (!mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
const blender::BoundedBitSpan src = mesh->runtime->subsurf_optimal_display_edges;
result->runtime->subsurf_optimal_display_edges.resize(result->totedge);
blender::MutableBoundedBitSpan dst = result->runtime->subsurf_optimal_display_edges;
dst.slice({0, src.size()}).copy_from(src);
dst.slice({src.size(), src.size()}).copy_from(src);
}
/* handle uvs,
* let tessface recalc handle updating the MTFace data */
if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V) ||

View File

@ -481,15 +481,19 @@ static void get_sequence_filepath(const MovieClip *clip, const int framenr, char
int offset;
BLI_strncpy(filepath, clip->filepath, sizeof(clip->filepath));
BLI_path_sequence_decode(filepath, head, tail, &numlen);
BLI_path_sequence_decode(filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
/* Movie-clips always points to first image from sequence, auto-guess offset for now.
* Could be something smarter in the future. */
offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
if (numlen) {
BLI_path_sequence_encode(
filepath, head, tail, numlen, offset + framenr - clip->start_frame + clip->frame_offset);
BLI_path_sequence_encode(filepath,
sizeof(filepath),
head,
tail,
numlen,
offset + framenr - clip->start_frame + clip->frame_offset);
}
else {
BLI_strncpy(filepath, clip->filepath, sizeof(clip->filepath));
@ -702,7 +706,7 @@ static void movieclip_calc_length(MovieClip *clip)
ushort numlen;
char filepath[FILE_MAX], head[FILE_MAX], tail[FILE_MAX];
BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
BLI_path_sequence_decode(clip->filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
if (numlen == 0) {
/* there's no number group in file name, assume it's single framed sequence */
@ -790,7 +794,7 @@ static int user_frame_to_cache_frame(MovieClip *clip, int framenr)
ushort numlen;
char head[FILE_MAX], tail[FILE_MAX];
BLI_path_sequence_decode(clip->filepath, head, tail, &numlen);
BLI_path_sequence_decode(clip->filepath, head, sizeof(head), tail, sizeof(tail), &numlen);
/* see comment in get_sequence_filepath */
clip->cache->sequence_offset = sequence_guess_offset(clip->filepath, strlen(head), numlen);
@ -933,7 +937,7 @@ static bool put_imbuf_cache(
clip->cache->sequence_offset = -1;
if (clip->source == MCLIP_SRC_SEQUENCE) {
ushort numlen;
BLI_path_sequence_decode(clip->filepath, NULL, NULL, &numlen);
BLI_path_sequence_decode(clip->filepath, NULL, 0, NULL, 0, &numlen);
clip->cache->is_still_sequence = (numlen == 0);
}
}

View File

@ -654,8 +654,7 @@ int BKE_packedfile_unpack_image(Main *bmain,
BLI_strncpy(ima->filepath, new_file_path, sizeof(imapf->filepath));
if (ima->source == IMA_SRC_TILED) {
/* Ensure that the Image filepath is kept in a tokenized format. */
char *filename = (char *)BLI_path_basename(ima->filepath);
BKE_image_ensure_tile_token(filename);
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
}
}
MEM_freeN(new_file_path);

View File

@ -1301,7 +1301,7 @@ static int ptcache_frame_from_filename(const char *filename, const char *ext)
#define MAX_PTCACHE_PATH FILE_MAX
#define MAX_PTCACHE_FILE (FILE_MAX * 2)
static int ptcache_path(PTCacheID *pid, char *dirname)
static int ptcache_path(PTCacheID *pid, char dirname[MAX_PTCACHE_PATH])
{
const char *blendfile_path = BKE_main_blendfile_path_from_global();
Library *lib = (pid->owner_id) ? pid->owner_id->lib : NULL;
@ -1311,13 +1311,13 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
size_t i;
if (pid->cache->flag & PTCACHE_EXTERNAL) {
strcpy(dirname, pid->cache->path);
BLI_strncpy(dirname, pid->cache->path, MAX_PTCACHE_PATH);
if (BLI_path_is_rel(dirname)) {
BLI_path_abs(dirname, blendfilename);
}
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
}
if ((blendfile_path[0] != '\0') || lib) {
char file[MAX_PTCACHE_PATH]; /* we don't want the dir, only the file */
@ -1334,18 +1334,18 @@ static int ptcache_path(PTCacheID *pid, char *dirname)
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "//" PTCACHE_PATH "%s", file);
BLI_path_abs(dirname, blendfilename);
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
}
/* use the temp path. this is weak but better than not using point cache at all */
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
BLI_snprintf(dirname, MAX_PTCACHE_PATH, "%s" PTCACHE_PATH, BKE_tempdir_session());
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_FILE); /* new strlen() */
return BLI_path_slash_ensure(dirname, MAX_PTCACHE_PATH); /* new strlen() */
}
static size_t ptcache_filepath_ext_append(PTCacheID *pid,
char *filepath,
char filepath[MAX_PTCACHE_FILE],
const size_t filepath_len,
const bool use_frame_number,
const int cfra)
@ -1396,8 +1396,11 @@ static size_t ptcache_filepath_ext_append(PTCacheID *pid,
return len;
}
static int ptcache_filepath(
PTCacheID *pid, char *filepath, int cfra, const bool do_path, const bool do_ext)
static int ptcache_filepath(PTCacheID *pid,
char filepath[MAX_PTCACHE_FILE],
int cfra,
const bool do_path,
const bool do_ext)
{
int len = 0;
char *idname;
@ -2591,7 +2594,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, uint cfra)
char path[MAX_PTCACHE_PATH];
char filepath[MAX_PTCACHE_FILE];
char path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
char ext[MAX_PTCACHE_FILE];
if (!pid || !pid->cache || pid->cache->flag & PTCACHE_BAKED) {
return;
@ -2818,7 +2821,7 @@ void BKE_ptcache_id_time(
struct dirent *de;
char path[MAX_PTCACHE_PATH];
char filepath[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
char ext[MAX_PTCACHE_FILE];
uint len; /* store the length of the string */
ptcache_path(pid, path);
@ -3490,7 +3493,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
char old_filepath[MAX_PTCACHE_FILE];
char new_path_full[MAX_PTCACHE_FILE];
char old_path_full[MAX_PTCACHE_FILE];
char ext[MAX_PTCACHE_PATH];
char ext[MAX_PTCACHE_FILE];
/* If both names are the same, there is nothing to do. */
if (STREQ(name_src, name_dst)) {

View File

@ -2,6 +2,8 @@
#pragma once
#include <optional>
#include "BLI_bit_ref.hh"
#include "BLI_index_range.hh"
#include "BLI_math_bits.h"
@ -129,6 +131,72 @@ class BitSpan {
}
};
/**
* Checks if the span fullfills the requirements for a bounded span. Bounded spans can often be
* processed more efficiently, because fewer cases have to be considered when aligning multiple
* such spans.
*
* See comments in the function for the exact requirements.
*/
inline bool is_bounded_span(const BitSpan span)
{
const int64_t offset = span.bit_range().start();
const int64_t size = span.size();
if (offset >= BitsPerInt) {
/* The data pointer must point at the first int already. If the offset is a multiple of
* #BitsPerInt, the bit span could theoretically become bounded as well if the data pointer is
* adjusted. But that is not handled here. */
return false;
}
if (size < BitsPerInt) {
/** Don't allow small sized spans to cross `BitInt` boundaries. */
return offset + size <= 64;
}
if (offset != 0) {
/* Start of larger spans must be aligned to `BitInt` boundaries. */
return false;
}
return true;
}
/**
* Same as #BitSpan but fullfills the requirements mentioned on #is_bounded_span.
*/
class BoundedBitSpan : public BitSpan {
public:
BoundedBitSpan() = default;
BoundedBitSpan(const BitInt *data, const int64_t size_in_bits) : BitSpan(data, size_in_bits)
{
BLI_assert(is_bounded_span(*this));
}
BoundedBitSpan(const BitInt *data, const IndexRange bit_range) : BitSpan(data, bit_range)
{
BLI_assert(is_bounded_span(*this));
}
explicit BoundedBitSpan(const BitSpan other) : BitSpan(other)
{
BLI_assert(is_bounded_span(*this));
}
int64_t offset() const
{
return bit_range_.start();
}
int64_t full_ints_num() const
{
return bit_range_.size() >> BitToIntIndexShift;
}
int64_t final_bits_num() const
{
return bit_range_.size() & BitIndexMask;
}
};
/** Same as #BitSpan, but also allows modifying the referenced bits. */
class MutableBitSpan {
protected:
@ -200,6 +268,9 @@ class MutableBitSpan {
/** Sets all referenced bits to 0. */
void reset_all();
void copy_from(const BitSpan other);
void copy_from(const BoundedBitSpan other);
/** Sets all referenced bits to either 0 or 1. */
void set_all(const bool value)
{
@ -218,71 +289,6 @@ class MutableBitSpan {
}
};
/**
* Checks if the span fullfills the requirements for a bounded span. Bounded spans can often be
* processed more efficiently, because fewer cases have to be considered when aligning multiple
* such spans.
*
* See comments in the function for the exact requirements.
*/
inline bool is_bounded_span(const BitSpan data)
{
const int64_t offset = data.bit_range().start();
const int64_t size = data.size();
if (offset >= BitsPerInt) {
/* The data pointer must point at the first int already. In general it's ok not to enforce
* this, because it might just add overhead when e.g. slicing a span. */
return false;
}
if (size < BitsPerInt) {
/** Don't allow small sized spans to cross `BitInt` boundaries. */
return offset + size <= 64;
}
if (offset != 0) {
/* Start of larger spans must be aligned to `BitInt` boundaries. */
return false;
}
return true;
}
/**
* Same as #BitSpan but fullfills the requirements mentioned on #is_bounded_span.
*/
class BoundedBitSpan : public BitSpan {
public:
BoundedBitSpan() = default;
BoundedBitSpan(const BitInt *data, const int64_t size_in_bits) : BitSpan(data, size_in_bits)
{
BLI_assert(is_bounded_span(*this));
}
BoundedBitSpan(const BitInt *data, const IndexRange bit_range) : BitSpan(data, bit_range)
{
BLI_assert(is_bounded_span(*this));
}
explicit BoundedBitSpan(const BitSpan other) : BitSpan(other)
{
BLI_assert(is_bounded_span(*this));
}
int64_t offset() const
{
return bit_range_.start();
}
int64_t full_ints_num() const
{
return bit_range_.size() >> BitToIntIndexShift;
}
int64_t final_bits_num() const
{
return bit_range_.size() & BitIndexMask;
}
};
/**
* Same as #MutableBitSpan but fullfills the requirements mentioned on #is_bounded_span.
*/
@ -324,12 +330,26 @@ class MutableBoundedBitSpan : public MutableBitSpan {
{
return bit_range_.size() & BitIndexMask;
}
void copy_from(const BitSpan other);
void copy_from(const BoundedBitSpan other);
};
inline std::optional<BoundedBitSpan> try_get_bounded_span(const BitSpan span)
{
if (is_bounded_span(span)) {
return BoundedBitSpan(span);
}
if (span.bit_range().start() % BitsPerInt == 0) {
return BoundedBitSpan(span.data() + (span.bit_range().start() >> BitToIntIndexShift),
span.size());
}
return std::nullopt;
}
/**
* This is overloaded in BLI_bit_vector.hh. The purpose is to make passing #BitVector into bit span
* operations more simpler and efficient (interpreting it as `BoundedBitSpan` instead of just
* `BitSpan`).
* Overloaded in BLI_bit_vector.hh. The purpose is to make passing #BitVector into bit span
* operations more efficient (interpreting it as `BoundedBitSpan` instead of just `BitSpan`).
*/
template<typename T> inline T to_best_bit_span(const T &data)
{

View File

@ -7,6 +7,7 @@
namespace blender::bits {
namespace detail {
/**
* Evaluates the expression on one or more bit spans and stores the result in the first.
*
@ -129,6 +130,7 @@ inline void foreach_1_index_expr(ExprFn &&expr,
BitInt tmp = expr(first_data[int_i], args.data()[int_i]...);
const int64_t offset = int_i << BitToIntIndexShift;
while (tmp != 0) {
static_assert(std::is_same_v<BitInt, uint64_t>);
const int index = bitscan_forward_uint64(tmp);
handle(index + offset);
tmp &= ~mask_single_bit(index);
@ -141,6 +143,7 @@ inline void foreach_1_index_expr(ExprFn &&expr,
mask_first_n_bits(final_bits);
const int64_t offset = full_ints_num << BitToIntIndexShift;
while (tmp != 0) {
static_assert(std::is_same_v<BitInt, uint64_t>);
const int index = bitscan_forward_uint64(tmp);
handle(index + offset);
tmp &= ~mask_single_bit(index);
@ -191,6 +194,13 @@ inline void inplace_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
mix_into_first_expr([](const auto... x) { return (x | ...); }, first_arg, args...);
}
template<typename FirstBitSpanT, typename... BitSpanT>
inline void copy_from_or(FirstBitSpanT &first_arg, const BitSpanT &...args)
{
mix_into_first_expr(
[](auto /*first*/, auto... rest) { return (rest | ...); }, first_arg, args...);
}
template<typename FirstBitSpanT, typename... BitSpanT>
inline void inplace_and(FirstBitSpanT &first_arg, const BitSpanT &...args)
{

View File

@ -311,14 +311,20 @@ bool BLI_path_filename_ensure(char *filepath, size_t maxlen, const char *filenam
*/
int BLI_path_sequence_decode(const char *string,
char *head,
size_t head_maxncpy,
char *tail,
size_t tail_maxncpy,
unsigned short *r_digits_len);
/**
* Returns in area pointed to by string a string of the form `<head><pic><tail>`,
* where pic is formatted as `numlen` digits with leading zeroes.
*/
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, unsigned short numlen, int pic);
void BLI_path_sequence_encode(char *string,
size_t string_maxncpy,
const char *head,
const char *tail,
unsigned short numlen,
int pic);
/**
* Remove redundant characters from \a path.

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_bit_span.hh"
#include "BLI_bit_span_ops.hh"
namespace blender::bits {
@ -54,6 +55,30 @@ void MutableBitSpan::reset_all()
}
}
void MutableBitSpan::copy_from(const BitSpan other)
{
BLI_assert(this->size() == other.size());
copy_from_or(*this, other);
}
void MutableBitSpan::copy_from(const BoundedBitSpan other)
{
BLI_assert(this->size() == other.size());
copy_from_or(*this, other);
}
void MutableBoundedBitSpan::copy_from(const BitSpan other)
{
BLI_assert(this->size() == other.size());
copy_from_or(*this, other);
}
void MutableBoundedBitSpan::copy_from(const BoundedBitSpan other)
{
BLI_assert(this->size() == other.size());
copy_from_or(*this, other);
}
std::ostream &operator<<(std::ostream &stream, const BitSpan &span)
{
stream << "(Size: " << span.size() << ", ";

View File

@ -47,8 +47,22 @@ static bool BLI_path_is_abs_win32(const char *name);
// #define DEBUG_STRSIZE
int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort *r_digits_len)
int BLI_path_sequence_decode(const char *string,
char *head,
const size_t head_maxncpy,
char *tail,
const size_t tail_maxncpy,
ushort *r_digits_len)
{
#ifdef DEBUG_STRSIZE
if (head) {
memset(head, 0xff, sizeof(*head) * head_maxncpy);
}
if (tail) {
memset(tail, 0xff, sizeof(*tail) * tail_maxncpy);
}
#endif
uint nums = 0, nume = 0;
int i;
bool found_digit = false;
@ -82,8 +96,7 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
strcpy(tail, &string[nume + 1]);
}
if (head) {
strcpy(head, string);
head[nums] = 0;
BLI_strncpy(head, string, MIN2(head_maxncpy, nums + 1));
}
if (r_digits_len) {
*r_digits_len = nume - nums + 1;
@ -93,7 +106,7 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
}
if (tail) {
strcpy(tail, string + name_end);
BLI_strncpy(tail, string + name_end, tail_maxncpy);
}
if (head) {
/* Name_end points to last character of head,
@ -106,10 +119,17 @@ int BLI_path_sequence_decode(const char *string, char *head, char *tail, ushort
return 0;
}
void BLI_path_sequence_encode(
char *string, const char *head, const char *tail, ushort numlen, int pic)
void BLI_path_sequence_encode(char *string,
const size_t string_maxncpy,
const char *head,
const char *tail,
ushort numlen,
int pic)
{
BLI_sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
#ifdef DEBUG_STRSIZE
memset(string, 0xff, sizeof(*string) * string_maxncpy);
#endif
BLI_snprintf(string, string_maxncpy, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
}
void BLI_path_normalize(char *path)

View File

@ -3,6 +3,9 @@
#include <array>
#include "BLI_bit_span.hh"
#include "BLI_bit_span_ops.hh"
#include "BLI_timeit.hh"
#include "BLI_vector.hh"
#include "testing/testing.h"
@ -159,14 +162,88 @@ TEST(bit_span, IsBounded)
EXPECT_TRUE(is_bounded_span(BitSpan(data.data(), IndexRange(1, 3))));
EXPECT_TRUE(is_bounded_span(BitSpan(data.data(), IndexRange(10, 20))));
EXPECT_TRUE(is_bounded_span(BitSpan(data.data(), IndexRange(63, 1))));
EXPECT_TRUE(is_bounded_span(BitSpan(data.data(), IndexRange(64, 0))));
EXPECT_TRUE(is_bounded_span(BitSpan(data.data(), IndexRange(10, 54))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(1, 64))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(10, 64))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(10, 200))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(60, 5))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(64, 0))));
EXPECT_FALSE(is_bounded_span(BitSpan(data.data(), IndexRange(70, 5))));
}
TEST(bit_span, CopyFrom)
{
std::array<uint64_t, 30> src_data;
uint64_t i = 0;
for (uint64_t &value : src_data) {
value = i;
i += 234589766883;
}
const BitSpan src(src_data.data(), src_data.size() * BitsPerInt);
std::array<uint64_t, 4> dst_data;
dst_data.fill(-1);
MutableBitSpan dst(dst_data.data(), 100);
dst.copy_from(src.slice({401, 100}));
for (const int i : dst.index_range()) {
EXPECT_TRUE(dst[i].test() == src[401 + i].test());
}
}
TEST(bit_span, InPlaceOr)
{
std::array<uint64_t, 100> data_1;
MutableBitSpan span_1(data_1.data(), data_1.size() * BitsPerInt);
for (const int i : span_1.index_range()) {
span_1[i].set(i % 2 == 0);
}
std::array<uint64_t, 100> data_2;
MutableBitSpan span_2(data_2.data(), data_2.size() * BitsPerInt);
for (const int i : span_2.index_range()) {
span_2[i].set(i % 2 != 0);
}
span_1 |= span_2;
for (const int i : span_1.index_range()) {
EXPECT_TRUE(span_1[i].test());
}
}
TEST(bit_span, InPlaceAnd)
{
std::array<uint64_t, 100> data_1;
MutableBitSpan span_1(data_1.data(), data_1.size() * BitsPerInt);
for (const int i : span_1.index_range()) {
span_1[i].set(i % 2 == 0);
}
std::array<uint64_t, 100> data_2;
MutableBitSpan span_2(data_2.data(), data_2.size() * BitsPerInt);
for (const int i : span_2.index_range()) {
span_2[i].set(i % 2 != 0);
}
span_1 &= span_2;
for (const int i : span_1.index_range()) {
EXPECT_FALSE(span_1[i].test());
}
}
TEST(bit_span, ForEach1)
{
std::array<uint64_t, 2> data{};
MutableBitSpan span(data.data(), data.size() * BitsPerInt);
for (const int i : {1, 28, 37, 86}) {
span[i].set();
}
Vector<int> indices_test;
foreach_1_index(span.slice({4, span.size() - 4}), [&](const int i) { indices_test.append(i); });
EXPECT_EQ(indices_test.as_span(), Span({24, 33, 82}));
}
} // namespace blender::bits::tests

View File

@ -1059,7 +1059,8 @@ TEST(path_util, FrameGet)
char head[FILE_MAX]; \
char tail[FILE_MAX]; \
ushort numdigits = 0; \
const int result = BLI_path_sequence_decode(path, head, tail, &numdigits); \
const int result = BLI_path_sequence_decode( \
path, head, sizeof(head), tail, sizeof(tail), &numdigits); \
EXPECT_EQ(result, expect_result); \
EXPECT_STREQ(head, expect_head); \
EXPECT_STREQ(tail, expect_tail); \

View File

@ -1047,10 +1047,12 @@ class StringEscape : public testing::Test {
void testEscapeWords(const CompareWordsArray &items)
{
size_t dst_test_len;
char dst_test[64];
char dst_test[64]; /* Must be big enough for all input. */
for (const auto &item : items) {
/* Validate the static size is big enough (test the test it's self). */
EXPECT_LT((strlen(item[0]) * 2) + 1, sizeof(dst_test));
/* Escape the string. */
dst_test_len = BLI_str_escape(dst_test, item[0], SIZE_MAX);
dst_test_len = BLI_str_escape(dst_test, item[0], sizeof(dst_test));
EXPECT_STREQ(dst_test, item[1]);
EXPECT_EQ(dst_test_len, strlen(dst_test));
/* Escape back. */

View File

@ -428,10 +428,9 @@ static void do_version_layers_to_collections(Main *bmain, Scene *scene)
if (base->lay & (1 << layer)) {
/* Create collections when needed only. */
if (collections[layer] == NULL) {
char name[MAX_NAME];
char name[MAX_ID_NAME - 2];
BLI_snprintf(
name, sizeof(collection_master->id.name), DATA_("Collection %d"), layer + 1);
BLI_snprintf(name, sizeof(name), DATA_("Collection %d"), layer + 1);
Collection *collection = BKE_collection_add(bmain, collection_master, name);
collection->id.lib = scene->id.lib;

View File

@ -1263,8 +1263,7 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain)
/* Ensure tiled image sources contain a UDIM token. */
LISTBASE_FOREACH (Image *, ima, &bmain->images) {
if (ima->source == IMA_SRC_TILED) {
char *filename = (char *)BLI_path_basename(ima->filepath);
BKE_image_ensure_tile_token(filename);
BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
}
}
}

View File

@ -2975,7 +2975,7 @@ static void filenum_newname(char *name, size_t name_size, int add)
int pic;
ushort digits;
pic = BLI_path_sequence_decode(name, head, tail, &digits);
pic = BLI_path_sequence_decode(name, head, sizeof(head), tail, sizeof(tail), &digits);
/* are we going from 100 -> 99 or from 10 -> 9 */
if (add < 0 && digits > 0) {
@ -2993,7 +2993,7 @@ static void filenum_newname(char *name, size_t name_size, int add)
if (pic < 0) {
pic = 0;
}
BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
BLI_path_sequence_encode(name_temp, sizeof(name_temp), head, tail, digits, pic);
BLI_strncpy(name, name_temp, name_size);
}

View File

@ -1586,8 +1586,7 @@ static int image_file_browse_exec(bContext *C, wmOperator *op)
/* If loading into a tiled texture, ensure that the filename is tokenized. */
if (ima->source == IMA_SRC_TILED) {
char *filename = (char *)BLI_path_basename(filepath);
BKE_image_ensure_tile_token(filename);
BKE_image_ensure_tile_token(filepath, sizeof(filepath));
}
PointerRNA imaptr;

View File

@ -55,7 +55,8 @@ static void image_sequence_get_frame_ranges(wmOperator *op, ListBase *ranges)
ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame");
/* use the first file in the list as base filename */
frame->framenr = BLI_path_sequence_decode(filename, head, tail, &digits);
frame->framenr = BLI_path_sequence_decode(
filename, head, sizeof(head), tail, sizeof(tail), &digits);
/* still in the same sequence */
if (do_frame_range && (range != NULL) && STREQLEN(base_head, head, FILE_MAX) &&

View File

@ -856,10 +856,12 @@ float ED_view3d_grid_scale(const Scene *scene, View3D *v3d, const char **r_grid_
}
#define STEPS_LEN 8
void ED_view3d_grid_steps(const Scene *scene,
View3D *v3d,
RegionView3D *rv3d,
float r_grid_steps[STEPS_LEN])
static void view3d_grid_steps_ex(const Scene *scene,
View3D *v3d,
RegionView3D *rv3d,
float r_grid_steps[STEPS_LEN],
void const **r_usys_pt,
int *r_len)
{
const void *usys;
int len;
@ -881,7 +883,7 @@ void ED_view3d_grid_steps(const Scene *scene,
}
for (; i < STEPS_LEN; i++) {
/* Fill last slots */
r_grid_steps[i] = 10.0f * r_grid_steps[i - 1];
r_grid_steps[i] = r_grid_steps[len - 1];
}
}
else {
@ -899,6 +901,20 @@ void ED_view3d_grid_steps(const Scene *scene,
subdiv *= v3d->gridsubdiv;
}
}
if (r_usys_pt) {
*r_usys_pt = usys;
}
if (r_len) {
*r_len = len;
}
}
void ED_view3d_grid_steps(const Scene *scene,
View3D *v3d,
RegionView3D *rv3d,
float r_grid_steps[STEPS_LEN])
{
view3d_grid_steps_ex(scene, v3d, rv3d, r_grid_steps, nullptr, nullptr);
}
float ED_view3d_grid_view_scale(Scene *scene,
@ -912,23 +928,20 @@ float ED_view3d_grid_view_scale(Scene *scene,
/* Decrease the distance between grid snap points depending on zoom. */
float dist = 12.0f / (region->sizex * rv3d->winmat[0][0]);
float grid_steps[STEPS_LEN];
ED_view3d_grid_steps(scene, v3d, rv3d, grid_steps);
/* Skip last item, in case the 'mid_dist' is greater than the largest unit. */
int i;
for (i = 0; i < ARRAY_SIZE(grid_steps) - 1; i++) {
const void *usys;
int grid_steps_len;
view3d_grid_steps_ex(scene, v3d, rv3d, grid_steps, &usys, &grid_steps_len);
int i = 0;
while (true) {
grid_scale = grid_steps[i];
if (grid_scale > dist) {
if (grid_scale > dist || i == (grid_steps_len - 1)) {
break;
}
i++;
}
if (r_grid_unit) {
const void *usys;
int len;
BKE_unit_system_get(scene->unit.system, B_UNIT_LENGTH, &usys, &len);
if (usys && i < len) {
*r_grid_unit = IFACE_(BKE_unit_display_name_get(usys, len - i - 1));
}
if (r_grid_unit && usys) {
*r_grid_unit = IFACE_(BKE_unit_display_name_get(usys, grid_steps_len - i - 1));
}
}
else {

View File

@ -43,8 +43,44 @@
#include "view3d_navigate.h" /* own include */
/* Prototypes. */
static void viewops_data_init_context(bContext *C, ViewOpsData *vod);
static void viewops_data_init_navigation(bContext *C,
const wmEvent *event,
const eV3D_OpMode nav_type,
const bool use_cursor_init,
ViewOpsData *vod);
static void viewops_data_end_navigation(bContext *C, ViewOpsData *vod);
static int viewpan_invoke_impl(ViewOpsData *vod, PointerRNA *ptr);
const char *viewops_operator_idname_get(eV3D_OpMode nav_type)
{
switch (nav_type) {
case V3D_OP_MODE_ZOOM:
return "VIEW3D_OT_zoom";
case V3D_OP_MODE_ROTATE:
return "VIEW3D_OT_rotate";
case V3D_OP_MODE_MOVE:
return "VIEW3D_OT_move";
case V3D_OP_MODE_VIEW_PAN:
return "VIEW3D_OT_view_pan";
case V3D_OP_MODE_VIEW_ROLL:
return "VIEW3D_OT_view_roll";
case V3D_OP_MODE_DOLLY:
return "VIEW3D_OT_dolly";
#ifdef WITH_INPUT_NDOF
case V3D_OP_MODE_NDOF_ORBIT:
return "VIEW3D_OT_ndof_orbit";
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
return "VIEW3D_OT_ndof_orbit_zoom";
#endif
}
BLI_assert(false);
return nullptr;
}
/* -------------------------------------------------------------------- */
/** \name Navigation Polls
/** \name Generic Operator Callback Utils
* \{ */
static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
@ -57,6 +93,128 @@ static bool view3d_navigation_poll_impl(bContext *C, const char viewlock)
return !(RV3D_LOCK_FLAGS(rv3d) & viewlock);
}
static eV3D_OpEvent view3d_navigate_event(ViewOpsData *vod, const wmEvent *event)
{
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CONFIRM:
return VIEW_CONFIRM;
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
vod->axis_snap = true;
return VIEW_APPLY;
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
vod->rv3d->persp = vod->init.persp_with_auto_persp_applied;
vod->axis_snap = false;
return VIEW_APPLY;
case VIEWROT_MODAL_SWITCH_ZOOM:
case VIEWROT_MODAL_SWITCH_MOVE:
case VIEWROT_MODAL_SWITCH_ROTATE: {
const eV3D_OpMode nav_type_new = (event->val == VIEWROT_MODAL_SWITCH_ZOOM) ?
V3D_OP_MODE_ZOOM :
(event->val == VIEWROT_MODAL_SWITCH_MOVE) ?
V3D_OP_MODE_MOVE :
V3D_OP_MODE_ROTATE;
if (nav_type_new == vod->nav_type) {
break;
}
vod->nav_type = nav_type_new;
return VIEW_APPLY;
}
}
}
else {
if (event->type == TIMER && event->customdata == vod->timer) {
/* Zoom uses timer for continuous zoom. */
return VIEW_APPLY;
}
if (event->type == MOUSEMOVE) {
return VIEW_APPLY;
}
if (event->type == vod->init.event_type && event->val == KM_RELEASE) {
return VIEW_CONFIRM;
}
if (event->type == EVT_ESCKEY && event->val == KM_PRESS) {
return VIEW_CANCEL;
}
}
return VIEW_PASS;
}
static int view3d_navigation_modal(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
{
switch (vod->nav_type) {
case V3D_OP_MODE_ZOOM:
return viewzoom_modal_impl(C, vod, event_code, xy);
case V3D_OP_MODE_ROTATE:
return viewrotate_modal_impl(C, vod, event_code, xy);
case V3D_OP_MODE_MOVE:
return viewmove_modal_impl(C, vod, event_code, xy);
default:
break;
}
return OPERATOR_CANCELLED;
}
static int view3d_navigation_invoke_generic(bContext *C,
ViewOpsData *vod,
const wmEvent *event,
PointerRNA *ptr,
const eV3D_OpMode nav_type)
{
bool use_cursor_init = false;
if (PropertyRNA *prop = RNA_struct_find_property(ptr, "use_cursor_init")) {
use_cursor_init = RNA_property_boolean_get(ptr, prop);
}
viewops_data_init_navigation(C, event, nav_type, use_cursor_init, vod);
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
switch (nav_type) {
case V3D_OP_MODE_ZOOM:
return viewzoom_invoke_impl(C, vod, event, ptr);
case V3D_OP_MODE_ROTATE:
return viewrotate_invoke_impl(vod, event);
case V3D_OP_MODE_MOVE:
return viewmove_invoke_impl(vod, event);
case V3D_OP_MODE_VIEW_PAN: {
return viewpan_invoke_impl(vod, ptr);
}
default:
break;
}
return OPERATOR_CANCELLED;
}
int view3d_navigate_invoke_impl(bContext *C,
wmOperator *op,
const wmEvent *event,
const eV3D_OpMode nav_type)
{
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
viewops_data_init_context(C, vod);
int ret = view3d_navigation_invoke_generic(C, vod, event, op->ptr, nav_type);
op->customdata = (void *)vod;
if (ret == OPERATOR_RUNNING_MODAL) {
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
viewops_data_free(C, vod);
op->customdata = nullptr;
return ret;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Generic Callbacks
* \{ */
bool view3d_location_poll(bContext *C)
{
return view3d_navigation_poll_impl(C, RV3D_LOCK_LOCATION);
@ -72,11 +230,32 @@ bool view3d_zoom_or_dolly_poll(bContext *C)
return view3d_navigation_poll_impl(C, RV3D_LOCK_ZOOM_AND_DOLLY);
}
/** \} */
int view3d_navigate_modal_fn(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod = static_cast<ViewOpsData *>(op->customdata);
/* -------------------------------------------------------------------- */
/** \name Generic Callbacks
* \{ */
const eV3D_OpMode nav_type_prev = vod->nav_type;
const eV3D_OpEvent event_code = view3d_navigate_event(vod, event);
if (nav_type_prev != vod->nav_type) {
wmOperatorType *ot_new = WM_operatortype_find(viewops_operator_idname_get(vod->nav_type),
false);
WM_operator_type_set(op, ot_new);
viewops_data_end_navigation(C, vod);
return view3d_navigation_invoke_generic(C, vod, event, op->ptr, vod->nav_type);
}
int ret = view3d_navigation_modal(C, vod, event_code, event->xy);
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
if (ret & OPERATOR_FINISHED) {
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
}
viewops_data_free(C, vod);
op->customdata = nullptr;
}
return ret;
}
void view3d_navigate_cancel_fn(bContext *C, wmOperator *op)
{
@ -312,8 +491,12 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
return is_set;
}
static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
static eViewOpsFlag viewops_flag_from_prefs(void)
{
const bool use_select = (U.uiflag & USER_ORBIT_SELECTION) != 0;
const bool use_depth = (U.uiflag & VIEWOPS_FLAG_DEPTH_NAVIGATE) != 0;
const bool use_zoom_to_mouse = (U.uiflag & USER_ZOOM_TO_MOUSEPOS) != 0;
enum eViewOpsFlag flag = VIEWOPS_FLAG_NONE;
if (use_select) {
flag |= VIEWOPS_FLAG_ORBIT_SELECT;
@ -321,20 +504,15 @@ static enum eViewOpsFlag viewops_flag_from_args(bool use_select, bool use_depth)
if (use_depth) {
flag |= VIEWOPS_FLAG_DEPTH_NAVIGATE;
}
if (use_zoom_to_mouse) {
flag |= VIEWOPS_FLAG_ZOOM_TO_MOUSE;
}
return flag;
}
enum eViewOpsFlag viewops_flag_from_prefs(void)
static void viewops_data_init_context(bContext *C, ViewOpsData *vod)
{
return viewops_flag_from_args((U.uiflag & USER_ORBIT_SELECTION) != 0,
(U.uiflag & USER_DEPTH_NAVIGATE) != 0);
}
ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOpsFlag viewops_flag)
{
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
/* Store data. */
vod->bmain = CTX_data_main(C);
vod->depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
@ -343,13 +521,46 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
vod->region = CTX_wm_region(C);
vod->v3d = static_cast<View3D *>(vod->area->spacedata.first);
vod->rv3d = static_cast<RegionView3D *>(vod->region->regiondata);
}
static void viewops_data_init_navigation(bContext *C,
const wmEvent *event,
const eV3D_OpMode nav_type,
const bool use_cursor_init,
ViewOpsData *vod)
{
Depsgraph *depsgraph = vod->depsgraph;
RegionView3D *rv3d = vod->rv3d;
eViewOpsFlag viewops_flag = viewops_flag_from_prefs();
if (use_cursor_init) {
viewops_flag |= VIEWOPS_FLAG_USE_MOUSE_INIT;
}
switch (nav_type) {
case V3D_OP_MODE_ZOOM:
case V3D_OP_MODE_MOVE:
case V3D_OP_MODE_VIEW_PAN:
case V3D_OP_MODE_DOLLY:
viewops_flag &= ~VIEWOPS_FLAG_ORBIT_SELECT;
break;
case V3D_OP_MODE_ROTATE:
viewops_flag |= VIEWOPS_FLAG_PERSP_ENSURE;
break;
#ifdef WITH_INPUT_NDOF
case V3D_OP_MODE_NDOF_ORBIT:
case V3D_OP_MODE_NDOF_ORBIT_ZOOM:
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
break;
#endif
default:
break;
}
/* Could do this more nicely. */
if ((viewops_flag & VIEWOPS_FLAG_USE_MOUSE_INIT) == 0) {
viewops_flag &= ~VIEWOPS_FLAG_DEPTH_NAVIGATE;
viewops_flag &= ~(VIEWOPS_FLAG_DEPTH_NAVIGATE | VIEWOPS_FLAG_ZOOM_TO_MOUSE);
}
/* we need the depth info before changing any viewport options */
@ -496,12 +707,27 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp
vod->reverse = -1.0f;
}
rv3d->rflag |= RV3D_NAVIGATING;
vod->nav_type = nav_type;
vod->viewops_flag = viewops_flag;
/* Default. */
vod->use_dyn_ofs_ortho_correction = false;
rv3d->rflag |= RV3D_NAVIGATING;
}
ViewOpsData *viewops_data_create(bContext *C,
const wmEvent *event,
const eV3D_OpMode nav_type,
const bool use_cursor_init)
{
ViewOpsData *vod = MEM_cnew<ViewOpsData>(__func__);
viewops_data_init_context(C, vod);
viewops_data_init_navigation(C, event, nav_type, use_cursor_init, vod);
return vod;
}
void viewops_data_free(bContext *C, ViewOpsData *vod)
static void viewops_data_end_navigation(bContext *C, ViewOpsData *vod)
{
ARegion *region;
if (vod) {
@ -512,11 +738,7 @@ void viewops_data_free(bContext *C, ViewOpsData *vod)
WM_event_remove_timer(CTX_wm_manager(C), vod->timer->win, vod->timer);
}
if (vod->init.dial) {
MEM_freeN(vod->init.dial);
}
MEM_freeN(vod);
MEM_SAFE_FREE(vod->init.dial);
}
else {
region = CTX_wm_region(C);
@ -527,6 +749,14 @@ void viewops_data_free(bContext *C, ViewOpsData *vod)
ED_region_tag_redraw(region);
}
void viewops_data_free(bContext *C, ViewOpsData *vod)
{
viewops_data_end_navigation(C, vod);
if (vod) {
MEM_freeN(vod);
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -1658,10 +1888,10 @@ static const EnumPropertyItem prop_view_pan_items[] = {
{0, nullptr, 0, nullptr, nullptr},
};
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int viewpan_invoke_impl(ViewOpsData *vod, PointerRNA *ptr)
{
int x = 0, y = 0;
int pandir = RNA_enum_get(op->ptr, "type");
int pandir = RNA_enum_get(ptr, "type");
if (pandir == V3D_VIEW_PANRIGHT) {
x = -32;
@ -1676,23 +1906,22 @@ static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
y = 25;
}
ViewOpsData *vod = viewops_data_create(
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT));
viewmove_apply(vod, vod->prev.event_xy[0] + x, vod->prev.event_xy[1] + y);
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
viewops_data_free(C, vod);
return OPERATOR_FINISHED;
}
static int viewpan_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_VIEW_PAN);
}
void VIEW3D_OT_view_pan(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Pan View Direction";
ot->description = "Pan the view in a given direction";
ot->idname = "VIEW3D_OT_view_pan";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_VIEW_PAN);
/* api callbacks */
ot->invoke = viewpan_invoke;

View File

@ -32,6 +32,19 @@ struct rcti;
struct wmEvent;
struct wmOperator;
typedef enum eV3D_OpMode {
V3D_OP_MODE_ZOOM = 0,
V3D_OP_MODE_ROTATE,
V3D_OP_MODE_MOVE,
V3D_OP_MODE_VIEW_PAN,
V3D_OP_MODE_VIEW_ROLL,
V3D_OP_MODE_DOLLY,
#ifdef WITH_INPUT_NDOF
V3D_OP_MODE_NDOF_ORBIT,
V3D_OP_MODE_NDOF_ORBIT_ZOOM,
#endif
} eV3D_OpMode;
enum eV3D_OpPropFlag {
V3D_OP_PROP_MOUSE_CO = (1 << 0),
V3D_OP_PROP_DELTA = (1 << 1),
@ -39,13 +52,13 @@ enum eV3D_OpPropFlag {
V3D_OP_PROP_USE_MOUSE_INIT = (1 << 3),
};
enum {
typedef enum eV3D_OpEvent {
VIEW_PASS = 0,
VIEW_APPLY,
VIEW_CONFIRM,
/** Only supported by some viewport operators. */
VIEW_CANCEL,
};
} eV3D_OpEvent;
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
enum {
@ -58,7 +71,7 @@ enum {
VIEWROT_MODAL_SWITCH_ROTATE = 6,
};
enum eViewOpsFlag {
typedef enum eViewOpsFlag {
VIEWOPS_FLAG_NONE = 0,
/** When enabled, rotate around the selection. */
VIEWOPS_FLAG_ORBIT_SELECT = (1 << 0),
@ -72,8 +85,10 @@ enum eViewOpsFlag {
VIEWOPS_FLAG_PERSP_ENSURE = (1 << 2),
/** When set, ignore any options that depend on initial cursor location. */
VIEWOPS_FLAG_USE_MOUSE_INIT = (1 << 3),
};
ENUM_OPERATORS(eViewOpsFlag, VIEWOPS_FLAG_USE_MOUSE_INIT);
VIEWOPS_FLAG_ZOOM_TO_MOUSE = (1 << 4),
} eViewOpsFlag;
ENUM_OPERATORS(eViewOpsFlag, VIEWOPS_FLAG_ZOOM_TO_MOUSE);
/** Generic View Operator Custom-Data */
typedef struct ViewOpsData {
@ -146,6 +161,9 @@ typedef struct ViewOpsData {
float viewquat[4];
} curr;
eV3D_OpMode nav_type;
eViewOpsFlag viewops_flag;
float reverse;
bool axis_snap; /* view rotate only */
@ -165,13 +183,22 @@ typedef struct ViewOpsData {
/* view3d_navigate.cc */
/**
* Navigation operators that share the `ViewOpsData` utility.
*/
const char *viewops_operator_idname_get(eV3D_OpMode nav_type);
bool view3d_location_poll(struct bContext *C);
bool view3d_rotation_poll(struct bContext *C);
bool view3d_zoom_or_dolly_poll(struct bContext *C);
int view3d_navigate_invoke_impl(bContext *C,
wmOperator *op,
const wmEvent *event,
const eV3D_OpMode nav_type);
int view3d_navigate_modal_fn(bContext *C, wmOperator *op, const wmEvent *event);
void view3d_navigate_cancel_fn(struct bContext *C, struct wmOperator *op);
enum eViewOpsFlag viewops_flag_from_prefs(void);
void calctrackballvec(const struct rcti *rect, const int event_xy[2], float r_dir[3]);
void viewmove_apply(ViewOpsData *vod, int x, int y);
void viewmove_apply_reset(ViewOpsData *vod);
@ -193,9 +220,10 @@ void viewops_data_free(struct bContext *C, ViewOpsData *vod);
/**
* Allocate, fill in context pointers and calculate the values for #ViewOpsData
*/
ViewOpsData *viewops_data_create(struct bContext *C,
const struct wmEvent *event,
enum eViewOpsFlag viewops_flag);
ViewOpsData *viewops_data_create(bContext *C,
const wmEvent *event,
const eV3D_OpMode nav_type,
const bool use_cursor_init);
void VIEW3D_OT_view_all(struct wmOperatorType *ot);
void VIEW3D_OT_view_selected(struct wmOperatorType *ot);
@ -219,6 +247,11 @@ void VIEW3D_OT_fly(struct wmOperatorType *ot);
/* view3d_navigate_move.c */
int viewmove_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2]);
int viewmove_invoke_impl(ViewOpsData *vod, const wmEvent *event);
void viewmove_modal_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_move(struct wmOperatorType *ot);
@ -249,6 +282,11 @@ void VIEW3D_OT_view_roll(struct wmOperatorType *ot);
/* view3d_navigate_rotate.c */
int viewrotate_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2]);
int viewrotate_invoke_impl(ViewOpsData *vod, const wmEvent *event);
void viewrotate_modal_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_rotate(struct wmOperatorType *ot);
@ -326,6 +364,11 @@ void VIEW3D_OT_walk(struct wmOperatorType *ot);
/* view3d_navigate_zoom.c */
int viewzoom_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2]);
int viewzoom_invoke_impl(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr);
void viewzoom_modal_keymap(struct wmKeyConfig *keyconf);
void VIEW3D_OT_zoom(struct wmOperatorType *ot);

View File

@ -246,11 +246,7 @@ static int viewdolly_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
vod = op->customdata = viewops_data_create(
C,
event,
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_DOLLY, use_cursor_init);
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
@ -314,7 +310,7 @@ void VIEW3D_OT_dolly(wmOperatorType *ot)
/* identifiers */
ot->name = "Dolly View";
ot->description = "Dolly in/out in the view";
ot->idname = "VIEW3D_OT_dolly";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_DOLLY);
/* api callbacks */
ot->invoke = viewdolly_invoke;

View File

@ -49,52 +49,17 @@ void viewmove_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_move");
}
static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
int viewmove_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
/* Execute the events. */
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CONFIRM:
event_code = VIEW_CONFIRM;
break;
case VIEW_MODAL_CANCEL:
event_code = VIEW_CANCEL;
break;
case VIEWROT_MODAL_SWITCH_ZOOM:
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
case VIEWROT_MODAL_SWITCH_ROTATE:
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
}
}
else {
if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
else if (event->type == vod->init.event_type) {
if (event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
}
else if (event->type == EVT_ESCKEY) {
if (event->val == KM_PRESS) {
event_code = VIEW_CANCEL;
}
}
}
switch (event_code) {
case VIEW_APPLY: {
viewmove_apply(vod, event->xy[0], event->xy[1]);
viewmove_apply(vod, xy[0], xy[1]);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@ -111,66 +76,47 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
ret = OPERATOR_CANCELLED;
break;
}
case VIEW_PASS:
break;
}
if (use_autokey) {
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
}
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
if (ret & OPERATOR_FINISHED) {
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
}
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
return ret;
}
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int viewmove_invoke_impl(ViewOpsData *vod, const wmEvent *event)
{
ViewOpsData *vod;
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
vod = op->customdata = viewops_data_create(
C,
event,
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
vod = op->customdata;
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
if (event->type == MOUSEPAN) {
/* invert it, trackpad scroll follows same principle as 2d windows this way */
viewmove_apply(
vod, 2 * event->xy[0] - event->prev_xy[0], 2 * event->xy[1] - event->prev_xy[1]);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
eV3D_OpEvent event_code = event->type == MOUSEPAN ? VIEW_CONFIRM : VIEW_PASS;
if (event_code == VIEW_CONFIRM) {
/* Invert it, trackpad scroll follows same principle as 2d windows this way. */
int mx = 2 * event->xy[0] - event->prev_xy[0];
int my = 2 * event->xy[1] - event->prev_xy[1];
viewmove_apply(vod, mx, my);
return OPERATOR_FINISHED;
}
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int viewmove_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_MOVE);
}
void VIEW3D_OT_move(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Pan View";
ot->description = "Move the view";
ot->idname = "VIEW3D_OT_move";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_MOVE);
/* api callbacks */
ot->invoke = viewmove_invoke;
ot->modal = viewmove_modal;
ot->modal = view3d_navigate_modal_fn;
ot->poll = view3d_location_poll;
ot->cancel = view3d_navigate_cancel_fn;

View File

@ -435,8 +435,7 @@ static int ndof_orbit_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const wmNDOFMotionData *ndof = event->customdata;
vod = op->customdata = viewops_data_create(
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE));
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_NDOF_ORBIT, false);
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
@ -522,8 +521,7 @@ static int ndof_orbit_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *ev
const wmNDOFMotionData *ndof = event->customdata;
vod = op->customdata = viewops_data_create(
C, event, (viewops_flag_from_prefs() & ~VIEWOPS_FLAG_DEPTH_NAVIGATE));
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_NDOF_ORBIT_ZOOM, false);
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);

View File

@ -253,7 +253,7 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
else {
/* makes op->customdata */
vod = op->customdata = viewops_data_create(C, event, viewops_flag_from_prefs());
vod = op->customdata = viewops_data_create(C, event, V3D_OP_MODE_VIEW_ROLL, false);
vod->init.dial = BLI_dial_init((const float[2]){BLI_rcti_cent_x(&vod->region->winrct),
BLI_rcti_cent_y(&vod->region->winrct)},
FLT_EPSILON);
@ -287,7 +287,7 @@ void VIEW3D_OT_view_roll(wmOperatorType *ot)
/* identifiers */
ot->name = "View Roll";
ot->description = "Roll the view";
ot->idname = "VIEW3D_OT_view_roll";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_VIEW_ROLL);
/* api callbacks */
ot->invoke = viewroll_invoke;

View File

@ -293,60 +293,17 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2])
ED_region_tag_redraw(vod->region);
}
static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
int viewrotate_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
/* Execute the events. */
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CONFIRM:
event_code = VIEW_CONFIRM;
break;
case VIEW_MODAL_CANCEL:
event_code = VIEW_CANCEL;
break;
case VIEWROT_MODAL_AXIS_SNAP_ENABLE:
vod->axis_snap = true;
event_code = VIEW_APPLY;
break;
case VIEWROT_MODAL_AXIS_SNAP_DISABLE:
vod->rv3d->persp = vod->init.persp_with_auto_persp_applied;
vod->axis_snap = false;
event_code = VIEW_APPLY;
break;
case VIEWROT_MODAL_SWITCH_ZOOM:
WM_operator_name_call(C, "VIEW3D_OT_zoom", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
case VIEWROT_MODAL_SWITCH_MOVE:
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
}
}
else {
if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
else if (event->type == vod->init.event_type) {
if (event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
}
else if (event->type == EVT_ESCKEY) {
if (event->val == KM_PRESS) {
event_code = VIEW_CANCEL;
}
}
}
switch (event_code) {
case VIEW_APPLY: {
viewrotate_apply(vod, event->xy);
viewrotate_apply(vod, xy);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@ -376,84 +333,60 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
ret = OPERATOR_CANCELLED;
break;
}
case VIEW_PASS:
break;
}
if (use_autokey) {
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
}
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
if (ret & OPERATOR_FINISHED) {
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
}
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
return ret;
}
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int viewrotate_invoke_impl(ViewOpsData *vod, const wmEvent *event)
{
ViewOpsData *vod;
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
/* makes op->customdata */
vod = op->customdata = viewops_data_create(
C,
event,
viewops_flag_from_prefs() | VIEWOPS_FLAG_PERSP_ENSURE |
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
if (vod->use_dyn_ofs && (vod->rv3d->is_persp == false)) {
vod->use_dyn_ofs_ortho_correction = true;
}
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
eV3D_OpEvent event_code = ELEM(event->type, MOUSEROTATE, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
if (ELEM(event->type, MOUSEPAN, MOUSEROTATE)) {
/* Rotate direction we keep always same */
int event_xy[2];
if (event_code == VIEW_CONFIRM) {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
const bool is_inverted = (event->flag & WM_EVENT_SCROLL_INVERT) &&
(event->type != MOUSEROTATE);
if (event->type == MOUSEPAN) {
if (event->flag & WM_EVENT_SCROLL_INVERT) {
event_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
event_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
}
else {
copy_v2_v2_int(event_xy, event->prev_xy);
}
int m_xy[2];
if (is_inverted) {
m_xy[0] = 2 * event->xy[0] - event->prev_xy[0];
m_xy[1] = 2 * event->xy[1] - event->prev_xy[1];
}
else {
/* MOUSEROTATE performs orbital rotation, so y axis delta is set to 0 */
copy_v2_v2_int(event_xy, event->prev_xy);
copy_v2_v2_int(m_xy, event->prev_xy);
}
viewrotate_apply(vod, event_xy);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
viewrotate_apply(vod, m_xy);
return OPERATOR_FINISHED;
}
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_ROTATE);
}
void VIEW3D_OT_rotate(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Rotate View";
ot->description = "Rotate the view";
ot->idname = "VIEW3D_OT_rotate";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_ROTATE);
/* api callbacks */
ot->invoke = viewrotate_invoke;
ot->modal = viewrotate_modal;
ot->modal = view3d_navigate_modal_fn;
ot->poll = view3d_rotation_poll;
ot->cancel = view3d_navigate_cancel_fn;

View File

@ -331,9 +331,10 @@ static void viewzoom_apply_3d(ViewOpsData *vod,
static void viewzoom_apply(ViewOpsData *vod,
const int xy[2],
const eViewZoom_Style viewzoom,
const bool zoom_invert,
const bool zoom_to_pos)
const bool zoom_invert)
{
const bool zoom_to_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
if ((vod->rv3d->persp == RV3D_CAMOB) &&
(vod->rv3d->is_persp && ED_view3d_camera_lock_check(vod->v3d, vod->rv3d)) == 0) {
viewzoom_apply_camera(vod, xy, viewzoom, zoom_invert, zoom_to_pos);
@ -343,62 +344,17 @@ static void viewzoom_apply(ViewOpsData *vod,
}
}
static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
int viewzoom_modal_impl(bContext *C,
ViewOpsData *vod,
const eV3D_OpEvent event_code,
const int xy[2])
{
ViewOpsData *vod = op->customdata;
short event_code = VIEW_PASS;
bool use_autokey = false;
int ret = OPERATOR_RUNNING_MODAL;
/* Execute the events. */
if (event->type == EVT_MODAL_MAP) {
switch (event->val) {
case VIEW_MODAL_CONFIRM:
event_code = VIEW_CONFIRM;
break;
case VIEW_MODAL_CANCEL:
event_code = VIEW_CANCEL;
break;
case VIEWROT_MODAL_SWITCH_MOVE:
WM_operator_name_call(C, "VIEW3D_OT_move", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
case VIEWROT_MODAL_SWITCH_ROTATE:
WM_operator_name_call(C, "VIEW3D_OT_rotate", WM_OP_INVOKE_DEFAULT, NULL, event);
event_code = VIEW_CONFIRM;
break;
}
}
else {
if (event->type == MOUSEMOVE) {
event_code = VIEW_APPLY;
}
else if (event->type == TIMER) {
if (event->customdata == vod->timer) {
/* Continuous zoom. */
event_code = VIEW_APPLY;
}
}
else if (event->type == vod->init.event_type) {
if (event->val == KM_RELEASE) {
event_code = VIEW_CONFIRM;
}
}
else if (event->type == EVT_ESCKEY) {
if (event->val == KM_PRESS) {
event_code = VIEW_CANCEL;
}
}
}
switch (event_code) {
case VIEW_APPLY: {
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
viewzoom_apply(vod,
event->xy,
(eViewZoom_Style)U.viewzoom,
(U.uiflag & USER_ZOOM_INVERT) != 0,
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
viewzoom_apply(vod, xy, (eViewZoom_Style)U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
use_autokey = true;
}
@ -423,64 +379,33 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
ret = OPERATOR_CANCELLED;
break;
}
case VIEW_PASS:
break;
}
if (use_autokey) {
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
}
if ((ret & OPERATOR_RUNNING_MODAL) == 0) {
if (ret & OPERATOR_FINISHED) {
ED_view3d_camera_lock_undo_push(op->type->name, vod->v3d, vod->rv3d, C);
}
viewops_data_free(C, op->customdata);
op->customdata = NULL;
}
return ret;
}
static int viewzoom_exec(bContext *C, wmOperator *op)
static void view_zoom_apply_step(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
ScrArea *area,
ARegion *region,
const int delta,
const int zoom_xy[2])
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d;
RegionView3D *rv3d;
ScrArea *area;
ARegion *region;
View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
bool use_cam_zoom;
float dist_range[2];
const int delta = RNA_int_get(op->ptr, "delta");
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
if (op->customdata) {
ViewOpsData *vod = op->customdata;
area = vod->area;
region = vod->region;
}
else {
area = CTX_wm_area(C);
region = CTX_wm_region(C);
}
v3d = area->spacedata.first;
rv3d = region->regiondata;
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) &&
!(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
int zoom_xy_buf[2];
const int *zoom_xy = NULL;
if (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
region->winx / 2;
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
region->winy / 2;
zoom_xy = zoom_xy_buf;
}
ED_view3d_dist_range_get(v3d, dist_range);
if (delta < 0) {
@ -514,73 +439,96 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ED_view3d_camera_lock_autokey(v3d, rv3d, C, false, true);
ED_region_tag_redraw(region);
}
static int viewzoom_exec(bContext *C, wmOperator *op)
{
BLI_assert(op->customdata == NULL);
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
ScrArea *area = CTX_wm_area(C);
ARegion *region = CTX_wm_region(C);
View3D *v3d = area->spacedata.first;
RegionView3D *rv3d = region->regiondata;
const int delta = RNA_int_get(op->ptr, "delta");
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
int zoom_xy_buf[2];
const int *zoom_xy = NULL;
const bool do_zoom_to_mouse_pos = (use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS));
if (do_zoom_to_mouse_pos) {
zoom_xy_buf[0] = RNA_struct_property_is_set(op->ptr, "mx") ? RNA_int_get(op->ptr, "mx") :
region->winx / 2;
zoom_xy_buf[1] = RNA_struct_property_is_set(op->ptr, "my") ? RNA_int_get(op->ptr, "my") :
region->winy / 2;
zoom_xy = zoom_xy_buf;
}
view_zoom_apply_step(C, depsgraph, scene, area, region, delta, zoom_xy);
ED_view3d_camera_lock_undo_grouped_push(op->type->name, v3d, rv3d, C);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
return OPERATOR_FINISHED;
}
int viewzoom_invoke_impl(bContext *C, ViewOpsData *vod, const wmEvent *event, PointerRNA *ptr)
{
int xy[2];
PropertyRNA *prop;
prop = RNA_struct_find_property(ptr, "mx");
xy[0] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[0];
prop = RNA_struct_find_property(ptr, "my");
xy[1] = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : event->xy[1];
prop = RNA_struct_find_property(ptr, "delta");
const int delta = RNA_property_is_set(ptr, prop) ? RNA_property_int_get(ptr, prop) : 0;
if (delta) {
const bool do_zoom_to_mouse_pos = (vod->viewops_flag & VIEWOPS_FLAG_ZOOM_TO_MOUSE) != 0;
view_zoom_apply_step(C,
vod->depsgraph,
vod->scene,
vod->area,
vod->region,
delta,
do_zoom_to_mouse_pos ? xy : NULL);
return OPERATOR_FINISHED;
}
else {
eV3D_OpEvent event_code = ELEM(event->type, MOUSEZOOM, MOUSEPAN) ? VIEW_CONFIRM : VIEW_PASS;
if (event_code == VIEW_CONFIRM) {
if (U.uiflag & USER_ZOOM_HORIZ) {
vod->init.event_xy[0] = vod->prev.event_xy[0] = xy[0];
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + xy[0] -
event->prev_xy[0];
}
viewzoom_apply(vod, event->prev_xy, USER_ZOOM_DOLLY, (U.uiflag & USER_ZOOM_INVERT) != 0);
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
return OPERATOR_FINISHED;
}
}
if (U.viewzoom == USER_ZOOM_CONTINUE) {
/* needs a timer to continue redrawing */
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
vod->prev.time = PIL_check_seconds_timer();
}
return OPERATOR_RUNNING_MODAL;
}
/* viewdolly_invoke() copied this function, changes here may apply there */
static int viewzoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
const bool use_cursor_init = RNA_boolean_get(op->ptr, "use_cursor_init");
vod = op->customdata = viewops_data_create(
C,
event,
(viewops_flag_from_prefs() & ~VIEWOPS_FLAG_ORBIT_SELECT) |
(use_cursor_init ? VIEWOPS_FLAG_USE_MOUSE_INIT : 0));
ED_view3d_smooth_view_force_finish(C, vod->v3d, vod->region);
/* if one or the other zoom position aren't set, set from event */
if (!RNA_struct_property_is_set(op->ptr, "mx") || !RNA_struct_property_is_set(op->ptr, "my")) {
RNA_int_set(op->ptr, "mx", event->xy[0]);
RNA_int_set(op->ptr, "my", event->xy[1]);
}
if (RNA_struct_property_is_set(op->ptr, "delta")) {
viewzoom_exec(C, op);
}
else {
if (ELEM(event->type, MOUSEZOOM, MOUSEPAN)) {
if (U.uiflag & USER_ZOOM_HORIZ) {
vod->init.event_xy[0] = vod->prev.event_xy[0] = event->xy[0];
}
else {
/* Set y move = x move as MOUSEZOOM uses only x axis to pass magnification value */
vod->init.event_xy[1] = vod->prev.event_xy[1] = vod->init.event_xy[1] + event->xy[0] -
event->prev_xy[0];
}
viewzoom_apply(vod,
event->prev_xy,
USER_ZOOM_DOLLY,
(U.uiflag & USER_ZOOM_INVERT) != 0,
(use_cursor_init && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)));
ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
viewops_data_free(C, op->customdata);
op->customdata = NULL;
return OPERATOR_FINISHED;
}
if (U.viewzoom == USER_ZOOM_CONTINUE) {
/* needs a timer to continue redrawing */
vod->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
vod->prev.time = PIL_check_seconds_timer();
}
/* add temp handler */
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
return OPERATOR_FINISHED;
return view3d_navigate_invoke_impl(C, op, event, V3D_OP_MODE_ZOOM);
}
void VIEW3D_OT_zoom(wmOperatorType *ot)
@ -588,12 +536,12 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
/* identifiers */
ot->name = "Zoom View";
ot->description = "Zoom in/out in the view";
ot->idname = "VIEW3D_OT_zoom";
ot->idname = viewops_operator_idname_get(V3D_OP_MODE_ZOOM);
/* api callbacks */
ot->invoke = viewzoom_invoke;
ot->exec = viewzoom_exec;
ot->modal = viewzoom_modal;
ot->modal = view3d_navigate_modal_fn;
ot->poll = view3d_zoom_or_dolly_poll;
ot->cancel = view3d_navigate_cancel_fn;

View File

@ -139,9 +139,14 @@ static int an_stringdec(const char *string, char *head, char *tail, ushort *numl
return true;
}
static void an_stringenc(char *string, const char *head, const char *tail, ushort numlen, int pic)
static void an_stringenc(char *string,
const size_t string_maxncpy,
const char *head,
const char *tail,
ushort numlen,
int pic)
{
BLI_path_sequence_encode(string, head, tail, numlen, pic);
BLI_path_sequence_encode(string, string_maxncpy, head, tail, numlen, pic);
}
#ifdef WITH_AVI
@ -1614,7 +1619,7 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim,
case ANIM_SEQUENCE:
pic = an_stringdec(anim->first, head, tail, &digits);
pic += position;
an_stringenc(anim->name, head, tail, digits, pic);
an_stringenc(anim->name, sizeof(anim->name), head, tail, digits, pic);
ibuf = IMB_loadiffname(anim->name, IB_rect, anim->colorspace);
if (ibuf) {
anim->cur_position = position;

View File

@ -519,7 +519,10 @@ static std::string float3_to_string(const float3 &numbers)
MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false)
{
mtl_filepath_ = obj_filepath;
const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl");
/* It only makes sense to replace this extension if it's at least as long as the existing one. */
BLI_assert(strlen(BLI_path_extension(obj_filepath)) == 4);
const bool ok = BLI_path_extension_replace(
mtl_filepath_.data(), mtl_filepath_.size() + 1, ".mtl");
if (!ok) {
throw std::system_error(ENAMETOOLONG, std::system_category(), "");
}

View File

@ -155,8 +155,8 @@ static std::string get_image_filepath(const bNode *tex_node)
char head[FILE_MAX], tail[FILE_MAX];
ushort numlen;
int framenr = static_cast<NodeTexImage *>(tex_node->storage)->iuser.framenr;
BLI_path_sequence_decode(path, head, tail, &numlen);
BLI_path_sequence_encode(path, head, tail, numlen, framenr);
BLI_path_sequence_decode(path, head, sizeof(head), tail, sizeof(tail), &numlen);
BLI_path_sequence_encode(path, sizeof(path), head, tail, numlen, framenr);
}
return path;

View File

@ -279,7 +279,8 @@ class obj_exporter_regression_test : public obj_exporter_test {
strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1);
params.blen_filepath = bfile->main->filepath;
std::string golden_file_path = blender::tests::flags_test_asset_dir() + SEP_STR + golden_obj;
BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX);
BLI_split_dir_part(
golden_file_path.c_str(), params.file_base_for_tests, sizeof(params.file_base_for_tests));
export_frame(depsgraph, params, out_file_path.c_str());
std::string output_str = read_temp_file_in_string(out_file_path);

View File

@ -688,6 +688,36 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
}
}
if (!use_merge && !mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
const BoundedBitSpan src = mesh->runtime->subsurf_optimal_display_edges;
result->runtime->subsurf_optimal_display_edges.resize(result->totedge);
MutableBoundedBitSpan dst = result->runtime->subsurf_optimal_display_edges;
for (const int i : IndexRange(count)) {
dst.slice({i * mesh->totedge, mesh->totedge}).copy_from(src);
}
if (start_cap_mesh) {
MutableBitSpan cap_bits = dst.slice(
{result_nedges - start_cap_nedges - end_cap_nedges, start_cap_mesh->totedge});
if (start_cap_mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
cap_bits.set_all(true);
}
else {
cap_bits.copy_from(start_cap_mesh->runtime->subsurf_optimal_display_edges);
}
}
if (end_cap_mesh) {
MutableBitSpan cap_bits = dst.slice({result_nedges - end_cap_nedges, end_cap_mesh->totedge});
if (end_cap_mesh->runtime->subsurf_optimal_display_edges.is_empty()) {
cap_bits.set_all(true);
}
else {
cap_bits.copy_from(end_cap_mesh->runtime->subsurf_optimal_display_edges);
}
}
}
last_chunk_start = (count - 1) * chunk_nverts;
last_chunk_nverts = chunk_nverts;

View File

@ -667,8 +667,12 @@ static void build_pict_list_ex(
char filepath[FILE_MAX];
BLI_strncpy(filepath, first, sizeof(filepath));
fp_framenr = BLI_path_sequence_decode(
filepath, fp_decoded.head, fp_decoded.tail, &fp_decoded.digits);
fp_framenr = BLI_path_sequence_decode(filepath,
fp_decoded.head,
sizeof(fp_decoded.head),
fp_decoded.tail,
sizeof(fp_decoded.tail),
&fp_decoded.digits);
pupdate_time();
ptottime = 1.0;
@ -774,8 +778,12 @@ static void build_pict_list_ex(
/* create a new filepath each time */
fp_framenr += fstep;
BLI_path_sequence_encode(
filepath, fp_decoded.head, fp_decoded.tail, fp_decoded.digits, fp_framenr);
BLI_path_sequence_encode(filepath,
sizeof(filepath),
fp_decoded.head,
fp_decoded.tail,
fp_decoded.digits,
fp_framenr);
while ((has_event = GHOST_ProcessEvents(g_WS.ghost_system, false))) {
GHOST_DispatchEvents(g_WS.ghost_system);