Geometry Nodes: initial Volume Grid socket support #115270

Merged
Jacques Lucke merged 193 commits from LukasTonne/blender:volume-grid-sockets into main 2023-12-20 22:33:26 +01:00
66 changed files with 746 additions and 437 deletions
Showing only changes of commit 4cec91d7d2 - Show all commits

View File

@ -6,9 +6,11 @@
* \ingroup GHOST
*/
#include "GHOST_SystemWin32.hh"
#include <limits>
#include "GHOST_EventDragnDrop.hh"
#include "GHOST_EventTrackpad.hh"
#include "GHOST_SystemWin32.hh"
#ifndef _WIN32_IE
# define _WIN32_IE 0x0501 /* shipped before XP, so doesn't impose additional requirements */
@ -2371,6 +2373,14 @@ static uint *getClipboardImageDibV5(int *r_width, int *r_height)
int bitcount = bitmapV5Header->bV5BitCount;
int width = bitmapV5Header->bV5Width;
int height = bitmapV5Header->bV5Height;
/* Clipboard data is untrusted. Protect against arithmetic overflow as DibV5
* only supports up to DWORD size bytes. */
if (uint64_t(width) * uint64_t(height) > (std::numeric_limits<DWORD>::max() / 4)) {
GlobalUnlock(hGlobal);
return nullptr;
}
*r_width = width;
*r_height = height;
@ -2387,7 +2397,7 @@ static uint *getClipboardImageDibV5(int *r_width, int *r_height)
}
uchar *source = (uchar *)buffer;
uint *rgba = (uint *)malloc(width * height * 4);
uint *rgba = (uint *)malloc(uint64_t(width) * height * 4);
uint8_t *target = (uint8_t *)rgba;
if (bitmapV5Header->bV5Compression == BI_BITFIELDS && bitcount == 32) {
@ -2451,8 +2461,9 @@ static uint *getClipboardImageImBuf(int *r_width, int *r_height, UINT format)
if (ibuf) {
*r_width = ibuf->x;
*r_height = ibuf->y;
rgba = (uint *)malloc(4 * ibuf->x * ibuf->y);
memcpy(rgba, ibuf->byte_buffer.data, 4 * ibuf->x * ibuf->y);
const uint64_t byte_count = uint64_t(ibuf->x) * ibuf->y * 4;
rgba = (uint *)malloc(byte_count);
memcpy(rgba, ibuf->byte_buffer.data, byte_count);
IMB_freeImBuf(ibuf);
}
@ -2497,6 +2508,13 @@ uint *GHOST_SystemWin32::getClipboardImage(int *r_width, int *r_height) const
static bool putClipboardImageDibV5(uint *rgba, int width, int height)
{
/* DibV5 only supports up to DWORD size bytes. Skip processing entirely
* in case of overflow but return true to the caller to allow PNG to be
* used on its own. */
if (uint64_t(width) * uint64_t(height) > (std::numeric_limits<DWORD>::max() / 4)) {
return true;
}
DWORD size_pixels = width * height * 4;
/* Pixel data is 12 bytes after the header. */

View File

@ -13,6 +13,10 @@
# error WIN32 only!
#endif /* WIN32 */
#ifndef NOMINMAX
# define NOMINMAX
#endif
#define WIN32_LEAN_AND_MEAN
#include <ole2.h> /* For drag-n-drop. */
#include <windows.h>

View File

@ -514,6 +514,8 @@ class TOPBAR_MT_file_export(Menu):
self.layout.operator("wm.obj_export", text="Wavefront (.obj)")
if bpy.app.build_options.io_ply:
self.layout.operator("wm.ply_export", text="Stanford PLY (.ply)")
if bpy.app.build_options.io_stl:
self.layout.operator("wm.stl_export", text="STL (.stl) (experimental)")
class TOPBAR_MT_file_external_data(Menu):

View File

@ -11,6 +11,7 @@
#include "BLI_generic_virtual_array.hh"
#include "BLI_offset_indices.hh"
#include "BLI_set.hh"
#include "BLI_struct_equality_utils.hh"
#include "BKE_anonymous_attribute_id.hh"
#include "BKE_attribute.h"
@ -50,7 +51,8 @@ class AttributeIDRef {
StringRef name() const;
const AnonymousAttributeID &anonymous_id() const;
friend bool operator==(const AttributeIDRef &a, const AttributeIDRef &b);
BLI_STRUCT_EQUALITY_OPERATORS_1(AttributeIDRef, name_)
friend std::ostream &operator<<(std::ostream &stream, const AttributeIDRef &attribute_id);
};
@ -63,10 +65,7 @@ struct AttributeMetaData {
eAttrDomain domain;
eCustomDataType data_type;
constexpr friend bool operator==(AttributeMetaData a, AttributeMetaData b)
{
return (a.domain == b.domain) && (a.data_type == b.data_type);
}
BLI_STRUCT_EQUALITY_OPERATORS_2(AttributeMetaData, domain, data_type)
};
struct AttributeKind {
@ -835,11 +834,6 @@ inline AttributeIDRef::AttributeIDRef(const AnonymousAttributeID *anonymous_id)
anonymous_id_ = anonymous_id;
}
inline bool operator==(const AttributeIDRef &a, const AttributeIDRef &b)
{
return a.name_ == b.name_;
}
inline AttributeIDRef::operator bool() const
{
return !name_.is_empty();

View File

@ -19,7 +19,6 @@ struct BMLoop;
struct BMPartialUpdate;
struct BMesh;
struct BMeshCalcTessellation_Params;
struct BoundBox;
struct Depsgraph;
struct Mesh;
struct Object;

View File

@ -9,6 +9,7 @@
*/
#include "BLI_array.hh"
#include "BLI_bounds_types.hh"
#include "BLI_math_vector_types.hh"
struct BMEditMesh;
@ -33,7 +34,5 @@ void BKE_editmesh_cache_ensure_vert_normals(BMEditMesh *em, blender::bke::EditMe
void BKE_editmesh_cache_ensure_face_centers(BMEditMesh *em, blender::bke::EditMeshData *emd);
bool BKE_editmesh_cache_calc_minmax(BMEditMesh *em,
blender::bke::EditMeshData *emd,
float min[3],
float max[3]);
std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
const BMEditMesh *em, const blender::bke::EditMeshData *emd);

View File

@ -8,10 +8,6 @@
* \ingroup bke
*/
#ifdef __cplusplus
extern "C" {
#endif
struct Depsgraph;
struct Main;
struct Object;
@ -510,6 +506,3 @@ float BKE_gpencil_stroke_average_pressure_get(struct bGPDstroke *gps);
* Check if the thickness of the stroke is constant.
*/
bool BKE_gpencil_stroke_is_pressure_constant(struct bGPDstroke *gps);
#ifdef __cplusplus
}
#endif

View File

@ -18,7 +18,6 @@ Mesh *BKE_mesh_wrapper_from_editmesh(BMEditMesh *em,
const CustomData_MeshMasks *cd_mask_extra,
const Mesh *me_settings);
void BKE_mesh_wrapper_ensure_mdata(Mesh *me);
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3]);
int BKE_mesh_wrapper_vert_len(const Mesh *me);
int BKE_mesh_wrapper_edge_len(const Mesh *me);

View File

@ -9,6 +9,7 @@
*/
#include "BLI_array.hh"
#include "BLI_bit_vector.hh"
#include "BLI_bitmap.h"
#include "BLI_compiler_compat.h"
#include "BLI_math_matrix_types.hh"
@ -388,7 +389,7 @@ struct SculptPersistentBase {
struct SculptVertexInfo {
/* Indexed by base mesh vertex index, stores if that vertex is a boundary. */
BLI_bitmap *boundary;
blender::BitVector<> boundary;
};
struct SculptBoundaryEditInfo {

View File

@ -191,53 +191,47 @@ void BKE_crazyspace_set_quats_mesh(Mesh *me,
{
using namespace blender;
using namespace blender::bke;
BLI_bitmap *vert_tag = BLI_BITMAP_NEW(me->totvert, __func__);
BitVector<> vert_tag(me->totvert);
/* first store two sets of tangent vectors in vertices, we derive it just from the face-edges */
const Span<float3> positions = me->vert_positions();
const OffsetIndices faces = me->faces();
const OffsetIndices<int> faces = me->faces();
const Span<int> corner_verts = me->corner_verts();
for (int i = 0; i < me->faces_num; i++) {
for (const int i : faces.index_range()) {
const IndexRange face = faces[i];
const int *corner_vert_next = &corner_verts[face.start()];
const int *corner_vert_curr = &corner_vert_next[face.size() - 1];
const int *corner_vert_prev = &corner_vert_next[face.size() - 2];
for (int j = 0; j < face.size(); j++) {
if (!BLI_BITMAP_TEST(vert_tag, *corner_vert_curr)) {
for (const int corner : face) {
const int vert = corner_verts[corner];
if (!vert_tag[vert]) {
const int corner_prev = mesh::face_corner_prev(face, corner);
const int corner_next = mesh::face_corner_next(face, corner);
const float *co_prev, *co_curr, *co_next; /* orig */
const float *vd_prev, *vd_curr, *vd_next; /* deform */
/* retrieve mapped coordinates */
vd_prev = mappedcos[*corner_vert_prev];
vd_curr = mappedcos[*corner_vert_curr];
vd_next = mappedcos[*corner_vert_next];
vd_prev = mappedcos[corner_prev];
vd_curr = mappedcos[corner];
vd_next = mappedcos[corner_next];
if (!origcos.is_empty()) {
co_prev = origcos[*corner_vert_prev];
co_curr = origcos[*corner_vert_curr];
co_next = origcos[*corner_vert_next];
co_prev = origcos[corner_prev];
co_curr = origcos[corner];
co_next = origcos[corner_next];
}
else {
co_prev = positions[*corner_vert_prev];
co_curr = positions[*corner_vert_curr];
co_next = positions[*corner_vert_next];
co_prev = positions[corner_prev];
co_curr = positions[corner];
co_next = positions[corner_next];
}
set_crazy_vertex_quat(
quats[*corner_vert_curr], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev);
set_crazy_vertex_quat(quats[corner], co_curr, co_next, co_prev, vd_curr, vd_next, vd_prev);
BLI_BITMAP_ENABLE(vert_tag, *corner_vert_curr);
vert_tag[vert].set();
}
corner_vert_prev = corner_vert_curr;
corner_vert_curr = corner_vert_next;
corner_vert_next++;
}
}
MEM_freeN(vert_tag);
}
int BKE_crazyspace_get_first_deform_matrices_editbmesh(

View File

@ -95,32 +95,27 @@ void BKE_editmesh_cache_ensure_face_centers(BMEditMesh *em, blender::bke::EditMe
/** \name Calculate Min/Max
* \{ */
bool BKE_editmesh_cache_calc_minmax(BMEditMesh *em,
blender::bke::EditMeshData *emd,
float min[3],
float max[3])
std::optional<blender::Bounds<blender::float3>> BKE_editmesh_cache_calc_minmax(
const BMEditMesh *em, const blender::bke::EditMeshData *emd)
{
using namespace blender;
BMesh *bm = em->bm;
if (bm->totvert == 0) {
zero_v3(min);
zero_v3(max);
return false;
return std::nullopt;
}
if (emd->vertexCos.is_empty()) {
BMVert *eve;
BMIter iter;
float3 min(std::numeric_limits<float>::max());
float3 max(std::numeric_limits<float>::lowest());
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
minmax_v3v3_v3(min, max, eve->co);
}
return Bounds<float3>{min, max};
}
else {
const Bounds<float3> bounds = *bounds::min_max(emd->vertexCos.as_span());
copy_v3_v3(min, math::min(bounds.min, float3(min)));
copy_v3_v3(max, math::max(bounds.max, float3(max)));
}
return true;
return bounds::min_max(emd->vertexCos.as_span());
}
/** \} */

View File

@ -206,11 +206,7 @@ std::optional<Bounds<float3>> GeometrySet::compute_boundbox_without_instances()
bounds = bounds::merge(bounds, pointcloud->bounds_min_max());
}
if (const Mesh *mesh = this->get_mesh()) {
Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::lowest())};
if (BKE_mesh_wrapper_minmax(mesh, mesh_bounds.min, mesh_bounds.max)) {
bounds = bounds::merge(bounds, {mesh_bounds});
}
bounds = bounds::merge(bounds, mesh->bounds_min_max());
}
if (const Volume *volume = this->get_volume()) {
Bounds<float3> volume_bounds{float3(std::numeric_limits<float>::max()),

View File

@ -46,6 +46,7 @@
#include "BKE_bpath.h"
#include "BKE_deform.h"
#include "BKE_editmesh.hh"
#include "BKE_editmesh_cache.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
#include "BKE_key.h"
@ -1156,37 +1157,29 @@ void BKE_mesh_ensure_default_orig_index_customdata_no_check(Mesh *mesh)
BoundBox BKE_mesh_boundbox_get(Object *ob)
{
using namespace blender;
Mesh *me = static_cast<Mesh *>(ob->data);
float min[3], max[3];
INIT_MINMAX(min, max);
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
const Bounds<float3> bounds = me->bounds_min_max().value_or(
Bounds<float3>{float3(-1.0f), float3(1.0f)});
BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, min, max);
BKE_boundbox_init_from_minmax(&bb, bounds.min, bounds.max);
return bb;
}
void BKE_mesh_texspace_calc(Mesh *me)
{
using namespace blender;
if (me->texspace_flag & ME_TEXSPACE_FLAG_AUTO) {
float min[3], max[3];
INIT_MINMAX(min, max);
if (!BKE_mesh_wrapper_minmax(me, min, max)) {
min[0] = min[1] = min[2] = -1.0f;
max[0] = max[1] = max[2] = 1.0f;
}
const Bounds<float3> bounds = me->bounds_min_max().value_or(
Bounds<float3>{float3(-1.0f), float3(1.0f)});
float texspace_location[3], texspace_size[3];
mid_v3_v3v3(texspace_location, min, max);
mid_v3_v3v3(texspace_location, bounds.min, bounds.max);
texspace_size[0] = (max[0] - min[0]) / 2.0f;
texspace_size[1] = (max[1] - min[1]) / 2.0f;
texspace_size[2] = (max[2] - min[2]) / 2.0f;
texspace_size[0] = (bounds.max[0] - bounds.min[0]) / 2.0f;
texspace_size[1] = (bounds.max[1] - bounds.min[1]) / 2.0f;
texspace_size[2] = (bounds.max[2] - bounds.min[2]) / 2.0f;
for (int a = 0; a < 3; a++) {
if (texspace_size[a] == 0.0f) {
@ -1493,11 +1486,21 @@ void BKE_mesh_looptri_get_real_edges(const blender::int2 *edges,
std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
{
using namespace blender;
if (this->totvert == 0) {
const int verts_num = BKE_mesh_wrapper_vert_len(this);
if (verts_num == 0) {
return std::nullopt;
}
this->runtime->bounds_cache.ensure(
[&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->vert_positions()); });
this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
switch (this->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
r_bounds = *BKE_editmesh_cache_calc_minmax(this->edit_mesh, this->runtime->edit_data);
break;
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD:
r_bounds = *bounds::min_max(this->vert_positions());
break;
}
});
return this->runtime->bounds_cache.data();
}

View File

@ -147,26 +147,6 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
});
}
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
{
using namespace blender;
switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: {
if (const std::optional<Bounds<float3>> bounds = me->bounds_min_max()) {
copy_v3_v3(min, math::min(bounds->min, float3(min)));
copy_v3_v3(max, math::max(bounds->max, float3(max)));
return true;
}
return false;
}
}
BLI_assert_unreachable();
return false;
}
/* -------------------------------------------------------------------- */
/** \name Mesh Coordinate Access
* \{ */

View File

@ -9,6 +9,7 @@
#include "BLI_bit_group_vector.hh"
#include "BLI_bit_span_ops.hh"
#include "BLI_set.hh"
#include "BLI_struct_equality_utils.hh"
#include "BLI_task.hh"
#include "BLI_timeit.hh"
@ -69,10 +70,7 @@ struct ZoneRelation {
return get_default_hash_2(this->parent, this->child);
}
friend bool operator==(const ZoneRelation &a, const ZoneRelation &b)
{
return a.parent == b.parent && a.child == b.child;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(ZoneRelation, parent, child)
};
static std::optional<Vector<ZoneRelation>> get_direct_zone_relations(

View File

@ -3606,19 +3606,15 @@ std::optional<BoundBox> BKE_object_boundbox_eval_cached_get(Object *ob)
void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
{
float3 min(FLT_MAX);
float3 max(-FLT_MAX);
if (!BKE_mesh_wrapper_minmax(me_eval, min, max)) {
min = float3(0);
max = float3(0);
}
using namespace blender;
const Bounds<float3> bounds = me_eval->bounds_min_max().value_or(
Bounds<float3>{float3(0), float3(0)});
if (ob->runtime->bb == nullptr) {
ob->runtime->bb = MEM_cnew<BoundBox>("DM-BoundBox");
}
BKE_boundbox_init_from_minmax(ob->runtime->bb, min, max);
BKE_boundbox_init_from_minmax(ob->runtime->bb, bounds.min, bounds.max);
ob->runtime->bb->flag &= ~BOUNDBOX_DIRTY;
}
@ -3632,11 +3628,7 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
bounds = ob->runtime->geometry_set_eval->compute_boundbox_without_instances();
}
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::lowest())};
if (BKE_mesh_wrapper_minmax(mesh_eval, mesh_bounds.min, mesh_bounds.max)) {
bounds = bounds::merge(bounds, {mesh_bounds});
}
bounds = bounds::merge(bounds, mesh_eval->bounds_min_max());
}
else {
return false;
@ -3947,7 +3939,8 @@ bool BKE_object_minmax_empty_drawtype(const Object *ob, float r_min[3], float r_
}
case OB_EMPTY_IMAGE: {
const float *ofs = ob->ima_ofs;
/* NOTE: this is the best approximation that can be calculated without loading the image. */
/* NOTE: this is the best approximation that can be calculated without loading the image.
*/
min[0] = ofs[0] * radius;
min[1] = ofs[1] * radius;
max[0] = radius + (ofs[0] * radius);
@ -4279,9 +4272,9 @@ Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object)
blender::bke::GeometrySet *geometry_set_eval = object->runtime->geometry_set_eval;
if (geometry_set_eval) {
/* Some areas expect to be able to modify the evaluated mesh in limited ways. Theoretically
* this should be avoided, or at least protected with a lock, so a const mesh could be returned
* from this function. We use a const_cast instead of #get_mesh_for_write, because that might
* result in a copy of the mesh when it is shared. */
* this should be avoided, or at least protected with a lock, so a const mesh could be
* returned from this function. We use a const_cast instead of #get_mesh_for_write, because
* that might result in a copy of the mesh when it is shared. */
Mesh *mesh = const_cast<Mesh *>(geometry_set_eval->get_mesh());
if (mesh) {
return mesh;
@ -4421,8 +4414,8 @@ static int pc_cmp(const void *a, const void *b)
/* TODO: Review the usages of this function, currently with COW it will be called for orig object
* and then again for COW copies of it, think this is bad since there is no guarantee that we get
* the same stack index in both cases? Order is important since this index is used for filenames on
* disk. */
* the same stack index in both cases? Order is important since this index is used for filenames
* on disk. */
int BKE_object_insert_ptcache(Object *ob)
{
LinkData *link = nullptr;

View File

@ -1460,7 +1460,7 @@ static void sculptsession_free_pbvh(Object *object)
MEM_SAFE_FREE(ss->preview_vert_list);
ss->preview_vert_count = 0;
MEM_SAFE_FREE(ss->vertex_info.boundary);
ss->vertex_info.boundary.clear_and_shrink();
MEM_SAFE_FREE(ss->fake_neighbors.fake_neighbor_index);
}

View File

@ -7,6 +7,7 @@
#include <ostream>
#include "BLI_math_color.h"
#include "BLI_struct_equality_utils.hh"
namespace blender {
@ -118,17 +119,7 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB
return stream;
}
friend bool operator==(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
{
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
}
friend bool operator!=(const ColorRGBA<ChannelStorageType, Space, Alpha> &a,
const ColorRGBA<ChannelStorageType, Space, Alpha> &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_4(ColorRGBA, r, g, b, a)
uint64_t hash() const
{

View File

@ -38,6 +38,7 @@
#include "BLI_linear_allocator.hh"
#include "BLI_stack.hh"
#include "BLI_string_ref.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender {
@ -55,15 +56,7 @@ struct ComputeContextHash {
return v1;
}
friend bool operator==(const ComputeContextHash &a, const ComputeContextHash &b)
{
return a.v1 == b.v1 && a.v2 == b.v2;
}
friend bool operator!=(const ComputeContextHash &a, const ComputeContextHash &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_2(ComputeContextHash, v1, v2)
void mix_in(const void *data, int64_t len);

View File

@ -9,6 +9,7 @@
*/
#include "BLI_implicit_sharing.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender {
@ -127,10 +128,7 @@ template<typename T> class ImplicitSharingPtr {
return get_default_hash(data_);
}
friend bool operator==(const ImplicitSharingPtr &a, const ImplicitSharingPtr &b)
{
return a.data_ == b.data_;
}
BLI_STRUCT_EQUALITY_OPERATORS_1(ImplicitSharingPtr, data_)
private:
static void add_user(T *data)

View File

@ -20,6 +20,7 @@
#include <ostream>
#include "BLI_math_base.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender::math {
@ -144,15 +145,7 @@ template<typename T> struct AngleRadianBase {
return *this;
}
friend bool operator==(const AngleRadianBase &a, const AngleRadianBase &b)
{
return a.value_ == b.value_;
}
friend bool operator!=(const AngleRadianBase &a, const AngleRadianBase &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_1(AngleRadianBase, value_)
friend std::ostream &operator<<(std::ostream &stream, const AngleRadianBase &rot)
{
@ -348,15 +341,7 @@ template<typename T> struct AngleCartesianBase {
return *this;
}
friend bool operator==(const AngleCartesianBase &a, const AngleCartesianBase &b)
{
return a.cos_ == b.cos_ && a.sin_ == b.sin_;
}
friend bool operator!=(const AngleCartesianBase &a, const AngleCartesianBase &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_2(AngleCartesianBase, cos_, sin_)
friend std::ostream &operator<<(std::ostream &stream, const AngleCartesianBase &rot)
{

View File

@ -79,15 +79,7 @@ template<typename T, typename AngleT> struct AxisAngleBase {
/** Operators. */
friend bool operator==(const AxisAngleBase &a, const AxisAngleBase &b)
{
return (a.axis() == b.axis()) && (a.angle() == b.angle());
}
friend bool operator!=(const AxisAngleBase &a, const AxisAngleBase &b)
{
return (a != b);
}
BLI_STRUCT_EQUALITY_OPERATORS_2(AxisAngleBase, axis_, angle_)
friend std::ostream &operator<<(std::ostream &stream, const AxisAngleBase &rot)
{

View File

@ -31,6 +31,7 @@
#include "BLI_math_angle_types.hh"
#include "BLI_math_base.hh"
#include "BLI_math_basis_types.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender::math {
@ -186,10 +187,7 @@ template<typename T> struct EulerXYZBase : public EulerBase<T> {
return {-a.xyz_.x, -a.xyz_.y, -a.xyz_.z};
}
friend bool operator==(const EulerXYZBase &a, const EulerXYZBase &b)
{
return a.xyz_ == b.xyz_;
}
BLI_STRUCT_EQUALITY_OPERATORS_1(EulerXYZBase, xyz_)
friend std::ostream &operator<<(std::ostream &stream, const EulerXYZBase &rot)
{
@ -336,10 +334,7 @@ template<typename T> struct Euler3Base : public EulerBase<T> {
return {-a.xyz_, a.order_};
}
friend bool operator==(const Euler3Base &a, const Euler3Base &b)
{
return a.xyz_ == b.xyz_ && a.order_ == b.order_;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(Euler3Base, xyz_, order_)
friend std::ostream &operator<<(std::ostream &stream, const Euler3Base &rot)
{

View File

@ -15,6 +15,7 @@
#include "BLI_math_basis_types.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender::math {
@ -157,10 +158,7 @@ template<typename T> struct QuaternionBase {
return {-a.w, -a.x, -a.y, -a.z};
}
friend bool operator==(const QuaternionBase &a, const QuaternionBase &b)
{
return (a.w == b.w) && (a.x == b.x) && (a.y == b.y) && (a.z == b.z);
}
BLI_STRUCT_EQUALITY_OPERATORS_4(QuaternionBase, w, x, y, z)
uint64_t hash() const
{
@ -264,11 +262,8 @@ template<typename T> struct DualQuaternionBase {
return dq;
}
friend bool operator==(const DualQuaternionBase &a, const DualQuaternionBase &b)
{
return (a.quat == b.quat) && (a.trans == b.trans) && (a.quat_weight == b.quat_weight) &&
(a.scale_weight == b.scale_weight) && (a.scale == b.scale);
}
BLI_STRUCT_EQUALITY_OPERATORS_5(
DualQuaternionBase, quat, trans, quat_weight, scale_weight, scale)
friend std::ostream &operator<<(std::ostream &stream, const DualQuaternionBase &rot)
{

View File

@ -0,0 +1,55 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/**
* The macros below reduce the boilerplate needed to implement basic equality operators for
* structs. These macros could be removed starting with C++20, because then we can use defaulted
* comparison operators: https://en.cppreference.com/w/cpp/language/default_comparisons
*
* Using these macros also reduces the probably for common typos, like comparing a value to itself
* or comparing the same value twice.
*/
#define BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type) \
friend bool operator!=(const Type &a, const Type &b) \
{ \
return !(a == b); \
}
#define BLI_STRUCT_EQUALITY_OPERATORS_1(Type, m) \
friend bool operator==(const Type &a, const Type &b) \
{ \
return a.m == b.m; \
} \
BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type)
#define BLI_STRUCT_EQUALITY_OPERATORS_2(Type, m1, m2) \
friend bool operator==(const Type &a, const Type &b) \
{ \
return a.m1 == b.m1 && a.m2 == b.m2; \
} \
BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type)
#define BLI_STRUCT_EQUALITY_OPERATORS_3(Type, m1, m2, m3) \
friend bool operator==(const Type &a, const Type &b) \
{ \
return a.m1 == b.m1 && a.m2 == b.m2 && a.m3 == b.m3; \
} \
BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type)
#define BLI_STRUCT_EQUALITY_OPERATORS_4(Type, m1, m2, m3, m4) \
friend bool operator==(const Type &a, const Type &b) \
{ \
return a.m1 == b.m1 && a.m2 == b.m2 && a.m3 == b.m3 && a.m4 == b.m4; \
} \
BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type)
#define BLI_STRUCT_EQUALITY_OPERATORS_5(Type, m1, m2, m3, m4, m5) \
friend bool operator==(const Type &a, const Type &b) \
{ \
return a.m1 == b.m1 && a.m2 == b.m2 && a.m3 == b.m3 && a.m4 == b.m4 && a.m5 == b.m5; \
} \
BLI_STRUCT_DERIVED_UNEQUAL_OPERATOR(Type)

View File

@ -8,6 +8,7 @@
#include "BLI_assert.h"
#include "BLI_math_base.h"
#include "BLI_struct_equality_utils.hh"
namespace blender {
@ -58,15 +59,7 @@ struct SubFrame {
return {INT32_MAX, std::nexttowardf(1.0f, 0.0)};
}
friend bool operator==(const SubFrame &a, const SubFrame &b)
{
return a.frame_ == b.frame_ && a.subframe_ == b.subframe_;
}
friend bool operator!=(const SubFrame &a, const SubFrame &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_2(SubFrame, frame_, subframe_)
friend bool operator<(const SubFrame &a, const SubFrame &b)
{

View File

@ -355,6 +355,7 @@ set(SRC
BLI_string_utf8.h
BLI_string_utf8_symbols.h
BLI_string_utils.hh
BLI_struct_equality_utils.hh
BLI_sub_frame.hh
BLI_sys_types.h
BLI_system.h

View File

@ -515,9 +515,9 @@ void BM_mesh_copy_init_customdata_from_mesh_array(BMesh *bm_dst,
CustomData mesh_edata = CustomData_shallow_copy_remove_non_bmesh_attributes(
&me_src->edge_data, CD_MASK_BMESH.emask);
CustomData mesh_pdata = CustomData_shallow_copy_remove_non_bmesh_attributes(
&me_src->face_data, CD_MASK_BMESH.lmask);
&me_src->face_data, CD_MASK_BMESH.pmask);
CustomData mesh_ldata = CustomData_shallow_copy_remove_non_bmesh_attributes(
&me_src->loop_data, CD_MASK_BMESH.pmask);
&me_src->loop_data, CD_MASK_BMESH.lmask);
if (i == 0) {
CustomData_copy_layout(&mesh_vdata, &bm_dst->vdata, CD_MASK_BMESH.vmask, CD_SET_DEFAULT, 0);

View File

@ -16,6 +16,8 @@
#include "GPU_vertex_format.h"
struct GPUVertBuf;
/**
* Component length of 3 is used for scalars because implicit conversion is done by OpenGL from a
* scalar `s` will produce `vec4(s, 0, 0, 1)`. However, following the Blender convention, it should

View File

@ -23,9 +23,19 @@ namespace blender::draw {
* \{ */
struct UVStretchAngle {
int16_t angle;
/* NOTE: To more easily satisfy cross-platform alignment requirements, placing the 4-byte aligned
* 2 element array first ensures each attribute block is 4-byte aligned. */
int16_t uv_angles[2];
int16_t angle;
#if defined(WITH_METAL_BACKEND)
/* For apple platforms, vertex data struct must align to minimum per-vertex-stride of 4 bytes.
* Hence, this struct needs to align to 8 bytes. */
int16_t __pad;
#endif
};
#if defined(WITH_METAL_BACKEND)
BLI_STATIC_ASSERT_ALIGN(UVStretchAngle, 4)
#endif
struct MeshExtract_StretchAngle_Data {
UVStretchAngle *vbo_data;
@ -85,8 +95,8 @@ static void extract_edituv_stretch_angle_init(const MeshRenderData &mr,
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
/* Waning: adjust #UVStretchAngle struct accordingly. */
GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_I16, 2, GPU_FETCH_INT_TO_FLOAT_UNIT);
GPU_vertformat_attr_add(&format, "angle", GPU_COMP_I16, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(vbo, &format);

View File

@ -32,15 +32,15 @@ static int grease_pencil_material_reveal_exec(bContext *C, wmOperator * /*op*/)
bool changed = false;
for (const int i : IndexRange(object->totcol)) {
if (Material *ma = BKE_gpencil_material(object, i + 1)) {
MaterialGPencilStyle *gp_style = ma->gp_style;
gp_style->flag &= ~GP_MATERIAL_HIDE;
MaterialGPencilStyle &gp_style = *ma->gp_style;
gp_style.flag &= ~GP_MATERIAL_HIDE;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
changed = true;
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_SHADING);
WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
}

View File

@ -4374,7 +4374,7 @@ static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
const bool prior_label = but->prev && but->prev->type == UI_BTYPE_LABEL && but->prev->str[0] &&
but->prev->alignnr == but->alignnr;
if (title[0] && (categories == 0) && (!but->str[0] || !prior_label)) {
if (title && title[0] && (categories == 0) && (!but->str[0] || !prior_label)) {
/* Show title when no categories and calling button has no text or prior label. */
uiDefBut(block,
UI_BTYPE_LABEL,
@ -4434,7 +4434,7 @@ static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
if (item->icon) {
uiItemL(column, item->name, item->icon);
}
else {
else if (item->name) {
/* Do not use uiItemL here, as our root layout is a menu one,
* it will add a fake blank icon! */
uiDefBut(block,

View File

@ -72,5 +72,6 @@ void ED_operatortypes_io()
#ifdef WITH_IO_STL
WM_operatortype_append(WM_OT_stl_import);
WM_operatortype_append(WM_OT_stl_export);
#endif
}

View File

@ -16,14 +16,164 @@
# include "DNA_space_types.h"
# include "ED_fileselect.hh"
# include "ED_outliner.hh"
# include "RNA_access.hh"
# include "RNA_define.hh"
# include "BLT_translation.h"
# include "UI_interface.hh"
# include "UI_resources.hh"
# include "IO_stl.hh"
# include "io_stl_ops.hh"
static int wm_stl_export_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
ED_fileselect_ensure_default_filepath(C, op, ".stl");
WM_event_add_fileselect(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int wm_stl_export_execute(bContext *C, wmOperator *op)
{
if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
return OPERATOR_CANCELLED;
}
struct STLExportParams export_params;
RNA_string_get(op->ptr, "filepath", export_params.filepath);
export_params.forward_axis = eIOAxis(RNA_enum_get(op->ptr, "forward_axis"));
export_params.up_axis = eIOAxis(RNA_enum_get(op->ptr, "up_axis"));
export_params.global_scale = RNA_float_get(op->ptr, "global_scale");
export_params.apply_modifiers = RNA_boolean_get(op->ptr, "apply_modifiers");
export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects");
export_params.ascii_format = RNA_boolean_get(op->ptr, "ascii_format");
export_params.use_batch = RNA_boolean_get(op->ptr, "use_batch");
STL_export(C, &export_params);
return OPERATOR_FINISHED;
}
static void ui_stl_export_settings(uiLayout *layout, PointerRNA *op_props_ptr)
{
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
uiLayout *box, *col, *sub;
box = uiLayoutBox(layout);
col = uiLayoutColumn(box, false);
uiItemR(col, op_props_ptr, "ascii_format", UI_ITEM_NONE, IFACE_("ASCII"), ICON_NONE);
uiItemR(col, op_props_ptr, "use_batch", UI_ITEM_NONE, IFACE_("Batch"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Include"));
uiItemR(sub,
op_props_ptr,
"export_selected_objects",
UI_ITEM_NONE,
IFACE_("Selection Only"),
ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Transform"));
uiItemR(sub, op_props_ptr, "global_scale", UI_ITEM_NONE, IFACE_("Scale"), ICON_NONE);
uiItemR(sub, op_props_ptr, "use_scene_unit", UI_ITEM_NONE, IFACE_("Scene Unit"), ICON_NONE);
uiItemR(sub, op_props_ptr, "forward_axis", UI_ITEM_NONE, IFACE_("Forward"), ICON_NONE);
uiItemR(sub, op_props_ptr, "up_axis", UI_ITEM_NONE, IFACE_("Up"), ICON_NONE);
box = uiLayoutBox(layout);
sub = uiLayoutColumnWithHeading(box, false, IFACE_("Geometry"));
uiItemR(
sub, op_props_ptr, "apply_modifiers", UI_ITEM_NONE, IFACE_("Apply Modifiers"), ICON_NONE);
}
static void wm_stl_export_draw(bContext * /*C*/, wmOperator *op)
{
PointerRNA ptr = RNA_pointer_create(nullptr, op->type->srna, op->properties);
ui_stl_export_settings(op->layout, &ptr);
}
/**
* Return true if any property in the UI is changed.
*/
static bool wm_stl_export_check(bContext * /*C*/, wmOperator *op)
{
char filepath[FILE_MAX];
bool changed = false;
RNA_string_get(op->ptr, "filepath", filepath);
if (!BLI_path_extension_check(filepath, ".stl")) {
BLI_path_extension_ensure(filepath, FILE_MAX, ".stl");
RNA_string_set(op->ptr, "filepath", filepath);
changed = true;
}
return changed;
}
void WM_OT_stl_export(wmOperatorType *ot)
{
PropertyRNA *prop;
ot->name = "Export STL";
ot->description = "Save the scene to an STL file";
ot->idname = "WM_OT_stl_export";
ot->invoke = wm_stl_export_invoke;
ot->exec = wm_stl_export_execute;
ot->poll = WM_operator_winactive;
ot->ui = wm_stl_export_draw;
ot->check = wm_stl_export_check;
ot->flag = OPTYPE_PRESET;
WM_operator_properties_filesel(ot,
FILE_TYPE_FOLDER,
FILE_BLENDER,
FILE_SAVE,
WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS,
FILE_DEFAULTDISPLAY,
FILE_SORT_DEFAULT);
RNA_def_boolean(ot->srna,
"ascii_format",
false,
"ASCII Format",
"Export file in ASCII format, export as binary otherwise");
RNA_def_boolean(
ot->srna, "use_batch", false, "Batch Export", "Export each object to a separate file");
RNA_def_boolean(ot->srna,
"export_selected_objects",
false,
"Export Selected Objects",
"Export only selected objects instead of all supported objects");
RNA_def_float(ot->srna, "global_scale", 1.0f, 1e-6f, 1e6f, "Scale", "", 0.001f, 1000.0f);
RNA_def_boolean(ot->srna,
"use_scene_unit",
false,
"Scene Unit",
"Apply current scene's unit (as defined by unit scale) to exported data");
prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
RNA_def_property_update_runtime(prop, io_ui_forward_axis_update);
prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
RNA_def_property_update_runtime(prop, io_ui_up_axis_update);
RNA_def_boolean(
ot->srna, "apply_modifiers", true, "Apply Modifiers", "Apply modifiers to exported meshes");
/* Only show .stl files by default. */
prop = RNA_def_string(ot->srna, "filter_glob", "*.stl", 0, "Extension Filter", "");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int wm_stl_import_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
return WM_operator_filesel(C, op, event);

View File

@ -1065,21 +1065,20 @@ static void cursor_draw_tiling_preview(const uint gpuattr,
Object *ob,
const float radius)
{
const BoundBox bb = *BKE_object_boundbox_get(ob);
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob);
const blender::Bounds<blender::float3> bounds = *mesh_eval->bounds_min_max();
float orgLoc[3], location[3];
int tile_pass = 0;
int start[3];
int end[3];
int cur[3];
const float *bbMin = bb.vec[0];
const float *bbMax = bb.vec[6];
const float *step = sd->paint.tile_offset;
copy_v3_v3(orgLoc, true_location);
for (int dim = 0; dim < 3; dim++) {
if ((sd->paint.symmetry_flags & (PAINT_TILE_X << dim)) && step[dim] > 0) {
start[dim] = (bbMin[dim] - orgLoc[dim] - radius) / step[dim];
end[dim] = (bbMax[dim] - orgLoc[dim] + radius) / step[dim];
start[dim] = (bounds.min[dim] - orgLoc[dim] - radius) / step[dim];
end[dim] = (bounds.max[dim] - orgLoc[dim] + radius) / step[dim];
}
else {
start[dim] = end[dim] = 0;

View File

@ -986,8 +986,7 @@ void SCULPT_vertex_neighbors_get(SculptSession *ss,
static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss, const int index)
{
BLI_assert(ss->vertex_info.boundary);
return BLI_BITMAP_TEST(ss->vertex_info.boundary, index);
return ss->vertex_info.boundary[index];
}
bool SCULPT_vertex_is_boundary(const SculptSession *ss, const PBVHVertRef vertex)
@ -3411,7 +3410,7 @@ static void sculpt_topology_update(Sculpt *sd,
/* Free index based vertex info as it will become invalid after modifying the topology during the
* stroke. */
MEM_SAFE_FREE(ss->vertex_info.boundary);
ss->vertex_info.boundary.clear();
PBVHTopologyUpdateMode mode = PBVHTopologyUpdateMode(0);
float location[3];
@ -6099,13 +6098,13 @@ void SCULPT_boundary_info_ensure(Object *object)
{
using namespace blender;
SculptSession *ss = object->sculpt;
if (ss->vertex_info.boundary) {
if (!ss->vertex_info.boundary.is_empty()) {
return;
}
Mesh *base_mesh = BKE_mesh_from_object(object);
ss->vertex_info.boundary = BLI_BITMAP_NEW(base_mesh->totvert, "Boundary info");
ss->vertex_info.boundary.resize(base_mesh->totvert);
Array<int> adjacent_faces_edge_count(base_mesh->totedge, 0);
array_utils::count_indices(base_mesh->corner_edges(), adjacent_faces_edge_count);
@ -6113,8 +6112,8 @@ void SCULPT_boundary_info_ensure(Object *object)
for (const int e : edges.index_range()) {
if (adjacent_faces_edge_count[e] < 2) {
const int2 &edge = edges[e];
BLI_BITMAP_SET(ss->vertex_info.boundary, edge[0], true);
BLI_BITMAP_SET(ss->vertex_info.boundary, edge[1], true);
ss->vertex_info.boundary[edge[0]].set();
ss->vertex_info.boundary[edge[1]].set();
}
}
}

View File

@ -156,7 +156,7 @@ void SnapData::clip_planes_enable(SnapObjectContext *sctx,
bool SnapData::snap_boundbox(const float3 &min, const float3 &max)
{
/* In vertex and edges you need to get the pixel distance from ray to BoundBox,
/* In vertex and edges you need to get the pixel distance from ray to bounding box,
* see: #46099, #46816 */
#ifdef TEST_CLIPPLANES_IN_BOUNDBOX

View File

@ -314,7 +314,7 @@ static bool raycastEditMesh(SnapCache_EditMesh *em_cache,
local_depth *= local_scale;
}
/* Test BoundBox */
/* Test bounding box */
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */
if (!isect_ray_aabb_v3_simple(

View File

@ -104,7 +104,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
local_depth *= local_scale;
}
/* Test BoundBox */
/* Test bounding box */
if (ob_eval->data == me_eval) {
const Bounds<float3> bounds = *me_eval->bounds_min_max();
/* was BKE_boundbox_ray_hit_check, see: cf6ca226fa58 */

View File

@ -13,6 +13,7 @@
*/
#include "BLI_cpp_type.hh"
#include "BLI_struct_equality_utils.hh"
namespace blender::fn::multi_function {
@ -79,8 +80,7 @@ class DataType {
return *type_;
}
friend bool operator==(const DataType &a, const DataType &b);
friend bool operator!=(const DataType &a, const DataType &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(DataType, category_, type_)
std::string to_string() const
{
@ -100,14 +100,4 @@ class DataType {
}
};
inline bool operator==(const DataType &a, const DataType &b)
{
return a.category_ == b.category_ && a.type_ == b.type_;
}
inline bool operator!=(const DataType &a, const DataType &b)
{
return !(a == b);
}
} // namespace blender::fn::multi_function

View File

@ -141,18 +141,7 @@ class ParamType {
return interface_type_ == Output;
}
friend bool operator==(const ParamType &a, const ParamType &b);
friend bool operator!=(const ParamType &a, const ParamType &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(ParamType, interface_type_, data_type_)
};
inline bool operator==(const ParamType &a, const ParamType &b)
{
return a.interface_type_ == b.interface_type_ && a.data_type_ == b.data_type_;
}
inline bool operator!=(const ParamType &a, const ParamType &b)
{
return !(a == b);
}
} // namespace blender::fn::multi_function

View File

@ -67,16 +67,7 @@ class InstructionCursor {
Type type() const;
friend bool operator==(const InstructionCursor &a, const InstructionCursor &b)
{
return a.type_ == b.type_ && a.instruction_ == b.instruction_ &&
a.branch_output_ == b.branch_output_;
}
friend bool operator!=(const InstructionCursor &a, const InstructionCursor &b)
{
return !(a == b);
}
BLI_STRUCT_EQUALITY_OPERATORS_3(InstructionCursor, type_, instruction_, branch_output_)
};
/**

View File

@ -2,6 +2,7 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_bounds.hh"
#include "BLI_function_ref.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_string_ref.hh"
@ -37,7 +38,7 @@ struct MeshToVolumeResolution {
* used for deciding the voxel size in "Amount" mode.
*/
float volume_compute_voxel_size(const Depsgraph *depsgraph,
FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
FunctionRef<Bounds<float3>()> bounds_fn,
MeshToVolumeResolution resolution,
float exterior_band_width,
const float4x4 &transform);

View File

@ -72,7 +72,7 @@ void OpenVDBMeshAdapter::getIndexSpacePoint(size_t polygon_index,
}
float volume_compute_voxel_size(const Depsgraph *depsgraph,
FunctionRef<void(float3 &r_min, float3 &r_max)> bounds_fn,
const FunctionRef<Bounds<float3>()> bounds_fn,
const MeshToVolumeResolution res,
const float exterior_band_width,
const float4x4 &transform)
@ -89,14 +89,12 @@ float volume_compute_voxel_size(const Depsgraph *depsgraph,
return 0;
}
float3 bb_min;
float3 bb_max;
bounds_fn(bb_min, bb_max);
const Bounds<float3> bounds = bounds_fn();
/* Compute the diagonal of the bounding box. This is used because
* it will always be bigger than the widest side of the mesh. */
const float diagonal = math::distance(math::transform_point(transform, bb_max),
math::transform_point(transform, bb_min));
const float diagonal = math::distance(math::transform_point(transform, bounds.min),
math::transform_point(transform, bounds.max));
/* To get the approximate size per voxel, first subtract the exterior band from the requested
* voxel amount, then divide the diagonal with this value if it's bigger than 1. */

View File

@ -5,6 +5,7 @@
set(INC
.
importer
exporter
../common
../../blenkernel
../../bmesh
@ -18,6 +19,7 @@ set(INC
set(INC_SYS
../../../../extern/fast_float
../../../../extern/fmtlib/include
)
set(SRC
@ -26,12 +28,16 @@ set(SRC
importer/stl_import_ascii_reader.cc
importer/stl_import_binary_reader.cc
importer/stl_import_mesh.cc
exporter/stl_export.cc
exporter/stl_export_writer.cc
IO_stl.hh
importer/stl_import.hh
importer/stl_import_ascii_reader.hh
importer/stl_import_binary_reader.hh
importer/stl_import_mesh.hh
exporter/stl_export_writer.hh
exporter/stl_export.hh
)
set(LIB
@ -40,6 +46,7 @@ set(LIB
PRIVATE bf::dna
PRIVATE bf::intern::guardedalloc
bf_io_common
extern_fmtlib
)
blender_add_lib(bf_io_stl "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

View File

@ -9,6 +9,7 @@
#include "BLI_timeit.hh"
#include "IO_stl.hh"
#include "stl_export.hh"
#include "stl_import.hh"
void STL_import(bContext *C, const STLImportParams *import_params)
@ -16,3 +17,9 @@ void STL_import(bContext *C, const STLImportParams *import_params)
SCOPED_TIMER("STL Import");
blender::io::stl::importer_main(C, *import_params);
}
void STL_export(bContext *C, const STLExportParams *export_params)
{
SCOPED_TIMER("STL Export");
blender::io::stl::exporter_main(C, *export_params);
}

View File

@ -23,7 +23,18 @@ struct STLImportParams {
bool use_mesh_validate;
};
/**
* C-interface for the importer.
*/
struct STLExportParams {
/** Full path to the to-be-saved STL file. */
char filepath[FILE_MAX];
eIOAxis forward_axis;
eIOAxis up_axis;
float global_scale;
bool export_selected_objects;
bool use_scene_unit;
bool apply_modifiers;
bool ascii_format;
bool use_batch;
};
void STL_import(bContext *C, const STLImportParams *import_params);
void STL_export(bContext *C, const STLExportParams *export_params);

View File

@ -0,0 +1,113 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup stl
*/
#include <algorithm>
#include <memory>
#include <string>
#include "BKE_mesh.hh"
#include "BKE_object.hh"
#include "BLI_string.h"
#include "DEG_depsgraph_query.hh"
#include "DNA_scene_types.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_math_vector_types.hh"
#include "IO_stl.hh"
#include "stl_export.hh"
#include "stl_export_writer.hh"
namespace blender::io::stl {
void exporter_main(bContext *C, const STLExportParams &export_params)
{
std::unique_ptr<FileWriter> writer;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene = CTX_data_scene(C);
/* If not exporting in batch, create single writer for all objects. */
if (!export_params.use_batch) {
writer = std::make_unique<FileWriter>(export_params.filepath, export_params.ascii_format);
}
DEGObjectIterSettings deg_iter_settings{};
deg_iter_settings.depsgraph = depsgraph;
deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE |
DEG_ITER_OBJECT_FLAG_DUPLI;
DEG_OBJECT_ITER_BEGIN (&deg_iter_settings, object) {
if (object->type != OB_MESH) {
continue;
}
if (export_params.export_selected_objects && !(object->base_flag & BASE_SELECTED)) {
continue;
}
/* If exporting in batch, create writer for each iteration over objects. */
if (export_params.use_batch) {
/* Get object name by skipping initial "OB" prefix. */
std::string object_name = (object->id.name + 2);
/* Replace spaces with underscores. */
std::replace(object_name.begin(), object_name.end(), ' ', '_');
/* Include object name in the exported file name. */
std::string suffix = object_name + ".stl";
char filepath[FILE_MAX];
BLI_strncpy(filepath, export_params.filepath, FILE_MAX);
BLI_path_extension_replace(filepath, FILE_MAX, suffix.c_str());
writer = std::make_unique<FileWriter>(export_params.filepath, export_params.ascii_format);
}
Object *obj_eval = DEG_get_evaluated_object(depsgraph, object);
Mesh *mesh = export_params.apply_modifiers ? BKE_object_get_evaluated_mesh(obj_eval) :
BKE_object_get_pre_modified_mesh(obj_eval);
/* Calculate transform. */
float global_scale = export_params.global_scale;
if ((scene->unit.system != USER_UNIT_NONE) && export_params.use_scene_unit) {
global_scale *= scene->unit.scale_length;
}
float axes_transform[3][3];
unit_m3(axes_transform);
float xform[4][4];
/* +Y-forward and +Z-up are the default Blender axis settings. */
mat3_from_axis_conversion(
export_params.forward_axis, export_params.up_axis, IO_AXIS_Y, IO_AXIS_Z, axes_transform);
mul_m4_m3m4(xform, axes_transform, obj_eval->object_to_world);
/* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */
mul_v3_m3v3(xform[3], axes_transform, obj_eval->object_to_world[3]);
xform[3][3] = obj_eval->object_to_world[3][3];
/* Write triangles. */
const Span<float3> positions = mesh->vert_positions();
const blender::Span<int> corner_verts = mesh->corner_verts();
for (const MLoopTri &loop_tri : mesh->looptris()) {
Triangle t;
for (int i = 0; i < 3; i++) {
float3 pos = positions[corner_verts[loop_tri.tri[i]]];
mul_m4_v3(xform, pos);
pos *= global_scale;
t.vertices[i] = pos;
}
t.normal = math::normal_tri(t.vertices[0], t.vertices[1], t.vertices[2]);
writer->write_triangle(t);
}
}
DEG_OBJECT_ITER_END;
}
} // namespace blender::io::stl

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup stl
*/
#pragma once
#include "IO_stl.hh"
namespace blender::io::stl {
/* Main export function used from within Blender. */
void exporter_main(bContext *C, const STLExportParams &export_params);
} // namespace blender::io::stl

View File

@ -0,0 +1,105 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup stl
*/
#include <cstdint>
#include <cstdio>
#include <stdexcept>
/* SEP macro from BLI path utils clashes with SEP symbol in fmt headers. */
#undef SEP
#include <fmt/format.h>
#include "stl_export_writer.hh"
#include "BLI_fileops.h"
namespace blender::io::stl {
constexpr size_t BINARY_HEADER_SIZE = 80;
#pragma pack(push, 1)
struct ExportBinaryTriangle {
float3 normal;
float3 vertices[3];
uint16_t attribute_byte_count;
};
#pragma pack(pop)
static_assert(sizeof(ExportBinaryTriangle) == 12 + 12 * 3 + 2,
"ExportBinaryTriangle expected size mismatch");
FileWriter::FileWriter(const char *filepath, bool ascii) : tris_num_(0), ascii_(ascii)
{
file_ = BLI_fopen(filepath, "wb");
if (file_ == nullptr) {
throw std::runtime_error("STL export: failed to open file");
}
/* Write header */
if (ascii_) {
fmt::print(file_, "solid \n");
}
else {
char header[BINARY_HEADER_SIZE] = {};
fwrite(header, 1, BINARY_HEADER_SIZE, file_);
/* Write placeholder for number of triangles, so that it can be updated later (after all
* triangles have been written). */
fwrite(&tris_num_, sizeof(uint32_t), 1, file_);
}
}
FileWriter::~FileWriter()
{
if (file_ == nullptr) {
return;
}
if (ascii_) {
fmt::print(file_, "endsolid \n");
}
else {
fseek(file_, BINARY_HEADER_SIZE, SEEK_SET);
fwrite(&tris_num_, sizeof(uint32_t), 1, file_);
}
fclose(file_);
}
void FileWriter::write_triangle(const Triangle &t)
{
tris_num_++;
if (ascii_) {
fmt::print(file_,
"facet normal {} {} {}\n"
" outer loop\n"
" vertex {} {} {}\n"
" vertex {} {} {}\n"
" vertex {} {} {}\n"
" endloop\n"
"endfacet\n",
t.normal.x,
t.normal.y,
t.normal.z,
t.vertices[0].x,
t.vertices[0].y,
t.vertices[0].z,
t.vertices[1].x,
t.vertices[1].y,
t.vertices[1].z,
t.vertices[2].x,
t.vertices[2].y,
t.vertices[2].z);
}
else {
ExportBinaryTriangle bin_tri;
bin_tri.normal = t.normal;
bin_tri.vertices[0] = t.vertices[0];
bin_tri.vertices[1] = t.vertices[1];
bin_tri.vertices[2] = t.vertices[2];
bin_tri.attribute_byte_count = 0;
fwrite(&bin_tri, sizeof(ExportBinaryTriangle), 1, file_);
}
}
} // namespace blender::io::stl

View File

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup stl
*/
#pragma once
#include "BLI_math_vector_types.hh"
namespace blender::io::stl {
struct Triangle {
float3 normal;
float3 vertices[3];
};
class FileWriter {
public:
FileWriter(const char *filepath, bool ascii);
~FileWriter();
void write_triangle(const Triangle &t);
private:
FILE *file_;
uint32_t tris_num_;
bool ascii_;
};
} // namespace blender::io::stl

View File

@ -470,7 +470,7 @@ void USDMeshReader::read_color_data_primvar(Mesh *mesh,
const OffsetIndices faces = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
for (const int i : faces.index_range()) {
const IndexRange &face = faces[i];
const IndexRange face = faces[i];
for (int j = 0; j < face.size(); ++j) {
int loop_index = face[j];

View File

@ -114,17 +114,11 @@ void transform_object(Object *object, const OBJImportParams &import_params)
BKE_object_apply_mat4(object, obmat, true, false);
if (import_params.clamp_size != 0.0f) {
float3 max_coord(-INT_MAX);
float3 min_coord(INT_MAX);
const BoundBox bb = BKE_mesh_boundbox_get(object);
for (const float(&vertex)[3] : bb.vec) {
for (int axis = 0; axis < 3; axis++) {
max_coord[axis] = max_ff(max_coord[axis], vertex[axis]);
min_coord[axis] = min_ff(min_coord[axis], vertex[axis]);
}
}
const float max_diff = max_fff(
max_coord[0] - min_coord[0], max_coord[1] - min_coord[1], max_coord[2] - min_coord[2]);
BLI_assert(object->type == OB_MESH);
const Mesh *mesh = static_cast<const Mesh *>(object->data);
const Bounds<float3> bounds = *mesh->bounds_min_max();
const float max_diff = math::reduce_max(bounds.max - bounds.min);
float scale = 1.0f;
while (import_params.clamp_size < max_diff * scale) {
scale = scale / 10;

View File

@ -303,7 +303,6 @@ typedef struct Mesh {
/**
* Calculate the largest and smallest position values of vertices.
* \note Does not take non-mesh data (edit mesh) into account, see #BKE_mesh_wrapper_minmax,
*/
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;

View File

@ -608,23 +608,27 @@ static void rna_Object_ray_cast(Object *ob,
return;
}
/* Test BoundBox first (efficiency) */
const std::optional<BoundBox> bb = BKE_object_boundbox_get(ob);
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
/* Test bounding box first (efficiency) */
const std::optional<blender::Bounds<blender::float3>> bounds = mesh_eval->bounds_min_max();
if (!bounds) {
return;
}
float distmin;
/* Needed for valid distance check from #isect_ray_aabb_v3_simple() call. */
float direction_unit[3];
normalize_v3_v3(direction_unit, direction);
if (!bb || (isect_ray_aabb_v3_simple(
origin, direction_unit, bb->vec[0], bb->vec[6], &distmin, nullptr) &&
distmin <= distance))
if ((isect_ray_aabb_v3_simple(
origin, direction_unit, bounds->min, bounds->max, &distmin, nullptr) &&
distmin <= distance))
{
BVHTreeFromMesh treeData = {nullptr};
/* No need to managing allocation or freeing of the BVH data.
* This is generated and freed as needed. */
Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
BKE_bvhtree_from_mesh_get(&treeData, mesh_eval, BVHTREE_FROM_LOOPTRI, 4);
/* may fail if the mesh has no faces, in that case the ray-cast misses */

View File

@ -149,14 +149,12 @@ static Volume *mesh_to_volume(ModifierData *md,
}
}
auto bounds_fn = [&](float3 &r_min, float3 &r_max) {
const Bounds<float3> bounds = *mesh->bounds_min_max();
r_min = bounds.min;
r_max = bounds.max;
};
const float voxel_size = geometry::volume_compute_voxel_size(
ctx->depsgraph, bounds_fn, resolution, 0.0f, mesh_to_own_object_space_transform);
ctx->depsgraph,
[&]() { return *mesh->bounds_min_max(); },
resolution,
0.0f,
mesh_to_own_object_space_transform);
/* Create a new volume. */
Volume *volume;

View File

@ -83,8 +83,8 @@ class DNode {
const bNode *operator->() const;
const bNode &operator*() const;
friend bool operator==(const DNode &a, const DNode &b);
friend bool operator!=(const DNode &a, const DNode &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(DNode, context_, bnode_)
operator bool() const;
uint64_t hash() const;
@ -119,8 +119,8 @@ class DSocket {
const bNodeSocket *operator->() const;
const bNodeSocket &operator*() const;
friend bool operator==(const DSocket &a, const DSocket &b);
friend bool operator!=(const DSocket &a, const DSocket &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(DSocket, context_, bsocket_)
operator bool() const;
uint64_t hash() const;
@ -295,16 +295,6 @@ inline const bNode *DNode::bnode() const
return bnode_;
}
inline bool operator==(const DNode &a, const DNode &b)
{
return a.context_ == b.context_ && a.bnode_ == b.bnode_;
}
inline bool operator!=(const DNode &a, const DNode &b)
{
return !(a == b);
}
inline DNode::operator bool() const
{
return bnode_ != nullptr;
@ -379,16 +369,6 @@ inline const bNodeSocket *DSocket::bsocket() const
return bsocket_;
}
inline bool operator==(const DSocket &a, const DSocket &b)
{
return a.context_ == b.context_ && a.bsocket_ == b.bsocket_;
}
inline bool operator!=(const DSocket &a, const DSocket &b)
{
return !(a == b);
}
inline DSocket::operator bool() const
{
return bsocket_ != nullptr;

View File

@ -73,8 +73,7 @@ class OutputFieldDependency {
OutputSocketFieldType field_type() const;
Span<int> linked_input_indices() const;
friend bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b);
friend bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(OutputFieldDependency, type_, linked_input_indices_)
};
/**
@ -84,8 +83,7 @@ struct FieldInferencingInterface {
Vector<InputSocketFieldType> inputs;
Vector<OutputFieldDependency> outputs;
friend bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b);
friend bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b);
BLI_STRUCT_EQUALITY_OPERATORS_2(FieldInferencingInterface, inputs, outputs)
};
namespace anonymous_attribute_lifetime {
@ -97,11 +95,7 @@ struct PropagateRelation {
int from_geometry_input;
int to_geometry_output;
friend bool operator==(const PropagateRelation &a, const PropagateRelation &b)
{
return a.from_geometry_input == b.from_geometry_input &&
a.to_geometry_output == b.to_geometry_output;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(PropagateRelation, from_geometry_input, to_geometry_output)
};
/**
@ -111,10 +105,7 @@ struct ReferenceRelation {
int from_field_input;
int to_field_output;
friend bool operator==(const ReferenceRelation &a, const ReferenceRelation &b)
{
return a.from_field_input == b.from_field_input && a.to_field_output == b.to_field_output;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(ReferenceRelation, from_field_input, to_field_output)
};
/**
@ -124,10 +115,7 @@ struct EvalRelation {
int field_input;
int geometry_input;
friend bool operator==(const EvalRelation &a, const EvalRelation &b)
{
return a.field_input == b.field_input && a.geometry_input == b.geometry_input;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(EvalRelation, field_input, geometry_input)
};
/**
@ -137,10 +125,7 @@ struct AvailableRelation {
int field_output;
int geometry_output;
friend bool operator==(const AvailableRelation &a, const AvailableRelation &b)
{
return a.field_output == b.field_output && a.geometry_output == b.geometry_output;
}
BLI_STRUCT_EQUALITY_OPERATORS_2(AvailableRelation, field_output, geometry_output)
};
struct RelationsInNode {
@ -149,10 +134,15 @@ struct RelationsInNode {
Vector<EvalRelation> eval_relations;
Vector<AvailableRelation> available_relations;
Vector<int> available_on_none;
BLI_STRUCT_EQUALITY_OPERATORS_5(RelationsInNode,
propagate_relations,
reference_relations,
eval_relations,
available_relations,
available_on_none)
};
bool operator==(const RelationsInNode &a, const RelationsInNode &b);
bool operator!=(const RelationsInNode &a, const RelationsInNode &b);
std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations);
} // namespace anonymous_attribute_lifetime

View File

@ -25,32 +25,35 @@ static void node_declare(NodeDeclarationBuilder &b)
static void edge_paths_to_selection(const Mesh &src_mesh,
const IndexMask &start_selection,
const Span<int> next_indices,
MutableSpan<bool> r_selection)
MutableSpan<bool> r_edge_selection)
{
const Span<int2> edges = src_mesh.edges();
Array<bool> vert_selection(src_mesh.totvert, false);
Array<bool> selection(src_mesh.totvert);
start_selection.to_bools(selection);
start_selection.foreach_index([&](const int start_i) {
int iter = start_i;
while (iter != next_indices[iter] && !selection[next_indices[iter]]) {
if (next_indices[iter] < 0 || next_indices[iter] >= src_mesh.totvert) {
const IndexRange vert_range(src_mesh.totvert);
start_selection.foreach_index(GrainSize(2048), [&](const int start_vert) {
/* If vertex is selected, all next is already selected too. */
for (int current_vert = start_vert; !vert_selection[current_vert];
current_vert = next_indices[current_vert])
{
if (UNLIKELY(!vert_range.contains(current_vert))) {
break;
}
selection[next_indices[iter]] = true;
iter = next_indices[iter];
vert_selection[current_vert] = true;
}
});
for (const int i : edges.index_range()) {
const int2 &edge = edges[i];
if ((selection[edge[0]] && selection[edge[1]]) &&
(edge[0] == next_indices[edge[1]] || edge[1] == next_indices[edge[0]]))
{
r_selection[i] = true;
const Span<int2> edges = src_mesh.edges();
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
const int2 edge = edges[i];
if (!(vert_selection[edge[0]] && vert_selection[edge[1]])) {
continue;
}
if (edge[0] == next_indices[edge[1]] || edge[1] == next_indices[edge[0]]) {
r_edge_selection[i] = true;
}
}
}
});
}
class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput {
@ -78,15 +81,12 @@ class PathToEdgeSelectionFieldInput final : public bke::MeshFieldInput {
evaluator.evaluate();
const VArraySpan<int> next_vert = evaluator.get_evaluated<int>(0);
const IndexMask start_verts = evaluator.get_evaluated_as_mask(1);
if (start_verts.is_empty()) {
return {};
}
Array<bool> selection(mesh.totedge, false);
MutableSpan<bool> selection_span = selection.as_mutable_span();
edge_paths_to_selection(mesh, start_verts, next_vert, selection_span);
edge_paths_to_selection(mesh, start_verts, next_vert, selection);
return mesh.attributes().adapt_domain<bool>(
VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_EDGE, domain);

View File

@ -109,16 +109,12 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams &para
const float4x4 mesh_to_volume_space_transform = float4x4::identity();
auto bounds_fn = [&](float3 &r_min, float3 &r_max) {
float3 min{std::numeric_limits<float>::max()};
float3 max{-std::numeric_limits<float>::max()};
BKE_mesh_wrapper_minmax(&mesh, min, max);
r_min = min;
r_max = max;
};
const float voxel_size = geometry::volume_compute_voxel_size(
params.depsgraph(), bounds_fn, resolution, half_band_width, mesh_to_volume_space_transform);
params.depsgraph(),
[&]() { return *mesh.bounds_min_max(); },
resolution,
half_band_width,
mesh_to_volume_space_transform);
if (voxel_size < 1e-5f) {
/* The voxel size is too small. */

View File

@ -104,16 +104,12 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams &para
const float4x4 mesh_to_volume_space_transform = float4x4::identity();
auto bounds_fn = [&](float3 &r_min, float3 &r_max) {
float3 min{std::numeric_limits<float>::max()};
float3 max{-std::numeric_limits<float>::max()};
BKE_mesh_wrapper_minmax(&mesh, min, max);
r_min = min;
r_max = max;
};
const float voxel_size = geometry::volume_compute_voxel_size(
params.depsgraph(), bounds_fn, resolution, 0.0f, mesh_to_volume_space_transform);
params.depsgraph(),
[&]() { return *mesh.bounds_min_max(); },
resolution,
0.0f,
mesh_to_volume_space_transform);
Volume *volume = reinterpret_cast<Volume *>(BKE_id_new_nomain(ID_VO, nullptr));

View File

@ -147,19 +147,6 @@ void NodeDeclarationBuilder::set_active_panel_builder(const PanelDeclarationBuil
namespace anonymous_attribute_lifetime {
bool operator==(const RelationsInNode &a, const RelationsInNode &b)
{
return a.propagate_relations == b.propagate_relations &&
a.reference_relations == b.reference_relations && a.eval_relations == b.eval_relations &&
a.available_relations == b.available_relations &&
a.available_on_none == b.available_on_none;
}
bool operator!=(const RelationsInNode &a, const RelationsInNode &b)
{
return !(a == b);
}
std::ostream &operator<<(std::ostream &stream, const RelationsInNode &relations)
{
stream << "Propagate Relations: " << relations.propagate_relations.size() << "\n";
@ -857,26 +844,6 @@ Span<int> OutputFieldDependency::linked_input_indices() const
return linked_input_indices_;
}
bool operator==(const OutputFieldDependency &a, const OutputFieldDependency &b)
{
return a.type_ == b.type_ && a.linked_input_indices_ == b.linked_input_indices_;
}
bool operator!=(const OutputFieldDependency &a, const OutputFieldDependency &b)
{
return !(a == b);
}
bool operator==(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
{
return a.inputs == b.inputs && a.outputs == b.outputs;
}
bool operator!=(const FieldInferencingInterface &a, const FieldInferencingInterface &b)
{
return !(a == b);
}
const CompositorInputRealizationOptions &SocketDeclaration::compositor_realization_options() const
{
return compositor_realization_options_;

View File

@ -78,6 +78,7 @@ static void seq_add_generic_update(Scene *scene, Sequence *seq)
SEQ_sequence_base_unique_name_recursive(scene, &scene->ed->seqbase, seq);
SEQ_relations_invalidate_cache_composite(scene, seq);
SEQ_sequence_lookup_tag(scene, SEQ_LOOKUP_TAG_INVALID);
seq_time_effect_range_set(scene, seq);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
@ -183,7 +184,6 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, SeqLoadData *loa
seq_add_set_name(scene, seq, load_data);
seq_add_generic_update(scene, seq);
seq_time_effect_range_set(scene, seq);
return seq;
}

View File

@ -977,9 +977,9 @@ void SEQ_retiming_key_timeline_frame_set(const Scene *scene,
seq_retiming_key_offset(scene, seq, key, offset);
}
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
void SEQ_retiming_key_speed_set(const Scene *scene,

View File

@ -200,9 +200,9 @@ void SEQ_time_update_meta_strip_range(const Scene *scene, Sequence *seq_meta)
seq_meta->enddisp = strip_end; /* Only to make files usable in older versions. */
seq_update_sound_bounds_recursive(scene, seq_meta);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq_meta));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq_meta);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq_meta));
}
void seq_time_effect_range_set(const Scene *scene, Sequence *seq)
@ -494,9 +494,9 @@ float SEQ_time_start_frame_get(const Sequence *seq)
void SEQ_time_start_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
{
seq->start = timeline_frame;
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
float SEQ_time_content_end_frame_get(const Scene *scene, const Sequence *seq)
@ -544,9 +544,9 @@ void SEQ_time_left_handle_frame_set(const Scene *scene, Sequence *seq, int timel
seq->startdisp = timeline_frame; /* Only to make files usable in older versions. */
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int timeline_frame)
@ -560,9 +560,9 @@ void SEQ_time_right_handle_frame_set(const Scene *scene, Sequence *seq, int time
seq->endofs = SEQ_time_content_end_frame_get(scene, seq) - timeline_frame;
seq->enddisp = timeline_frame; /* Only to make files usable in older versions. */
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}
void seq_time_translate_handles(const Scene *scene, Sequence *seq, const int offset)
@ -572,7 +572,7 @@ void seq_time_translate_handles(const Scene *scene, Sequence *seq, const int off
seq->startdisp += offset; /* Only to make files usable in older versions. */
seq->enddisp -= offset; /* Only to make files usable in older versions. */
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(scene, seq);
seq_time_update_effects_strip_range(scene, effects);
SEQ_time_update_meta_strip_range(scene, seq_sequence_lookup_meta_by_seq(scene, seq));
}

View File

@ -139,9 +139,9 @@ void SEQ_transform_translate_sequence(Scene *evil_scene, Sequence *seq, int delt
}
SEQ_offset_animdata(evil_scene, seq, delta);
SEQ_time_update_meta_strip_range(evil_scene, seq_sequence_lookup_meta_by_seq(evil_scene, seq));
blender::Span effects = seq_sequence_lookup_effects_by_seq(evil_scene, seq);
seq_time_update_effects_strip_range(evil_scene, effects);
SEQ_time_update_meta_strip_range(evil_scene, seq_sequence_lookup_meta_by_seq(evil_scene, seq));
}
bool SEQ_transform_seqbase_shuffle_ex(ListBase *seqbasep,