Geometry Nodes: initial Volume Grid socket support #115270
@ -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. */
|
||||
|
@ -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>
|
||||
|
@ -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):
|
||||
|
@ -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();
|
||||
|
@ -19,7 +19,6 @@ struct BMLoop;
|
||||
struct BMPartialUpdate;
|
||||
struct BMesh;
|
||||
struct BMeshCalcTessellation_Params;
|
||||
struct BoundBox;
|
||||
struct Depsgraph;
|
||||
struct Mesh;
|
||||
struct Object;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -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()),
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* \{ */
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
55
source/blender/blenlib/BLI_struct_equality_utils.hh
Normal file
55
source/blender/blenlib/BLI_struct_equality_utils.hh
Normal 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)
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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_)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
@ -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. */
|
||||
|
@ -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}")
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
113
source/blender/io/stl/exporter/stl_export.cc
Normal file
113
source/blender/io/stl/exporter/stl_export.cc
Normal 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 (°_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
|
16
source/blender/io/stl/exporter/stl_export.hh
Normal file
16
source/blender/io/stl/exporter/stl_export.hh
Normal 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
|
105
source/blender/io/stl/exporter/stl_export_writer.cc
Normal file
105
source/blender/io/stl/exporter/stl_export_writer.cc
Normal 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
|
30
source/blender/io/stl/exporter/stl_export_writer.hh
Normal file
30
source/blender/io/stl/exporter/stl_export_writer.hh
Normal 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
|
@ -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];
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -109,16 +109,12 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶
|
||||
|
||||
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. */
|
||||
|
@ -104,16 +104,12 @@ static Volume *create_volume_from_mesh(const Mesh &mesh, GeoNodeExecParams ¶
|
||||
|
||||
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));
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user